Codebase list libmawk / upstream/1.0.0
New upstream version 1.0.0 Bdale Garbee 5 years ago
518 changed file(s) with 57054 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 Changelog for libmawk
1 ~~~~~~~~~~~~~~~~~~~~~
2 libmawk 1.0.0 (released: 2018-11-11, r1276)
3 [API] -Change: resume capable function call entries
4 [build] -Fix: make clean should remove custom C test objects and executables
5 [build] -Fix: incomplete install headers list
6 [build] -Add: Makefile variable for selecting zmalloc alternatives
7 [build] -Add: optional DESTDIR for debian
8 [build] -Add: --prefix, --debug, --symbols
9 [build] -Add: help
10 [build] -Chnage: upgrade to tmpasm and latest version of scconfig
11 [build] -Add: optional support for soname
12 [build] -Change: use $(MAKE) instead of make in central Makefiles for parallel build
13 [build] -Add: detect -rdynamic
14 [core] -Change: extend mpow2 for covering new celltypes
15 [core] -Cleanup: rename _STOP and _RANGE to _RANGE_STOP and _RANGE_CHK to make their purpose more clear
16 [core] -Fix: return read error in getline doesn't fall in infinite loop in fill buff anymore
17 [core] -Add: MAWK_MEM_PEDANTIC compile time option; when set, try to free all allocation instead of letting zmalloc catch them all
18 [core] -Fix: don't free the hash before freeing argv and others
19 [core] -Fix: make sure code blocks are free'd only once, but are really free'd
20 [core] -Fix: memory leak when initializing argv
21 [core] -Fix: let mawk_delete() free arrays, don't manually do that on argv
22 [core] -Change: let mawk_delete() free user function
23 [core] -Change: fin is under files - higher level code should do all access through the file infra
24 [core] -Fix: FIN is only about buffering, no open/close should go through that API
25 [core] -Fix: reference count vf structs since one vf might be open multiple times from FILE_NODEs (for input and output) and should be destroyed only once
26 [core] -Fix: closing all files, not only output files, is not a pedantic-mem feature - not doig it could lead to leaking fds and other resources even if zmalloc pools are freed centrally
27 [core] -Fix: there is only one way files are closed, only one code is needed
28 [core] -Fix: mawk_fill_buff returns a signed long for indicating temporary error (fixed for 64 bit)
29 [core] -Fix: rename state field userdata to func_userdata to make the purpose more clear
30 [core] -Add: ctx_userdata intended for the host app for storing whatever data, per context
31 [core] -Add: have a field in the state struct for the C function being called back so that subsequent execute()s may know about that
32 [core] -Fix: memory leak: free data of c function calls compiled into the code at uninit
33 [core] -Fix: C89 fixes (func-data ptr conv through union, don't use strcasemp(), strdup, snprintf, //, vararg macros)
34 [core] -Fix: wrong arg passed to isnan - cell instead fo double value
35 [core] -Fix: vio fclose survives if there's no close function available (double close?)
36 [doc] -Add: short desc about the vm
37 [doc] -Add: explain how execution/resume works
38 [doc] -Add: describe deep recursion
39 [doc] -Add: minimalistic install
40 [example_apps] -Add: blocking fifo test also tests bifunct getline in an user function
41 [example_apps] -Add: make sure to demonstrate how the code is suspended even in user functions
42 [example_apps] -Update: 15_call for the new function call API
43 [example_apps] -Add: example on run limit resume
44 [example_apps] -Add: central Makefile that runs all examples
45 [example_apps] -Add: call a c function from c using awk's func call (demonstrate that awk and c functions should not make any difference)
46 [example_apps] -Fix: hash_re won't init std pipes twice
47 [example_apps] -Fix: custom vio test sets up pipes correctly and closes the hass from the app's end of the deal at the end
48 [example_apps] -Add: better explanation of the c_func_call example and hook it in the all-test-chain
49 [libmawk] -Fix: C function call from execute with new function call conventions
50 [libmawk] -Fix: call_functionp increases sp before push else the stack pointer points to the wrong place
51 [libmawk] -Fix: restore sp on function call failure
52 [libmawk] -Fix: before closing stdio on awk side, close stdin on app side to make sure both ends can be closed
53 [libmawk] -Fix: do not leak function arguments already pushed on stack if an awk function call fails due to bad arguments
54 [libmawk] -Fix: allow c functions to be called using mawk_call_function*()
55 [libmawk] -Fix: don't close stdin if it's not open
56 [libmawk] -Fix: don't use strdup() for c function reg
57 [libmawk] -Fix: don't close non-fifo stdin as fifo
58 [libmawk] -Fix: priting uninitialized cell should work and should result in empty string
59 [libmawk] -Add: wants_to_exit flag so that a libmawk caller knows a script wants to exit
60 [libmawk] -Add: function call API with cell argc/argv
61 [parser] -Fix: really reset the parser stack when it gets freed - used to segfault for two includes on the topmost level
62 [parser] -Fix: allow excess newlines in the main context - this fixes a corner case around multiple includes
63 [regression] -Add: test for bifunct call()
64 [regression] -Add: test for acall() (dynamic call with array as argument)
65 [regression] -Add: test for stack grow on deep recursion
66 [regression] -Add: test program for awk function call corner cases
67 [regression] -Add: libmawk corner case test base
68 [regression] -Fix: libmawk func call test diag messages are more clear on what's wrong or good
69 [rexp] -Fix: infinite loop bug (gawk test noloop1 and noloop2) - contributed by Thomas E. Dickey as a mawk fix
70 [vio] -Fix: set eof flags on fifo creation (fixes a conditional jump on uninited var bug)
71 [vio] -Fix: closing FIN closes the vio layer even if fin buffer had not been initialized
72 [vio] -Fix: close vf throug FIN to make sure buffers are also freed
73 [vio] -Fix: simpler common header with refco and who-knows-what in the future
74 [vio] -Fix: initialize refco to 0
75 [vm] -Change: avoid recursive calls to execute() on plain hardwired awk function calls
76 [vm] -Change: wants_to_ret is execution state instead - need to remember whether we are running range1 or range2
77 [vm] -Fix: leak in function return value stack handling
78 [vm] -Add: new convention in bi_funct calling: return stack may be a directive for executing an user functioin (for bi_call and bi_acall)
79 [vm] -Fix: mawk_bi_call() and bifunct acall() follow the new no-recurse calling convention
80 [vm] -Add: new low level c->awk call functions trying to follow the no-recurse execute_() conventions
81 [vm] -Move: execute API into new execute.h
82 [vm] -Add: a separate execution exit status for exit()
83 [vm] -Add: execution run limit and resume
84 [vm] -Fix: bi_funct getline can indicate 'nomore' instead of eof
85 [vm] -Fix: properly save and restore old_stack_base and old_sp on stack danger (stack growth)
86 [vm] -Cleanup: remumber types (continous numbering)
87 [vm] -Add: more stack-related cell types and make room for future non-string additions
88 [vm] -Fix: compare() returns double so that nan-checks can be performed
89 [vm] -Fix: error return with value from execute()
90 [vm] -Fix: make MAWK->pow big enough and make it safe (need to be unsigned long for these values and for the bit ops)
91
92
93 libmawk 0.10.1 (released: 2014-07-11, r1056)
94 [compiler] -Fix: zero-offset bug in jmp push (xref test crash)
95 [build] -Add: make test should run the standard regression tests; do not run tests automatically on build
96 [core] -Add: zfifo: generic fifo implemented using zmalloc/zfree
97 [core] -Add: mawk_file_find() has a create flag that can disable creating a new file node - useful for forcing existing/open files
98 [core] -Cleanup: move fin struct to fin.h
99 [core] -Cleanup: rename FIN to mawk_input_t for naming consistency
100 [core] -Fix: rewritten mawk_FINgets - cleaner code that is non-blocking-safe
101 [core] -Fix: zrealloc() should not crash if old ptr is NULL
102 [core] -Fix: safer vf close, close outputs only in uninit, when EXIT has finished for sure
103 [vio] -Fix: input is always fd, output is always FILE *; remove fgets and stdin related API
104 [vio] -Clenaup: cleaner ways recognizing "/dev/std*"
105 [vio] -Add: support for /dev/fd/xxx (fdopen() wrapper)
106 [vio] -Add: an extra layer to dispatch vio calls - multiple vio implementations can coexist
107 [vio] -Add: virtualize vio init (non-per-file vio hooks); use MAWK->vio_init instead of hardwired vio_orig (so that vio_orig can be omitted)
108 [vio] -Del: setbuf from API - this callback was a hack, now all done by the call that sets up stdio
109 [vio] -Change: replace is_stdouts with a more generic mark_no_close hook
110 [vio] -Fix: use zmalloc/zfree for the mawk_vio_t allocations
111 [vio] -Add: a generic fifo implementation that also replaces the artificial FIN buf
112 [regression] -Cleanup: remove test/ and convert all shell script based tests to make-based tests in regression/
113 [tools] -Fix: find_globals uses the right dir
114 [tools] -Fix: sym prefix validator won't complain for main()
115 [API] -Add: file name validation hook
116 [API] -Add: call to register a file by name:type and vio handle in the high level list of files; also sets up input buffering as needed
117 [API] -Add: call to close the default input fifo (sending eof to the script)
118 [API] -Add: convenient stdio-init call for multi-staged init
119 [example_app] -Add: custom output pipe hack examples and update pipe in buffer fill examples with all possible corner cases
120 [example_app] -Add: file name validation and vio hook examples
121
122
123 libmawk 0.10.0 (released: 2014-06-26, r937)
124 Major changes in core, mostly for virtual arrays:
125 [array] -Add: introduce new VM instructions for all array-element-write operations and split the lvalue rule of the grammar; besides being new instructions, they do the same in the execution switch as before
126 [array] -Add: virtualize array operations
127 [array] -Add: virtual, per instance ENVIRON[] that copies environ[] upon the first access and affects exec()
128 [array] -Del: ST_ENV: ENVIRON[] is not a global special case anymore, just a builtin array with a different implementation
129 [core] -Fix: replace "short int type" and a bunch of C_ macros for cell type with a proper enum
130 [core] -Add: macro option for cell operators for speed
131 [core] -Fix: set ERRNO in fin after a read error
132 [core] -Cleanup: mawk_ prefix zmalloc, zfree, ZMALLOC, ZFREE and a lot of other constants and macros
133 [init] -Add: a flag for indicating that it is ok for initialize_argv() to end up without a script
134 [dump] -Fix: print the code of illegal instructions
135 [dump] -Add: da_text: use blank lines to separate blocks: functions, BEGIN, MAIN, END
136 [dump] -Change: da_text: after user functions, dump code in BEGIN-MAIN-END order - it is more intuitive this way
137 [dump] -Add: text dump includes a summary of the global symbol table
138 [dump] -Change: introduce -W dumpsym for dumping symbols independently of dumping code
139 [da_bin] -Fix: properly save/load C_SNULL and C_SPACE (special split argument types) to/from binary dump
140 API CHANGES affecting libmawk:
141 [core] -Clenaup: rename STRING to mawk_string_t
142 [core] -Clenaup: rename CELL to libmawk_cell_t
143 [core] -Change: use an union instead of dval in CELL, to make room for other data types
144 [core] -Add: new cell type C_ARR_REF (should be execute()-internal); an array reference by name and index (instead of pointer to a cell)
145 [API] -move parsing the script from init stage1 to stage2 to give the host app a chance to inject things into the context before any code is parsed
146 [API] -Change: get_var should return a read-only CELL - direct modification of the cell is a bad idea due to possible side effects required at write
147 [API] -Fix: libmawk_print_cell shall be called with the context (mawk_state_t) as any other call in the API
148 [API] -Change: new, easier-to-use c-func calling conventions and helpers
149 [array] -Cleanup: rename ARRAY to mawk_array_t
150 New libmawk API features:
151 [API] -Add: helper functions to return the numeric value of a cell
152 [API] -Add: an easy way to set a cell to empty
153 [API] -Add: high level array set_at calls and scalar set calls
154
155 libmawk 0.9.7 (released: 2014-05-17, r732)
156 Major code structure changes:
157 [vio] -Split: file/pipe open/close operations to virtual IO (vio)
158 [linux] -Add: initial linux kernel module effort (defunct yet)
159 [array] -Add: virtualized array access (except for write) with callback functions
160 [libmawk] -Split: lmawk-comp and lmawk-exec frames - most code is in common yet
161 [libmawk] -Add: MAWK_NO_FORK for configuring against system() and fork()
162 Code cleanup:
163 [da_bin] -Cleanup: compiler warnings around da_bin (binary script save/load)
164 [da_bin] -Split: da_bin and da_bin_helper: precompiled binary script load doesn't directly call read() but an user provided callback for virtualization
165 [da_bin] -Fix: array creation on binary load
166 [da_bin] -Fix: when resetting code base size for loading binary, use zmalloc for proper allocation size
167 [build] -Fix: Makefile cleanup for portability
168 [libmawk] -Fix: prefix NF, RS and other similar macro names with MAWK_ - they collide in the Linux kernel
169 [test_3rd] -Add: scripts for running optional 3rd party tests from vendor/ (for the gawk set, without much configuration or filtering)
170 [regex] -Change: error handling without setjmp/longjmp (return values and a bunch of checks)
171 [regex] -Fix: regex lib uses zmalloc memory allocation to ensure all memory is free'd after a context is destroyed
172 [regex] -Add: tiny test program to trigger almost all possible error conditions in the regex lib
173 [regex] -Fix: move runtime states of the regex lib in the mawk struct to make it reentrant
174 [regex] -Fix: bi_vars are part of the mawk struct because parallel scripts may have different values for the same variables or even modify them from script
175 More portable doubles (and numeric):
176 [numeric] -Add: use porty's math_wrap for log() to get rid of undeterministic fpe
177 [numeric] -Add: use PM math protection copied from libporty
178 [numeric] -Add: new builtin function isnan()
179 [numeric] -Fix: virtualize strtod int strtonum: on a real int-only platform (e.g. Linux kernel) there won't be strtod at all
180 Fixes of the core functionality:
181 [libmawk] -Fix: make sure runtime error exit code takes over in final_error_code
182 [bi_func] -Fix: substr for start indices less than 1 behave similar to how substr() handles length overruns (silently truncate) - gawk has the same behavior
183 [bi_func] -Fix: gsub() patch for the ^ bug
184 [io] -Fix: redirection conditions messed up in r349
185 [libmawk] -Fix: disable -v only when MAWK_NO_EXEC is set, and don't even consider MAWK_NO_COMP
186 [libmawk] -Fix: fin_exec should respect a MAWK exit request and not retry reading
187 [libmawk] -Fix: if FIN can not be open (invalid file name, nonexisting file), don't segfault but return error
188
189 libmawk 0.9.6 (missed)
190
191 libmawk 0.9.5 (released: 2012-10-13, r527)
192 [libmawk] -Add: memory usage accounting figures; -Wmaxmem=size sets maximum
193 memory allocation in bytes (optional suffixes: k and m)
194 [libmawk] -Add: binary save/load functionality (-Wcompile and -b)
195 works on 32 bit systems only (will be fixed later)
196 [libmawk] -Change: replace hardwired double references with generin numeric
197 (C_NUM, num_t) - libmawk can be configured to use int or
198 double as numeric format (./configure --numeric=)
199 [libmawk] -Cleanup: (portability tweak) const correctness in mawk_reverse_find
200 [libmawk] -Add: (portability tweak) _POSIX_SOURCE
201 [libmawk] -Fix: (portability tweak) explicit rules for rexp/*.o incuding
202 $(CC) command line for old fashioned make having the wrong
203 implicit rule
204 [libmawk] -Cleanup: (portability tweak) k&r style function
205 declarations/definitions removed from rexp lib
206 [libmawk] -Fix: (portability tweak) missing prototypes to avoid implicit
207 declaration warning
208 [libmawk] -Change: disable two zfree() calls that would free main code to
209 avoid double frees
210 [libmawk] -Add: compile with app clfags
211 [libmawk] -Cleanup: move scconfig'd -D options to conf.h from Makefile.conf
212 to make compiler command lines shorter
213 [libmawk] -Cleanup: new vars.[ch] for collecting variable-related code
214 [libmawk] -Fix: mawk_mm (aka free_later) mechanism memory handling erros
215 when realloc()'d
216 [doc] -Add: explain design decisions behind our two gnu-dependencies
217 [doc] -Add: portability table (per system: compiles out of the box, has
218 FPE problems, awklib test ran fine)
219
220 libmawk 0.9.4 (released: 2010-12-26, r392)
221 [scconfig] -Add: detect pipe(2) and set NO_PIPE, replacing HAVE_REAL_PIPES
222 [scconfig] -Add: detect size_t include file (removes the ifdef mess)
223 [scconfig] -Add: require detection of cc/fpic (fixes compilation on amd64)
224 [libmawk] -Cleanup: del PROTO() macro: libmawk requires at least C89 compiler
225 [libmawk] -Cleanup: remove revision history and file name comments from *.[ch]
226 copyright notice above all mawk copyright notices
227 [libmawk] -Cleanup: version to clearly indicate that this is lmawk
228 [libmawk] -Cleanup: unified indentation in all .c and .h files
229 [libmawk] -Cleanup: remove a lot of compiler warnings, fix const correctness
230 [libmawk] -Cleanup: Makefile.dep generation rule; proper, up-to-date Makefile.dep
231 [libmawk] -Del: remove FAKE_PIPES support (was only for DOS anyway)
232 [libmawk] -Del: void * is a must, PTR should not fall back to char *
233 [libmawk] -Del: cut out MSDOS support with all its "dreaded segment nonsense"
234 [libmawk] -Fix: get bison to generate a reentrant parser
235 [libmawk] -Fix: move static globals to mawk state struct
236 [libmawk] -Fix: memory leaks
237
238
239 libmawk 0.9.3 (released: 2010-12-21, r307)
240 [libmawk] -Fix: use -fPIC for compiling (helps on amd64)
241 [libmawk] -Add: new builtin variable ERRNO with a different error code for each corner case in extension calls
242 [libmawk] -Add: new built-in variable LIBPATH for library search path
243 - skip loading a script if name started with '+' and the script was already loaded
244 - if script file name starts with '/', assume it to be an absolute path and skip LIBPATH search
245 [scconfig] -Add: scconfig configures/generates Makefiles of libmawk after autodetecting system features
246 [scconfig] -Del: config-user, v7, atarist: scconfig should take care of all supported systems
247 [scconfig] -Add: central ./configure and Makefile
248 [libmawk] -Fix: order of running BEGINs with "include"
249 [libmawk] -Fix: memory leaks around parser state
250 [awklib] -Add: three awk libraries:
251 - lib_rand for reproducible pseudo random numbers
252 - lib_array for packing/unpacking/printing arrays
253 - lib_ascii for converting characters to ASCII codes
254
255
256 libmawk 0.9.2 (released: 2010-12-12, r229)
257 [libmawk] -Fix: invalid memory handling around cells
258 [libmawk] -Fix: manual page dates and author and project/executable name
259 [libmawk] -Add: dynamic awk function calls (call() and acall())
260 [libmawk] -Add: dynamic awk variable value fetch (valueof())
261 [libmawk] -Add: include
262
263 libmawk 0.9.1 (released: 2009-08-14, r198)
264 [API] -Add: remember userdata when registering and calling back c functions
265 [API] -Add: option to suppress undefined function calls
266 [API] -Add: new call allowing awk function calls without varargs
267 [API] -Change: split up libmawk_initialize in 3 stages (optional)
268 [libmawk] -Del: autotools, keep last generated Makefile for hand editing
269 [libmawk] -Del: config.h (merged in Makefile.conf.in)
270 [libmawk] -Rename: mawk -> lmawk (the binary)
271 [libmawk] -Change: print cell prints integers without .000000
272 [testapp] -Move: testapp out from libmawk (new dir structure)
273 [testapp] -Fix: stack handling bug
274 [doc] -Add: manual pages for libmawk calls
275
276 libmawk 0.9.0 (released: 2009-07-22, r146)
277 * Initial release, based on mawk 1.3.3
278 * r3...r8 Separate libmawk_call() from execute(); allow undefined functions
279 * r9...r42 globals to struct (reentrant)
280 * r43...r92 rename non-static functions to have a mawk_ prefix
281 * r92...r145 libmawk
282
0 all: src/libmawk/Makefile.conf
1 cd src && $(MAKE)
2
3 install: src/libmawk/Makefile.conf
4 cd src && $(MAKE) install
5 cd doc && $(MAKE) install
6
7 uninstall:
8 cd src && $(MAKE) uninstall
9
10 linstall: src/libmawk/Makefile.conf
11 cd src && $(MAKE) linstall
12
13 clean:
14 cd src && $(MAKE) clean
15
16 distclean:
17 cd src && $(MAKE) distclean
18 cd scconfig && $(MAKE) clean
19
20 test:
21 cd src && $(MAKE) test
22
23 src/libmawk/Makefile.conf:
24 @echo "Please run ./configure first."; false
0 1. Introduction
1
2 Libmawk is a fork of mawk 1.3.3, restructured for embedding. This means the
3 user gets libmawk.h and libmawk.so and can embed awk scripting language
4 in any application written in C. For more information, check out the web page
5 at http://repo.hu/projects/libmawk and the documentation in doc/.
6
7 2. Requirements and compiling
8
9 ANSI C compiler, POSIX shell and make are required for compiling libmawk.
10 Bison should be installed for developing libmawk; if it is not installed,
11 local changes to the grammar will be ingored.
12
13 ./configure; make
14
15 On top of usual scconfig arguments, ./configure accepts --numeric=TYPE,
16 where TYPE is int or double. Default is double. This switch affects
17 what type libmawk stores numbers in.
18
19 3. installation
20
21 Run "make install" or "make linstall". The linstall version
22 will use symlinks instead of actual copying of files which is useful if
23 you develop libmawk, the library itself.
24
25 Debian package can be installed from http://repo.hu/debian.
26
27 4. Compatibility with mawk
28
29 Compatibility with mawk is maintained to some degree. Currently libmawk
30 offers a small set of extra features on awk level while providing
31 everything that mawk provides. A valid mawk script will work with
32 libmawk/lmawk without modification. However, the new features will work
33 only with libmawk/lmawk and not mawk, so portable scripts shouldn't
34 depend on them. All extensions are clearly marked in the manual.
35
36 Conclusion: libmawk will compile and install mawk executable, which is
37 backward compatible with mawk executable but also adds some extension
38 features.
39
40 Awklib depends on one of the libmawk features (include), thus awklib
41 scripts won't work with other awk implementations without tweaking.
0 Release notes for libmawk 1.0.0
1
2 This release introduces runlimits, better floating point handling on
3 corner cases (i.e. NaN) and memory leak cleanups.
4
0 #!/bin/sh
1 cd scconfig && make && ./configure "$@"
2
0 all:
1
2 include ../src/libmawk/Makefile.conf
3
4 install:
5 $(MKDIR) $(DOCDIR)
6 $(CP) $(PWD)/*.html $(DOCDIR)
0 1. update the changelog
1 2. update the release notes
2 3. change the version number in src/scconfig/hooks.c
3 4. test a fresh checkout
4 5. svn tag
0 000. full doc rewrite
1
2 Features:
3 - c->awk func call should be able to pass arrays
4
5 00. vio rewrite
6 - add all vio in a linked list in MAWK for garbage collection at mawk_uninit
7 - add a force-clenup hook for this; but also replace mawk_close_out_pipes()
8 - hooks? wrapper?
9 - document file_name_rewrite
10 - document vio
11
12 0. bugs
13 - string ref crash:
14 for(n = 0; n < 1000000; n++) A[n] = "foo"
15 if refcount of "foo" reaches 65535, it crashes
16 - mpow2 should be static
17
18 1. restrictions
19 - detect and use LDFLAGS -dynamic
20 - split compile and run into separate libs:
21 - implement a Single Safe number->string converter;
22 grep for OFMT and CONVFMT and INT_FMT to find all the buggy sprintf based
23 implementations
24 - split da_bin to exec and comp
25 - fix error.c: it shouldn't depend on stdio.h and it shouldn't print
26 to stderr anyway (incompatible with the lib idea)
27 - check whether int-compiled lmawk handles OFMT/CONVFMT properly
28 - floating point:
29 - try to find a platform with FPE for overflow and test
30 - consider a -W nandebug option so that the user knows where the script
31 went wrong; but he could also just check from the script
32 - if isinf() is avaialable, check for inf() result and convert them to nan
33
34
35 1.5.
36 - check all zmalloc() and zrealloc() calls - they may return NULL and callers
37 should return in that case so that runtime error takes over
38
39 2. porting
40 - test on UNIX
41 - provide a real alternative to realpath()
42
43 3.0 extend arrays
44 - array copy
45 - array in array (for orig implementation only?)
46 - length(array) as in gawk? POSIX: length() works on strings only
47 update test_3rd funlen accordingly!
48
49 3.1 features, minor bugs
50 - debugging (gdb scripts); location-file instruction to track src file changes
51 - consider printf with no arg to work like in gawk; also check posix about this
52 test_3rd: printf0
53 - decide whether regex "^+" (and "^*"?) should be accepted and treated as
54 plain + and * at the beginning of the string; update test_3rd reindops
55 (check posix regex)
56 - decide whether regex should support binary; related tests to update:
57 test_3rd jared, regx8bit
58 - posix FS point 3. requires that ^ work in FS; check test_3rd uparrfs
59 - introduce a new symtab flag for remembering builtin vars and arrays;
60 when -W dumpsym, do not dump these unless verbose
61 - introduce a -W dumpallsym (for verbose symdumps)
62 - write regression test for flush() (it used to pass the wrong pointer)
63
64 4. lib fineprint
65 - expose mawk_append_input_file
66
67 5. optimization
68 - mawk_find_bi_ptr(): use perfect hash instead of linear search
69 does it really matter?
70 - peephole:
71 - 'print "a", a, "b", b, "c", c' results in push/cat pairs;
72 make the parser emit a lot of pushes and replace cat with catN
73 - 'expr = 1' will add a pop; there should be another type of assignment
74 that doesn't push anything
75 - replace tail recursion (call+ret)
76
0 <HTML>
1 <BODY>
2 <H1> Why not using autotools </H1>
3 <P>
4 I believe autotools is the wrong designed and poor implementation, partly
5 trying to solve the wrong problem. The fix for this is a better design.
6 For example scconfig - which is the system that configures libmawk. It
7 can do everything it needs to do (yes, including cross compilation).
8 <P>
9 Mawk generally dosn't require too many special things and should compile
10 fine on POSIX systems. If it doesn't compile for you, you have the following
11 choices:
12 <OL>
13 <LI> you can contact me, report bugs, so I can fix scconfig
14 <LI> you can bypass scconfig and manually create Makefile.conf
15 and conf.h for your system yourself (won't help much in
16 fixing scconfig, tho)
17 <LI> you can create and maintain your own autotools version (but official
18 libmawk will not include support for autotools)
19 </OL>
20 </BODY>
21 </HTML>
0 This directory hosts documentation about libmawk internals.
1
2 These files are useful for developers of libmawk and in some specail
3 case for application developers if they plan to use advanced features
4 of libmawk.
5
0 API: Virtual array vs. function
1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2
3 1. Introduction: virtual arrays
4
5 Libmawk implements support for virtual arrays: arrays that do not simply
6 store data in a hash. This feature is designed for maximal flexibility:
7 awk arrays have a set of hooks (function pointers) and whenever the
8 bytecode interpreter has to read, list or modify an array, it will
9 call the hook functions. The original array implementation is just
10 a set of hooks simply storing data without side effects. The ENVIRON[]
11 array is set up with another set of hooks that syncs the environment
12 with awk array (and calls the original hooks for the actual data storage).
13
14
15 2. API: arrays are function calls at the end of the day
16
17 This also means that an application developer has two alternative paths
18 to provide bindings to the application code:
19 - explicit function calls
20 - implicit function calls through an awk array
21
22 For example if the application wants to expose direct I/O port access,
23 it may:
24 - implement functions io_out(port, value) and io_in(port)
25 - implement an array IO[port]
26
27 However, having side effects is usually not desirable. An awk program that
28 uses functions not declared in the awk code makes it clear that these functions
29 are external, whereas an array may be just a global awk variable, side effects
30 are not obvious.
31
32
33 3. how to chose?
34
35 While technically the two ways of the API design are equivalent in the sense
36 that both end up in function calls, there are always considerations that
37 may make one better than the other for a specific application. Below are
38 the pros and cons:
39
40 Function calls, pro:
41 - easy to recognize external calls in the awk code
42 - can implement much more than lookup, set and list
43 - may provide faster listing
44
45 Function calls, con:
46 - longer awk source
47 - when there are multiple different implementations under different names,
48 an awk function that needs to operate on all may need to get a function
49 name prefix and do dynamic function calls that makes the awk
50 code look more complicated
51
52 Array, pro:
53 - simple and short awk code, especially for listing ("for in")
54 - when there are multiple different implementation, passing one of them
55 to an awk function (by reference) hides the differences, keeping awk
56 function code simple
57 - the whole set of data can be handled together: output of split, generic
58 array print or load functions
59
60 Array, con:
61 - hidden side effects (risks awk source readability)
62 - always have to implement lookup, set and list
63
64 NOTE: a major advantage of arrays is listing (the "for in" construction).
65 In mawk this is implemented by saving a list of all indices that exist at
66 the time of entering the loop. While most of the time this means duplicating
67 string references only, it may still be slow and may take considerable amount
68 of memory if the array is large. What counts as large may vary, but generally
69 a 10^6 indices may cause memory allocations in the megabyte range already.
70
71 In practice the following considerations could easily decide the question:
72 A. if there are more operations than lookup/set/list, use functions
73 B. if only set/get is required, check if listing looks useful or not;
74 if useful, go for arrays (where listing is done via "for in");
75 similarly: if there's a function based API for set/get/list, reconsider
76 using an array instead of custom listing. Unless arrays are large!
77 C. are generic array functions useful in common applications? If so, arrays
78 may be better. Generic array functions include:
79 - awk function that prints all indices of an array
80 - awk function doing some complex lookup, e.g. regex search on all indices
81 - loading the array from a string using split(); useful when indices
82 are small integers, typically counting from 0 or 1
83 D. would there be alternative implementations and generic awk functions
84 operating on them depending on their arguments? If so, arrays may be better
85 as they can be passed as reference
86
87 4. examples
88
89 According to these, the I/O port example is better implemented with functions
90 as arrays offer no benefit in any of the above points:
91 A. has only set and get, at this point arrays are as good as functions
92 B. "for in" listing is not a typical application: array has no benefit
93 C. printing all ports is rarely useful; complex lookups are not common;
94 loading I/O space with split() is not useful;
95 no obvious example of generic array code being useful on an IO array:
96 array has no benefit
97 D. having multiple alternative I/O spaces and passing one of these
98 to an awk function as array is not probable: array has no benefit
99
100 An example where array is more suitable is an interface for network interfaces
101 (ifconfig): arrays NIC_IP[], NIC_NETMASK[], NIC_MTU[], etc, indexed by
102 the name of the nic:
103 A. has lookup, set and list; array is as good as functions
104 B. it's a reasonable application to list all interfaces: "for in" is useful,
105 array looks better
106 C. printing all interfaces makes sense; complex lookup
107 (e.g. "all alias interfaces") makes sense; loading the array may make
108 sense (e.g. restoring network settings); split wouldn't work, tho; array
109 looks better
110 D. no obvious alternative arrays to be passed in arg; array has no benefit
111
112 In point A. and D. arrays are not better than functions (but not worse either),
113 but in B. and C. arrays definitely have an advantage for this app.
0 <HTML>
1 <BODY>
2 <h1> The Virtual Machine (VM) </h1>
3
4 The VM lives in execute.c function mawk_execute_().
5 <p>
6 In principle it takes an array of instructions (INST), executing them
7 one by one, operating on the current <a href="stack.html"> evaluation
8 stack</a> (or stack for short). Most of the execution really goes in
9 order as the compiler prepares up everything to achieve linearity.
10 This makes the execution loop relatively simple and efficient: it is
11 just a large <i>while(dont_need_to_exit) execute_next_instruction;</i>.
12 The actual instruction execution is a real large switch on the instruction
13 opcode.
14 <p>
15 An usual example on how this is implemented in practice can be
16 obtained by <i>lmawk -Wdump -f test.awk</i> on some simple arithmetic
17 script:
18 <table border=1>
19 <tr><th> awk <th> asm (VM instructions)
20 <tr>
21 <td>
22 <pre>
23 BEGIN { a = 3 + 4 * 5 }
24 </pre>
25 <td>
26 <pre>
27 BEGIN
28 000 pusha a
29 002 pushd 3
30 004 pushd 4
31 006 pushd 5
32 008 mul
33 009 add
34 010 assign
35 011 pop
36 012 exit0
37 </pre>
38 </table>
39 <p>
40 First the lvalue (target variable, left side) of the assignment is pushed,
41 then the expression (right side). The stack is, from top to down: {5, 4, 3, a}.
42 The top of the stack is 5, the second element is 4 by the time <i>mul</i> runs.
43 <i>Mul</i> will replace these two elements by 20, decreasing the stack size by
44 one, leaving the result on the top. Next <i>add</i> does a similar job,
45 replacing the top two items of the stack {20, 3} with their sum, 23. At
46 the end <i>assign</i> runs on the stack {23, a}, removing both items, copying
47 the value 23 to the global variable <i>a</i>. At the end it also puts
48 the result on the top of the stack, leaving the stack as {23} - this is
49 the result (output) of the assignment operation. Since the script doesn't
50 need to use the result, it runs a <i>pop</i> that removes and discards
51 the top item, leaving the stack empty. Since the script didn't have main
52 or END parts, the script can quit at this point, executing the <i>exit0</i>
53 instruction (exiting with value 0 - the implicit exit).
54 <p>
55 NOTE: currently there's absolutely no optimization in the parser: everything
56 is calculated as written in the script and some values are saved just to be
57 discarded by the next instruction.
58 <p>
59 An interesting and important feature of execute_() is that it can save all
60 states and return to the caller <b>at any point</b> of the execution, i.e.
61 between any two instruction in the code. It can also resume execution from
62 the next instruction. This provides the host application full control over
63 scheduling the script, while the script can be built of sequential, blocking
64 instructions.
65
66 <h2> Jumps and conditions </h2>
67
68 There are a few instructions that have to break linear execution flow, tho:
69 <ul>
70 <li> <a href="parser_if.html"> if()</a> needs to make a jump depending on some condition
71 <li> conditional code (e.g. <i>/^A/ { ... }</i>) is the same
72 <li> range conditional code (e.g. <i>/^A/,/^B/ { ... }</i>) is still the same with some extra complications (internal state tracking whether the script is within the range)
73 <li> <a href="parser_for.html">loops</a> obviously need to do a similar conditional jump back
74 <li> function calls have to temporarily suspend executing the current code and jump to the function code from which a <i>ret</i> or <i>ret0</i> instruction jumps back
75 </ul>
76 <p>
77 Some of the above are implemented using conditional and unconditional jumps
78 to direct addresses (first column on the asm). For example a simple if
79 is compiled to contain 2 jumps:
80 <table border=1>
81 <tr><th> awk <th> asm (VM instructions)
82 <tr>
83 <td>
84 <pre>
85 BEGIN {
86 if (bool)
87 a = 6
88 else
89 a = 7
90 }
91 </pre>
92 <td>
93 <pre>
94 BEGIN
95 000 pushi bool
96 002 jz 012
97 004 pusha a
98 006 pushd 6
99 008 assign
100 009 pop
101 010 jmp 018
102 012 pusha a
103 014 pushd 7
104 016 assign
105 017 pop
106 018 exit0
107 </pre>
108 </table>
109 <p>
110 The first one is a conditional jump, "jump if [top of the stack is] zero"
111 (<i>jz</i>) - this makes the VM jump to the <i>else</i> branch at address 10.
112 The <i>then</i> branch ends in an unconditional jump to the next instruction
113 after the if (which is the implicit exit in this example), bypassing
114 the code of the <i>else</i> branch.
115 <p>
116 A jump is carried out by a simple modification of the "next instruction"
117 pointer before running the next iteration of the execution loop.
118
119 <h2> Recursion: function calls </h2>
120
121 A slightly more complicated mechanism is used when jumps are of recursive
122 nature: the code has to jump to somewhere to do some work and then
123 return here and continue execution from the next instruction. A typical
124 example on this is executing user functions.
125 <p>
126 The original mawk implementation simply called mawk_execute_() recursively.
127 This meant the C compiler took care of saving all internal states on the
128 C stack for the detour. However, this wouldn't allow the code to be suspended
129 during such detour as it would be problematic to rebuild the C stack on a resume.
130 <p>
131 Thus libmawk's mawk_execute_() does not recurse on C level but on VM level.
132 For example when a function is called (using the <i>call</i> instruction):
133 <ul>
134 <li> 1. prepare the eval stack for the function (as mawk did): push arguments and local variables
135 <li> 2. push execution state on top of the eval stack
136 <li> 3. unconditional jump to the function body
137 </ul>
138 <p>
139 Upon a <i>ret</i> instruction from the function:
140 <ul>
141 <li> 1. save and remove the return value from the top of the stack
142 <li> 2. restore previous execution state from the top of the stack
143 <li> 3. remove all arguments and local variables from the stack (remove the frame)
144 <li> 4. push the return value on top of the stack
145 <li> 5. continue execution normally - because step 2., this will run the instruction right after the <i>call</i>
146 </ul>
147
148 <h3> additional cases of recursion </h3>
149 A range pattern is recursive as well: it needs to evaluate one or two pattern
150 matching before it decides whether to execute the action and/or update
151 the state. The range check starts with instruction _RANGE_CHK which
152 encodes expression code offsets and state in the next few instruction slots. It
153 recurses to evaluate expressions which are terminated by the _RANGE_STOP command.
154 Entering an expression evaluation is similar to a function call while
155 _RANGE_STOP is very similar to a ret.
156
157 <h3> deep recursion </h3>
158 At any time the eval stack has to have enough space after sp for
159 evaluation the longest awk expression. Any user function recursion will
160 bump sp leaving less room for expressions and further recursion. Relocating
161 the stack (with a realloc()) is not a good idea as there might be cell
162 pointers pointing to stack elements all around.
163
164 Instead, mawk limits expression length in compile time to a fixed
165 maximum. If entering a new function would not leave at list this
166 amount of eval stack above sp, "deep recursion" is performed. This
167 starts by allocating an entire new stack for the call. Call stacking
168 saves enough pointers so that the code can switch back to the
169 previous stack easily. The allocation is done using zmalloc(), the overhead
170 is minimal. Since the original stack/stacks is/are kept intact, any
171 pointer stays valid. sp points into the new stack block and will increase
172 there until another deep recursion.
173
174 This wastes some stack space on the old stack (potentially max expression
175 length minus one slot) but guarantees that:
176 - checks and special things need to be done only at entering/leaving functions
177 - even that happens rarely as a stack block is large enough to host
178 many functions besides the longest expression
179 - the stack can grow as big as it likes to, without having to allocate
180 one large block of memory
181 - all allocation is done from normal instance memory - allocation limit,
182 and auto cleanup at the end are granted
183
184 <h2> Resuming execute_() </h2>
185
186 Since the far most common thing in an embedded setup is to resume a
187 code interrupted by execution limit or a blocking getline, mawk_execute_() is
188 doing that by default. The top few slots in the eval stack is always a full
189 state dump, the same thing used in recursion. Entering mawk_execute_() pops this
190 section and initializes all internal states from it. When execution needs
191 to be interrupted, mawk_execute_() saves internal states onto the top
192 of the stack.
193
194 <h2> Entering execute_() (fresh start) </h2>
195
196 Entering in run state involves setting up internal states pointing to
197 the beginning of the code in question, pushing these states on top of
198 the stack and calling mawk_execute_() which will "resume" from these states.
199 Similar thing happens when the application calls an awk function.
200 <p>
201 It may be that the execution is interrupted in the middle of running of
202 a large block of code, for example in BEGIN. The top of the stack holds
203 the current execution state so that mawk_execute_() will be able to
204 continue execution. The application may decide to run an awk
205 function before resuming the code: this operation would push a new
206 set of execution state on top of the stack and call mawk_execute_().
207 When the current state finishes at the _RET instruction, mawk_execute_()
208 would take the next frame from the stack and would automatically resume
209 execution of the interrupted BEGIN block. This would cause the return value
210 of the function to be lost and would attempt to resume BEGIN as a side effect
211 of the function call!
212 <p>
213 To avoid such confusion, any new enter to mawk_execute_() is required to
214 push two sets of states: an EXEST_EXIT and the actual state it wants
215 to "resume" at (start execution at). When mawk_execute_() hits the _RET
216 instruction in the above example, it does pop the next frame, but that
217 frame would be the EXEST_EXIT which would cause it to interrupt immediately.
218 This leaves the stack exactly as it looked like before the function call,
219 and the application later may decide to resume execution.
220 <p>
221 Fresh start entries:
222 <ul>
223 <li> running BEGIN (last stage of initialization)
224 <li> running main on new input, in non-interrupted state
225 <li> running END (first stage of uninitialization)
226 <li> an awk function is called by the application
227 </ul>
228
229
230
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:30 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>EXAMPLE</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">EXAMPLE</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#Example application">Example application</a><br>
26
27 <hr>
28
29
30 <h2>NAME
31 <a name="NAME"></a>
32 </h2>
33
34
35 <p style="margin-left:11%; margin-top: 1em">libmawk example
36 &minus; how to use the library</p>
37
38 <h2>SYNOPSIS
39 <a name="SYNOPSIS"></a>
40 </h2>
41
42
43 <p style="margin-left:11%; margin-top: 1em"><b>#include
44 &lt;libmawk.h&gt;</b></p>
45
46 <h2>DESCRIPTION
47 <a name="DESCRIPTION"></a>
48 </h2>
49
50
51 <p style="margin-left:11%; margin-top: 1em">Libmawk is a
52 library that lets applications to embed awk scripts using
53 the code of the popular implementation <b>mawk.</b> The
54 normal process is to call libmawk_initialize() to set up a
55 new mawk context (with script(s) loaded), then in the main
56 loop feed it using libmawk_append_input(). For &quot;out of
57 band&quot; communication, the program may also call
58 functions implemented in awk and read (or modify) global
59 variables of the awk script. The hos tapplication usally
60 will also bind some of its functions to the context using
61 libmawk_register_function, which allows the awk script to
62 call the host applicaiton&rsquo;s functions directly as they
63 were awk builtins or user defined functions. After the main
64 loop, the application destroys the context freeing up all
65 memory allocated for the script(s).</p>
66
67 <p style="margin-left:11%; margin-top: 1em">One context is
68 for one awk program. One awk program may consist of multiple
69 script files (just as with command line awk, with multiple
70 -f filename arguments). Libmawk is instance safe, the host
71 application may create multiple instances of contexts with
72 the same or with different set of awk scripts loaded. These
73 contexts are totally separate, no variables, functions or
74 any sort of states are shared. However, the host application
75 may provide means of communication between those scripts by
76 custom functions or by copying variable contents between
77 them.</p>
78
79 <h2>Example application
80 <a name="Example application"></a>
81 </h2>
82
83
84 <p style="margin-left:11%; margin-top: 1em">The following
85 example application creates a single context to demonstrate
86 all the above mentioned functionality. <br>
87 #include &lt;stdio.h&gt; <br>
88 #include &lt;libmawk.h&gt;</p>
89
90 <p style="margin-left:11%; margin-top: 1em">CELL
91 *blobb(mawk_state_t *context, CELL * sp, int a_args) <br>
92 {</p>
93
94 <table width="100%" border="0" rules="none" frame="void"
95 cellspacing="0" cellpadding="0">
96 <tr valign="top" align="left">
97 <td width="8%"></td>
98 <td width="7%"></td>
99 <td width="8%">
100
101
102 <p>int n;</p></td>
103 <td width="77%">
104 </td></tr>
105 <tr valign="top" align="left">
106 <td width="8%"></td>
107 <td width="7%"></td>
108 <td width="8%">
109
110
111 <p>char buff[64];</p></td>
112 <td width="77%">
113 </td></tr>
114 <tr valign="top" align="left">
115 <td width="8%"></td>
116 <td width="7%"></td>
117 <td width="8%">
118
119
120 <p>/* do something - print BLOBB and all arguments */</p></td>
121 <td width="77%">
122 </td></tr>
123 <tr valign="top" align="left">
124 <td width="8%"></td>
125 <td width="7%"></td>
126 <td width="8%">
127
128
129 <p>printf(&quot;BLOBB! &quot;);</p></td>
130 <td width="77%">
131 </td></tr>
132 <tr valign="top" align="left">
133 <td width="8%"></td>
134 <td width="7%"></td>
135 <td width="8%">
136
137
138 <p>for(n = a_args-1; n &gt;= 0; n--)</p></td>
139 <td width="77%">
140 </td></tr>
141 <tr valign="top" align="left">
142 <td width="8%"></td>
143 <td width="7%">
144 </td>
145 <td width="8%">
146 </td>
147 <td width="77%">
148
149
150 <p>printf(&quot;%d=&rsquo;%s&rsquo; &quot;, n,
151 libmawk_print_cell((sp-n), buff, sizeof(buff)));</p></td></tr>
152 <tr valign="top" align="left">
153 <td width="8%"></td>
154 <td width="7%"></td>
155 <td width="8%">
156
157
158 <p>printf(&quot;0);</p></td>
159 <td width="77%">
160 </td></tr>
161 <tr valign="top" align="left">
162 <td width="8%"></td>
163 <td width="7%"></td>
164 <td width="8%">
165
166
167 <p>/* restore the stack (remove all arguments) */</p></td>
168 <td width="77%">
169 </td></tr>
170 <tr valign="top" align="left">
171 <td width="8%"></td>
172 <td width="7%"></td>
173 <td width="8%">
174
175
176 <p>sp = sp - a_args;</p></td>
177 <td width="77%">
178 </td></tr>
179 <tr valign="top" align="left">
180 <td width="8%"></td>
181 <td width="7%"></td>
182 <td width="8%">
183
184
185 <p>/* set a return value (find out where the return value
186 is on the stack,</p></td>
187 <td width="77%">
188 </td></tr>
189 <tr valign="top" align="left">
190 <td width="8%"></td>
191 <td width="7%"></td>
192 <td width="8%">
193
194
195 <p>using libmawk_stackret()) */</p></td>
196 <td width="77%">
197 </td></tr>
198 <tr valign="top" align="left">
199 <td width="8%"></td>
200 <td width="7%"></td>
201 <td width="8%">
202
203
204 <p>libmawk_set_cell(context, libmawk_stackret(sp),
205 &rsquo;f&rsquo;, (double)1234);</p></td>
206 <td width="77%">
207 </td></tr>
208 <tr valign="top" align="left">
209 <td width="8%"></td>
210 <td width="7%"></td>
211 <td width="8%">
212
213
214 <p>/* return the new stack pointer - should be the one that
215 it was before</p></td>
216 <td width="77%">
217 </td></tr>
218 <tr valign="top" align="left">
219 <td width="8%"></td>
220 <td width="7%"></td>
221 <td width="8%">
222
223
224 <p>arguments had been pushed on the stack */</p></td>
225 <td width="77%">
226 </td></tr>
227 <tr valign="top" align="left">
228 <td width="8%"></td>
229 <td width="7%"></td>
230 <td width="8%">
231
232
233 <p>return sp;</p></td>
234 <td width="77%">
235 </td></tr>
236 </table>
237
238 <p style="margin-left:11%;">}</p>
239
240 <p style="margin-left:11%; margin-top: 1em">int main(int
241 argc, char **argv) <br>
242 {</p>
243
244 <table width="100%" border="0" rules="none" frame="void"
245 cellspacing="0" cellpadding="0">
246 <tr valign="top" align="left">
247 <td width="8%"></td>
248 <td width="92%">
249
250
251 <p>mawk_state_t *m;</p></td></tr>
252 <tr valign="top" align="left">
253 <td width="8%"></td>
254 <td width="92%">
255
256
257 <p>CELL ret, arrv, *vr;</p></td></tr>
258 <tr valign="top" align="left">
259 <td width="8%"></td>
260 <td width="92%">
261
262
263 <p>char buff[64];</p></td></tr>
264 </table>
265
266 <p style="margin-left:11%; margin-top: 1em">/* the simpler
267 way is:</p>
268
269 <table width="100%" border="0" rules="none" frame="void"
270 cellspacing="0" cellpadding="0">
271 <tr valign="top" align="left">
272 <td width="8%"></td>
273 <td width="92%">
274
275
276 <p>m = libmawk_initialize(argc, argv);</p></td></tr>
277 <tr valign="top" align="left">
278 <td width="8%"></td>
279 <td width="92%">
280
281
282 <p>However, if the application wants to change the
283 environment before</p></td></tr>
284 <tr valign="top" align="left">
285 <td width="8%"></td>
286 <td width="92%">
287
288
289 <p>executing BEGIN, the following, 3 stage initialization
290 should be done:</p></td></tr>
291 </table>
292
293 <p style="margin-left:11%;">*/</p>
294
295 <table width="100%" border="0" rules="none" frame="void"
296 cellspacing="0" cellpadding="0">
297 <tr valign="top" align="left">
298 <td width="8%"></td>
299 <td width="7%"></td>
300 <td width="8%">
301
302
303 <p>m = libmawk_initialize_stage1(); /* set up m */</p></td>
304 <td width="8%"></td>
305 <td width="7%"></td>
306 <td width="62%">
307 </td></tr>
308 <tr valign="top" align="left">
309 <td width="8%"></td>
310 <td width="7%"></td>
311 <td width="8%">
312
313
314 <p>custom_array_init(m); /* set up a new builtin array with
315 side effects, before parsing scripts */</p></td>
316 <td width="8%"></td>
317 <td width="7%"></td>
318 <td width="62%">
319 </td></tr>
320 <tr valign="top" align="left">
321 <td width="8%"></td>
322 <td width="7%"></td>
323 <td width="8%">
324
325
326 <p>m = libmawk_initialize_stage2(m, argc, argv); /* parse
327 args loads the script(s) */</p></td>
328 <td width="8%"></td>
329 <td width="7%"></td>
330 <td width="62%">
331 </td></tr>
332 <tr valign="top" align="left">
333 <td width="8%"></td>
334 <td width="7%"></td>
335 <td width="8%">
336
337
338 <p>m = libmawk_initialize_stage3(m); /* execute BEGIN {}
339 */</p> </td>
340 <td width="8%"></td>
341 <td width="7%"></td>
342 <td width="62%">
343 </td></tr>
344 <tr valign="top" align="left">
345 <td width="8%"></td>
346 <td width="7%"></td>
347 <td width="8%">
348
349
350 <p>ret.type = C_NOINIT;</p></td>
351 <td width="8%"></td>
352 <td width="7%"></td>
353 <td width="62%">
354 </td></tr>
355 <tr valign="top" align="left">
356 <td width="8%"></td>
357 <td width="7%"></td>
358 <td width="8%">
359
360
361 <p>if (m != NULL) {</p></td>
362 <td width="8%"></td>
363 <td width="7%"></td>
364 <td width="62%">
365 </td></tr>
366 <tr valign="top" align="left">
367 <td width="8%"></td>
368 <td width="7%">
369 </td>
370 <td width="8%">
371 </td>
372 <td width="8%">
373
374
375 <p>/* test function call */</p></td>
376 <td width="7%"></td>
377 <td width="62%">
378 </td></tr>
379 <tr valign="top" align="left">
380 <td width="8%"></td>
381 <td width="7%">
382 </td>
383 <td width="8%">
384 </td>
385 <td width="8%">
386
387
388 <p>if (libmawk_call_function(m, &quot;func&quot;, &amp;ret,
389 &quot;dfs&quot;, (int)42, (double)1.234, (char *)&quot;test
390 string.&quot;) == 0) {</p></td>
391 <td width="7%"></td>
392 <td width="62%">
393 </td></tr>
394 <tr valign="top" align="left">
395 <td width="8%"></td>
396 <td width="7%">
397 </td>
398 <td width="8%">
399 </td>
400 <td width="8%">
401 </td>
402 <td width="7%">
403
404
405 <p>printf(&quot;Return value of func is &rsquo;%s&rsquo;0,
406 libmawk_print_cell(&amp;ret, buff, sizeof(buff)));</p></td>
407 <td width="62%">
408 </td></tr>
409 <tr valign="top" align="left">
410 <td width="8%"></td>
411 <td width="7%">
412 </td>
413 <td width="8%">
414 </td>
415 <td width="8%">
416 </td>
417 <td width="7%">
418
419
420 <p>libmawk_cell_destroy(m, &amp;ret);</p></td>
421 <td width="62%">
422 </td></tr>
423 <tr valign="top" align="left">
424 <td width="8%"></td>
425 <td width="7%">
426 </td>
427 <td width="8%">
428 </td>
429 <td width="8%">
430
431
432 <p>}</p></td>
433 <td width="7%"></td>
434 <td width="62%">
435 </td></tr>
436 <tr valign="top" align="left">
437 <td width="8%"></td>
438 <td width="7%">
439 </td>
440 <td width="8%">
441 </td>
442 <td width="8%">
443
444
445 <p>printf(&quot;Failed to call func()0);</p></td>
446 <td width="7%"></td>
447 <td width="62%">
448 </td></tr>
449 <tr valign="top" align="left">
450 <td width="8%"></td>
451 <td width="7%">
452 </td>
453 <td width="8%">
454 </td>
455 <td width="8%">
456
457
458 <p>/* this is the same function call with a different
459 syntax */</p></td>
460 <td width="7%"></td>
461 <td width="62%">
462 </td></tr>
463 <tr valign="top" align="left">
464 <td width="8%"></td>
465 <td width="7%">
466 </td>
467 <td width="8%">
468 </td>
469 <td width="8%">
470
471
472 <p>{</p></td>
473 <td width="7%"></td>
474 <td width="62%">
475 </td></tr>
476 <tr valign="top" align="left">
477 <td width="8%"></td>
478 <td width="7%">
479 </td>
480 <td width="8%">
481 </td>
482 <td width="8%">
483 </td>
484 <td width="7%">
485
486
487 <p>int i = 42;</p></td>
488 <td width="62%">
489 </td></tr>
490 <tr valign="top" align="left">
491 <td width="8%"></td>
492 <td width="7%">
493 </td>
494 <td width="8%">
495 </td>
496 <td width="8%">
497 </td>
498 <td width="7%">
499
500
501 <p>double d = 1.234;</p></td>
502 <td width="62%">
503 </td></tr>
504 <tr valign="top" align="left">
505 <td width="8%"></td>
506 <td width="7%">
507 </td>
508 <td width="8%">
509 </td>
510 <td width="8%">
511 </td>
512 <td width="7%">
513
514
515 <p>char *s = &quot;test string.&quot;;</p></td>
516 <td width="62%">
517 </td></tr>
518 <tr valign="top" align="left">
519 <td width="8%"></td>
520 <td width="7%">
521 </td>
522 <td width="8%">
523 </td>
524 <td width="8%">
525 </td>
526 <td width="7%">
527
528
529 <p>void *args[] = {&amp;i, &amp;d, s};</p></td>
530 <td width="62%">
531 </td></tr>
532 <tr valign="top" align="left">
533 <td width="8%"></td>
534 <td width="7%">
535 </td>
536 <td width="8%">
537 </td>
538 <td width="8%">
539 </td>
540 <td width="7%">
541
542
543 <p>if (libmawk_call_functionp(m, &quot;func&quot;,
544 &amp;ret, &quot;dfs&quot;, args) != 0) {</p></td>
545 <td width="62%">
546 </td></tr>
547 <tr valign="top" align="left">
548 <td width="8%"></td>
549 <td width="7%">
550 </td>
551 <td width="8%">
552 </td>
553 <td width="8%">
554 </td>
555 <td width="7%">
556 </td>
557 <td width="62%">
558
559
560 <p>printf(&quot;Return value of func is &rsquo;%s&rsquo;0,
561 libmawk_print_cell(&amp;ret, buff, sizeof(buff)));</p></td></tr>
562 <tr valign="top" align="left">
563 <td width="8%"></td>
564 <td width="7%">
565 </td>
566 <td width="8%">
567 </td>
568 <td width="8%">
569 </td>
570 <td width="7%">
571 </td>
572 <td width="62%">
573
574
575 <p>libmawk_cell_destroy(m, &amp;ret);</p></td></tr>
576 <tr valign="top" align="left">
577 <td width="8%"></td>
578 <td width="7%">
579 </td>
580 <td width="8%">
581 </td>
582 <td width="8%">
583 </td>
584 <td width="7%">
585
586
587 <p>}</p></td>
588 <td width="62%">
589 </td></tr>
590 <tr valign="top" align="left">
591 <td width="8%"></td>
592 <td width="7%">
593 </td>
594 <td width="8%">
595 </td>
596 <td width="8%">
597
598
599 <p>}</p></td>
600 <td width="7%"></td>
601 <td width="62%">
602 </td></tr>
603 <tr valign="top" align="left">
604 <td width="8%"></td>
605 <td width="7%">
606 </td>
607 <td width="8%">
608 </td>
609 <td width="8%">
610
611
612 <p>/* register a C function (resolved runtime) */</p></td>
613 <td width="7%"></td>
614 <td width="62%">
615 </td></tr>
616 <tr valign="top" align="left">
617 <td width="8%"></td>
618 <td width="7%">
619 </td>
620 <td width="8%">
621 </td>
622 <td width="8%">
623
624
625 <p>if (libmawk_register_function(m, &quot;blobb&quot;,
626 blobb) != 0) {</p></td>
627 <td width="7%"></td>
628 <td width="62%">
629 </td></tr>
630 <tr valign="top" align="left">
631 <td width="8%"></td>
632 <td width="7%">
633 </td>
634 <td width="8%">
635 </td>
636 <td width="8%">
637 </td>
638 <td width="7%">
639
640
641 <p>fprintf(stderr, &quot;ERROR: Unable to register function
642 blobb0);</p> </td>
643 <td width="62%">
644 </td></tr>
645 <tr valign="top" align="left">
646 <td width="8%"></td>
647 <td width="7%">
648 </td>
649 <td width="8%">
650 </td>
651 <td width="8%">
652
653
654 <p>}</p></td>
655 <td width="7%"></td>
656 <td width="62%">
657 </td></tr>
658 <tr valign="top" align="left">
659 <td width="8%"></td>
660 <td width="7%">
661 </td>
662 <td width="8%">
663 </td>
664 <td width="8%">
665
666
667 <p>/* run some data */</p></td>
668 <td width="7%"></td>
669 <td width="62%">
670 </td></tr>
671 <tr valign="top" align="left">
672 <td width="8%"></td>
673 <td width="7%">
674 </td>
675 <td width="8%">
676 </td>
677 <td width="8%">
678
679
680 <p>libmawk_append_input(m, &quot;This is a0ultiline test
681 input0ut in the artificial input buffer.0);</p></td>
682 <td width="7%"></td>
683 <td width="62%">
684 </td></tr>
685 <tr valign="top" align="left">
686 <td width="8%"></td>
687 <td width="7%">
688 </td>
689 <td width="8%">
690 </td>
691 <td width="8%">
692
693
694 <p>libmawk_run_main(m);</p></td>
695 <td width="7%"></td>
696 <td width="62%">
697 </td></tr>
698 <tr valign="top" align="left">
699 <td width="8%"></td>
700 <td width="7%">
701 </td>
702 <td width="8%">
703 </td>
704 <td width="8%">
705
706
707 <p>/* print var: scalar */</p></td>
708 <td width="7%"></td>
709 <td width="62%">
710 </td></tr>
711 <tr valign="top" align="left">
712 <td width="8%"></td>
713 <td width="7%">
714 </td>
715 <td width="8%">
716 </td>
717 <td width="8%">
718
719
720 <p>vr = libmawk_get_var(m, &quot;var&quot;);</p></td>
721 <td width="7%"></td>
722 <td width="62%">
723 </td></tr>
724 <tr valign="top" align="left">
725 <td width="8%"></td>
726 <td width="7%">
727 </td>
728 <td width="8%">
729 </td>
730 <td width="8%">
731
732
733 <p>if (vr != NULL)</p></td>
734 <td width="7%"></td>
735 <td width="62%">
736 </td></tr>
737 <tr valign="top" align="left">
738 <td width="8%"></td>
739 <td width="7%">
740 </td>
741 <td width="8%">
742 </td>
743 <td width="8%">
744 </td>
745 <td width="7%">
746
747
748 <p>printf(&quot;Variable var = &rsquo;%s&rsquo;0,
749 libmawk_print_cell(vr, buff, sizeof(buff)));</p></td>
750 <td width="62%">
751 </td></tr>
752 <tr valign="top" align="left">
753 <td width="8%"></td>
754 <td width="7%">
755 </td>
756 <td width="8%">
757 </td>
758 <td width="8%">
759
760
761 <p>else</p></td>
762 <td width="7%"></td>
763 <td width="62%">
764 </td></tr>
765 <tr valign="top" align="left">
766 <td width="8%"></td>
767 <td width="7%">
768 </td>
769 <td width="8%">
770 </td>
771 <td width="8%">
772 </td>
773 <td width="7%">
774
775
776 <p>printf(&quot;No such variable</p></td>
777 <td width="62%">
778 </td></tr>
779 <tr valign="top" align="left">
780 <td width="8%"></td>
781 <td width="7%">
782 </td>
783 <td width="8%">
784 </td>
785 <td width="8%">
786
787
788 <p>/* print var: array */</p></td>
789 <td width="7%"></td>
790 <td width="62%">
791 </td></tr>
792 </table>
793
794 <p style="margin-left:11%;">#warning TODO</p>
795
796 <table width="100%" border="0" rules="none" frame="void"
797 cellspacing="0" cellpadding="0">
798 <tr valign="top" align="left">
799 <td width="8%"></td>
800 <td width="7%">
801 </td>
802 <td width="8%">
803 </td>
804 <td width="8%">
805
806
807 <p>arrv.type = C_NOINIT;</p></td>
808 <td width="69%">
809 </td></tr>
810 <tr valign="top" align="left">
811 <td width="8%"></td>
812 <td width="7%">
813 </td>
814 <td width="8%">
815 </td>
816 <td width="8%">
817
818
819 <p>if (libmawk_get_array_at(m, &quot;arr&quot;,
820 &quot;hello&quot;, &amp;arrv, 0) &gt; 0)</p></td>
821 <td width="69%">
822 </td></tr>
823 <tr valign="top" align="left">
824 <td width="8%"></td>
825 <td width="7%">
826 </td>
827 <td width="8%">
828 </td>
829 <td width="8%">
830 </td>
831 <td width="69%">
832
833
834 <p>printf(&quot;Variable arr[</p></td></tr>
835 <tr valign="top" align="left">
836 <td width="8%"></td>
837 <td width="7%">
838 </td>
839 <td width="8%">
840 </td>
841 <td width="8%">
842
843
844 <p>else</p></td>
845 <td width="69%">
846 </td></tr>
847 <tr valign="top" align="left">
848 <td width="8%"></td>
849 <td width="7%">
850 </td>
851 <td width="8%">
852 </td>
853 <td width="8%">
854 </td>
855 <td width="69%">
856
857
858 <p>printf(&quot;No such variable</p></td></tr>
859 </table>
860
861 <p style="margin-left:11%; margin-top: 1em">#warning todo:
862 array set</p>
863
864 <table width="100%" border="0" rules="none" frame="void"
865 cellspacing="0" cellpadding="0">
866 <tr valign="top" align="left">
867 <td width="11%"></td>
868 <td width="-3%"></td>
869 <td width="7%">
870 </td>
871 <td width="8%">
872 </td>
873 <td width="8%">
874
875
876 <p>/* set var: array; change the existing
877 (arr[&quot;hello&quot;]) */</p></td>
878 <td width="69%">
879 </td></tr>
880 <tr valign="top" align="left">
881 <td width="11%"></td>
882 <td width="-3%"></td>
883 <td width="7%">
884
885
886 <p>//</p></td>
887 <td width="8%">
888 </td>
889 <td width="8%">
890
891
892 <p>if (ret != NULL)</p></td>
893 <td width="69%">
894 </td></tr>
895 <tr valign="top" align="left">
896 <td width="11%"></td>
897 <td width="-3%"></td>
898 <td width="7%">
899
900
901 <p>//</p></td>
902 <td width="8%">
903 </td>
904 <td width="8%">
905 </td>
906 <td width="69%">
907
908
909 <p>libmawk_set_cell(m, ret, &rsquo;s&rsquo;,
910 &quot;WORLD&quot;);</p> </td></tr>
911 <tr valign="top" align="left">
912 <td width="11%"></td>
913 <td width="-3%"></td>
914 <td width="7%">
915 </td>
916 <td width="8%">
917 </td>
918 <td width="8%">
919
920
921 <p>/* set var: array; create a new index */</p></td>
922 <td width="69%">
923 </td></tr>
924 </table>
925
926 <p style="margin-left:11%;">#warning todo: array set</p>
927
928 <table width="100%" border="0" rules="none" frame="void"
929 cellspacing="0" cellpadding="0">
930 <tr valign="top" align="left">
931 <td width="11%"></td>
932 <td width="-3%"></td>
933 <td width="7%">
934
935
936 <p>//</p></td>
937 <td width="8%">
938 </td>
939 <td width="77%">
940
941
942 <p>libmawk_get_array_at(m, &quot;arr&quot;,
943 &quot;bye&quot;, &amp;arrv, 1);</p></td></tr>
944 <tr valign="top" align="left">
945 <td width="11%"></td>
946 <td width="-3%"></td>
947 <td width="7%">
948
949
950 <p>//</p></td>
951 <td width="8%">
952 </td>
953 <td width="77%">
954
955
956 <p>libmawk_set_cell(m, ret, &rsquo;s&rsquo;,
957 &quot;universe&quot;);</p> </td></tr>
958 <tr valign="top" align="left">
959 <td width="11%"></td>
960 <td width="-3%"></td>
961 <td width="7%">
962 </td>
963 <td width="8%">
964 </td>
965 <td width="77%">
966
967
968 <p>/* run some more data */</p></td></tr>
969 <tr valign="top" align="left">
970 <td width="11%"></td>
971 <td width="-3%"></td>
972 <td width="7%">
973 </td>
974 <td width="8%">
975 </td>
976 <td width="77%">
977
978
979 <p>libmawk_append_input(m, &quot;Second0);</p></td></tr>
980 <tr valign="top" align="left">
981 <td width="11%"></td>
982 <td width="-3%"></td>
983 <td width="7%">
984 </td>
985 <td width="8%">
986 </td>
987 <td width="77%">
988
989
990 <p>libmawk_append_input(m, &quot;run.0);</p></td></tr>
991 <tr valign="top" align="left">
992 <td width="11%"></td>
993 <td width="-3%"></td>
994 <td width="7%">
995 </td>
996 <td width="8%">
997 </td>
998 <td width="77%">
999
1000
1001 <p>libmawk_run_main(m);</p></td></tr>
1002 <tr valign="top" align="left">
1003 <td width="11%"></td>
1004 <td width="-3%"></td>
1005 <td width="7%">
1006 </td>
1007 <td width="8%">
1008 </td>
1009 <td width="77%">
1010
1011
1012 <p>custom_array_print(m);</p></td></tr>
1013 <tr valign="top" align="left">
1014 <td width="11%"></td>
1015 <td width="-3%"></td>
1016 <td width="7%">
1017 </td>
1018 <td width="8%">
1019 </td>
1020 <td width="77%">
1021
1022
1023 <p>/* run end */</p></td></tr>
1024 <tr valign="top" align="left">
1025 <td width="11%"></td>
1026 <td width="-3%"></td>
1027 <td width="7%">
1028 </td>
1029 <td width="8%">
1030 </td>
1031 <td width="77%">
1032
1033
1034 <p>libmawk_uninitialize(m);</p></td></tr>
1035 <tr valign="top" align="left">
1036 <td width="11%"></td>
1037 <td width="-3%"></td>
1038 <td width="7%"></td>
1039 <td width="8%">
1040
1041
1042 <p>}</p></td>
1043 <td width="77%">
1044 </td></tr>
1045 <tr valign="top" align="left">
1046 <td width="11%"></td>
1047 <td width="-3%"></td>
1048 <td width="7%"></td>
1049 <td width="8%">
1050
1051
1052 <p>else {</p></td>
1053 <td width="77%">
1054 </td></tr>
1055 <tr valign="top" align="left">
1056 <td width="11%"></td>
1057 <td width="-3%"></td>
1058 <td width="7%">
1059 </td>
1060 <td width="8%">
1061 </td>
1062 <td width="77%">
1063
1064
1065 <p>printf(&quot;Init failed.0);</p></td></tr>
1066 <tr valign="top" align="left">
1067 <td width="11%"></td>
1068 <td width="-3%"></td>
1069 <td width="7%"></td>
1070 <td width="8%">
1071
1072
1073 <p>}</p></td>
1074 <td width="77%">
1075 </td></tr>
1076 <tr valign="top" align="left">
1077 <td width="11%"></td>
1078 <td width="-3%"></td>
1079 <td width="7%"></td>
1080 <td width="8%">
1081
1082
1083 <p>printf(&quot;END0);</p></td>
1084 <td width="77%">
1085 </td></tr>
1086 <tr valign="top" align="left">
1087 <td width="11%"></td>
1088 <td width="-3%"></td>
1089 <td width="7%"></td>
1090 <td width="8%">
1091
1092
1093 <p>return 0 ;</p></td>
1094 <td width="77%">
1095 </td></tr>
1096 </table>
1097
1098 <p style="margin-left:11%;">}</p>
1099 <hr>
1100 </body>
1101 </html>
0 <HTML>
1 <BODY>
2 <H1> awk script execution </H1>
3 Libmawk runs the bytecode of the script in a <a href="developer/vm">virtual machine</a>.
4 The VM takes the bytecode as a series of instructions that operate on data
5 stored on the execution stack and in global states of the script instance
6 (libmawk_state_t).
7 <p>
8 There is only one thing at a time an instance is doing, however that
9 one thing may be interrupted and resumed any time. This one thing is
10 always one of these:
11 <ul>
12 <li> running BEGIN
13 <li> running END
14 <li> running main (the stdin read and pattern match rules)
15 <li> running an awk function called from the application
16 <li> nothing: empty stack; before starting or after finishing any of the above activities
17 </ul>
18 <p>
19 BEGIN, END, main and awk functions are the four entry points of executing
20 the script. Normally BEGIN is run right after setting up the script, then
21 main is run on all input and END is run when the script exits, right
22 before uninitialization of the script instance. This is a 1:1 copy
23 of the standard way awk works. The fourth, calling awk functions directly
24 from the application is an extra entry point.
25 <p>
26 The script is not doing anything unless the application commands it to. Some
27 of the simplified API does this automatically, but the raw API (staged
28 init/uninit) always lets the app decide when to <b>start</b> running the script.
29 This document calls an <i>execution transaction<i> when the application calls
30 the API to start running a script.
31 <p>
32 Any execution related call is non-blocking, thus it will return after a
33 reasonable time spent running the script and will never stuck running
34 an infinite loop. When such an API call returns, the return value
35 is a mawk_exec_result_t that indicates the reason of the return:
36 <ul>
37 <li> 1. if the script attempts to read a file/pipe that would block, it interrupts execution and returns (with <i>MAWK_EXER_INT_READ</i>) instead
38 <li> 2. when reaching the run limit (a given number of instructions has been executed), the script is interrupted (return value is <i>MAWK_EXER_INT_RUNLIMIT</i>)
39 <li> 3. the script may finish executing the current execution transaction (<i>MAWK_EXER_DONE</i> or <i>MAWK_EXER_FUNCRET</i>)
40 <li> 4. the script may decide to exit
41 </ul>
42 <p>
43 <i>Execution transaction<i> are collected on the evaluation stack. If
44 the application requests an execution and the API call returns before
45 finishing, the transaction is still active. The application is
46 free to initiate a new <i>execution transaction<i>, without
47 first finishing the previous one. However, the VM will always resume and
48 progress running the most recent <i>execution transaction<i>. This means
49 <i>execution transactions<i> are sort of nested. When the top, most recent
50 <i>execution transaction<i> finishes (return 3), the next resume request
51 will go on with the previous transaction.
52 <p>
53 Note, however, that the script has global states. The most obvious state
54 is the exit state: if the script runs exit(), it will discard all open
55 transactions. For example consider a script that is running a main part
56 processing the input. When the application is in this phase, the topmost
57 transaction is always a "running main" transaction that returned
58 previously because there was no more input to be processed. If the
59 application calls an awk function that decides to do an exit(), that will
60 affect not only discard the function transaction but the pending "running main"
61 transaction as well. Whenever the application requests a resume on
62 the code, that will start running the END section.
63
64
65 <h2> return path 1.: MAWK_EXER_INT_READ </h2>
66 Assume stdin is a FIFO between the application and the script. The
67 first script tries to prefix each line:
68 <pre>
69 {
70 print "prefix:", $0
71 }
72 </pre>
73 The application fills the FIFO with some data that may contain one or
74 more full records, potentially ending with a partial (unterminated)
75 record. If the application resumes the script, it will try to
76 read all full records and process them. It will interrupt
77 execution and return MAWK_EXER_INT_READ the first time a full
78 record can't be read. This always happens "before the {}".
79 <p>
80 A slightly more complicated script prefixes odd and even lines differently:
81 <pre>
82 {
83 print "odd:", $0
84 getline
85 print "even:", $0
86 }
87 </pre>
88 This script may return with MAWK_EXER_INT_READ either before {}
89 or in the getline instruction. This means the application should not
90 assume that when main returns it was not in the middle of such
91 a block. (In the actual VM main starts with an implicit getline so
92 there's no difference between the two cases).
93 <p>
94 A similar situation is when an awk function is executing getline on a FIFO:
95 the application that calls the function shall not expect that the function
96 finishes and produces its return value in the initial execution request.
97 Instead the request will create a new <i>execution transaction<i> and
98 multiple resume calls may be needed until the function actually returns.
99 <p>
100 Obviously the application shall fill the FIFO while executing resumes:
101 if there is no new input and the script is waiting for new input, the
102 resume call will return immediately.
103
104
105 <h2> return path 2.: <i>MAWK_EXER_INT_RUNLIMIT</i> </h2>
106 When runlimit is set the VM returns after executing a certain amount of
107 instructions. The application shall decide whether to simply resume or
108 to stop executing the script.
109 <p>
110 This feature is useful when the application is implemented as a single
111 threaded async loop: running a blocking script would block the entire loop.
112
113
114 <h2> return path 3.: <i>MAWK_EXER_DONE</i> or <i>MAWK_EXER_FUNCRET</i> </h2>
115 When BEGIN or main or END finishes <i>MAWK_EXER_DONE</i> is returned. When
116 an awk function called by the application returns, <i>MAWK_EXER_FUNCRET</i>
117 is returned and the retc argument is filled with the return value cell
118 (which may be of cell type NOINIT in case there was no return value).
119 <p>
120 The application <b>shall never</b> expect the initial call that
121 created the new <i>execution transaction<i> will end in
122 <i>MAWK_EXER_DONE</i> or <i>MAWK_EXER_FUNCRET</i>; when it does not,
123 a subsequent resume call eventually will.
124
125 <h2> return path 4.: <i>MAWK_EXER_EXIT</i> </h2>
126 Similar to <i>MAWK_EXER_DONE</i>, but means the script called exit.
127 This is legal from even an awk function call, in which case the
128 function will never have a return value (as the code can not be resumed
129 any more). Normal awk rules apply: calling exit() from BEGIN or main
130 (or subsequent functions, called by the script or the application) puts
131 the script in exit mode and next resume will run END. Calling exit from
132 END will exit immediately leaving the script in non-runnable state.
133
134
135 <h2> conclusion: script execution </h2>
136 It is safe to assume calling any script execution will return with
137 a conclusion if, and only if:
138 <ul>
139 <li> the script is not allowed to use getline on FIFOs (which can not be guaranteed!) or there are no FIFOs or otherwise blocking input (i.e. all files are plain files); and
140 <li> there is no run limit configured
141 </ul>
142 <p>
143 Since these are not guaranteed in most common use cases, the code should prepare
144 to:
145 <ul>
146 <li> start executing the code and check if it's already finished
147 <li> resume until it actually does finish
148 <li> if the script returned <i>MAWK_EXER_INT_READ</i>: fill FIFOs or if that's not possible stop resuming as there won't be any progress
149 </ul>
150 <p>
151 Thus following c-pseudo-code should be used:
152 <pre>
153 TODO
154 </pre>
0 <HTML>
1 <BODY>
2 <H1> Table Of Contents </H1>
3 <H2> Manual pages </H2>
4 <UL>
5 <LI> <a href="lmawk.1.html"> lmawk(1) </a> - command line implementation
6 <LI> <a href="example.7libmawk.html"> example(7libmawk) </a> - example on using the library
7 <LI> <a href="libmawk_append_input.3libmawk.html"> libmawk_append_input(3) </a>
8 <LI> <a href="libmawk_call_function.3libmawk.html"> libmawk_call_function(3) </a>
9 <LI> <a href="libmawk_cell_destroy.3libmawk.html"> libmawk_cell_destroy(3) </a>
10 <LI> <a href="libmawk_get_var.3libmawk.html"> libmawk_get_var(3) </a>
11 <LI> <a href="libmawk_initialize.3libmawk.html"> libmawk_initialize(3) </a>
12 <LI> <a href="libmawk_initialize_stage.3libmawk.html"> libmawk_initialize_stage(3) </a>
13 <LI> <a href="libmawk_register_function.3libmawk.html"> libmawk_register_function(3) </a>
14 <LI> <a href="libmawk_run_main.3libmawk.html"> libmawk_run_main(3) </a>
15 <LI> <a href="libmawk_set_cell.3libmawk.html"> libmawk_set_cell(3) </a>
16 <LI> <a href="libmawk_uninitialize.3libmawk.html"> libmawk_uninitialize(3) </a>
17 </UL>
18 <H2> Design decisions </H2>
19 <UL>
20 <LI> <a href="autotools.html"> why not using autotools in libmawk </a>
21 <LI> <a href="portability.html"> portability with scconfig </a>
22 <LI> <a href="semi-gnu.html"> semi-dependency on GNU utils </a>
23 <LI> <a href="numeric.html"> different numeric types and FPE/NaN </a>
24 </UL>
25 </BODY>
26 </HTML>
27
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:30 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LIBMAWK_APPEND_INPUT</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LIBMAWK_APPEND_INPUT</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#SEE ALSO">SEE ALSO</a><br>
26
27 <hr>
28
29
30 <h2>NAME
31 <a name="NAME"></a>
32 </h2>
33
34
35
36 <p style="margin-left:11%; margin-top: 1em">libmawk_append_input
37 &minus; append a string to an input buffer</p>
38
39 <h2>SYNOPSIS
40 <a name="SYNOPSIS"></a>
41 </h2>
42
43
44 <p style="margin-left:11%; margin-top: 1em"><b>#include
45 &lt;libmawk.h&gt;</b></p>
46
47 <p style="margin-left:11%; margin-top: 1em"><b>void
48 libmawk_append_input(mawk_state_t *</b><i>m</i><b>, const
49 char *</b><i>input_str</i><b>);</b></p>
50
51 <p style="margin-left:11%; margin-top: 1em"><b>void
52 libmawk_append_ninput(mawk_state_t *</b><i>m</i><b>, const
53 char *</b><i>input</i><b>, int</b><i>len</i><b>);</b></p>
54
55 <h2>DESCRIPTION
56 <a name="DESCRIPTION"></a>
57 </h2>
58
59
60 <p style="margin-left:11%; margin-top: 1em">The
61 <b>libmawk_append_input</b>() and
62 <b>libmawk_append_ninput</b>() functions allow the
63 application to fill the input buffer of a libmawk context.
64 No record separator is appended, only the bytes donated by
65 input_str or input, thus it is possible to append partial
66 records. Appending to the input doesn&rsquo;t have the side
67 effect of any script being run. There may be multiple
68 libmawk_append_input() calls before a call to
69 libmawk_run_main(). The latter all is used to let the script
70 process the input buffer.</p>
71
72 <p style="margin-left:11%; margin-top: 1em">The only
73 difference between the two calls are the input format:
74 <b>libmawk_append_input</b>() expects a nul-terminated
75 string, whereas <b>libmawk_append_ninput</b>() takes an
76 arbitrary binary data and its length.</p>
77
78 <p style="margin-left:11%; margin-top: 1em">Argument m is a
79 libmawk context previously returned by libmawk_initialize()
80 or libmawk_initialize_stage3().</p>
81
82 <h2>SEE ALSO
83 <a name="SEE ALSO"></a>
84 </h2>
85
86
87
88 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage</b>(3libmawk),
89 <b>libmawk_initialize</b>(3libmawk),
90 <b>libmawk_run_main</b>(3libmawk).</p>
91 <hr>
92 </body>
93 </html>
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:31 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LIBMAWK_CALL_FUNCTION</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LIBMAWK_CALL_FUNCTION</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#RETURN VALUE">RETURN VALUE</a><br>
26 <a href="#SEE ALSO">SEE ALSO</a><br>
27
28 <hr>
29
30
31 <h2>NAME
32 <a name="NAME"></a>
33 </h2>
34
35
36
37 <p style="margin-left:11%; margin-top: 1em">libmawk_call_function
38 &minus; call an user defined (script) function</p>
39
40 <h2>SYNOPSIS
41 <a name="SYNOPSIS"></a>
42 </h2>
43
44
45 <p style="margin-left:11%; margin-top: 1em"><b>#include
46 &lt;libmawk.h&gt;</b></p>
47
48 <p style="margin-left:11%; margin-top: 1em"><b>int
49 libmawk_call_function(mawk_state_t *</b><i>MAWK</i><b>,
50 const char *</b><i>fname</i><b>, CELL *</b><i>res</i><b>,
51 const char *</b><i>argtpes</i><b>, ...); <br>
52 int libmawk_call_functionp(mawk_state_t *</b><i>MAWK</i><b>,
53 const char *</b><i>fname</i><b>, CELL *</b><i>res</i><b>,
54 const char *</b><i>argtpes</i><b>, void **args);</b></p>
55
56 <h2>DESCRIPTION
57 <a name="DESCRIPTION"></a>
58 </h2>
59
60
61 <p style="margin-left:11%; margin-top: 1em">The
62 <b>libmawk_call_function</b>() function looks up an user
63 defined awk function called <i>fname</i> , fills the stack
64 with arguments converted from the varargs and calls the
65 function. The <b>libmawk_call_functionp</b>() performs the
66 same action but avoids using vararg by requiring an array of
67 generic pointers to the function arguments.</p>
68
69 <p style="margin-left:11%; margin-top: 1em">Argtype is a
70 zero terminated string for both functions, each character
71 corresponding to an argument. Type characters are described
72 in libmawk_set_cell() manual page.</p>
73
74 <p style="margin-left:11%; margin-top: 1em">If res is
75 non-NULL, it is cell_destroyed (regardless of errors) and
76 the return value of the user function is copied into it. The
77 caller shall run libmawk_cell_destroy on it.</p>
78
79 <p style="margin-left:11%; margin-top: 1em">Argument m is a
80 libmawk context previously returned by libmawk_initialize()
81 or libmawk_initialize_stage3().</p>
82
83 <h2>RETURN VALUE
84 <a name="RETURN VALUE"></a>
85 </h2>
86
87
88 <p style="margin-left:11%; margin-top: 1em">A pointer to
89 the cell returned by the user function. The cell
90 returnedmust be destroyed by the application using
91 libmawk_cell_destroy.</p>
92
93 <h2>SEE ALSO
94 <a name="SEE ALSO"></a>
95 </h2>
96
97
98
99 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage</b>(3libmawk),
100 <b>libmawk_initialize</b>(3libmawk),
101 <b>libmawk_cell_destroy</b>(3libmawk),
102 <b>libmawk_set_cell</b>(3libmawk),</p>
103 <hr>
104 </body>
105 </html>
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:31 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LIBMAWK_CELL_DESTROY</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LIBMAWK_CELL_DESTROY</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#SEE ALSO">SEE ALSO</a><br>
26
27 <hr>
28
29
30 <h2>NAME
31 <a name="NAME"></a>
32 </h2>
33
34
35
36 <p style="margin-left:11%; margin-top: 1em">libmawk_cell_destroy
37 &minus; free all memory associated with a cell</p>
38
39 <h2>SYNOPSIS
40 <a name="SYNOPSIS"></a>
41 </h2>
42
43
44 <p style="margin-left:11%; margin-top: 1em"><b>#include
45 &lt;libmawk.h&gt;</b></p>
46
47 <p style="margin-left:11%; margin-top: 1em"><b>void
48 libmawk_cell_destroy(mawk_state_t *</b><i>m</i><b>, CELL
49 *</b><i>c</i><b>);</b></p>
50
51 <h2>DESCRIPTION
52 <a name="DESCRIPTION"></a>
53 </h2>
54
55
56 <p style="margin-left:11%; margin-top: 1em">The
57 <b>libmawk_cell_destroy</b>() function frees all memory
58 allocated to store a mawk cell. It is useful with some of
59 the libmawk calls that return a newly allocated cell, such
60 as the libmawk_call_function() call.</p>
61
62 <p style="margin-left:11%; margin-top: 1em">Argument m is a
63 libmawk context previously returned by libmawk_initialize()
64 or libmawk_initialize_stage3().</p>
65
66 <h2>SEE ALSO
67 <a name="SEE ALSO"></a>
68 </h2>
69
70
71
72 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage</b>(3libmawk),
73 <b>libmawk_initialize</b>(3libmawk),
74 <b>libmawk_call_function</b>(3libmawk).</p>
75 <hr>
76 </body>
77 </html>
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:31 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LIBMAWK_GET_VAR</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LIBMAWK_GET_VAR</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#SEE ALSO">SEE ALSO</a><br>
26
27 <hr>
28
29
30 <h2>NAME
31 <a name="NAME"></a>
32 </h2>
33
34
35
36 <p style="margin-left:11%; margin-top: 1em">libmawk_get_var
37 &minus; returns a pointer to a mawk variable</p>
38
39 <h2>SYNOPSIS
40 <a name="SYNOPSIS"></a>
41 </h2>
42
43
44 <p style="margin-left:11%; margin-top: 1em"><b>#include
45 &lt;libmawk.h&gt;</b></p>
46
47 <p style="margin-left:11%; margin-top: 1em"><b>CELL
48 *libmawk_get_var(mawk_state_t *</b><i>m</i><b>, const char
49 *</b><i>vname</i><b>); <br>
50 int libmawk_get_array_at(mawk_state_t *</b><i>m</i><b>,
51 const char *</b><i>arr_name</i><b>, <br>
52 const char *</b><i>idx</i><b>, const char
53 *</b><i>res</i><b>, int</b> <i>alloc</i><b>);</b></p>
54
55 <h2>DESCRIPTION
56 <a name="DESCRIPTION"></a>
57 </h2>
58
59
60 <p style="margin-left:11%; margin-top: 1em">The
61 <b>libmawk_get_var</b>() function returns a pointer to a
62 mawk cell that represents the global variable with name
63 passed in <i>vname</i> in the given context. The returned
64 CELL should never be free&rsquo;d or destroyed. Function
65 libmawk_print_cell may be used for converting the cell to
66 string. The caller should not change the type of cell but is
67 free to change the value.</p>
68
69 <p style="margin-left:11%; margin-top: 1em">Function
70 <b>libmawk_get_array_at</b>() performs the same operation
71 for an element of an array. -1 is returned if
72 <i>arr_name</i> is not an array or upon an error. If
73 <i>idx</i> is not an existing index in the array it is
74 allocated if <i>alloc</i> is non-zero. If <i>res</i> is not
75 NULL, it is destroyed (regardless of the return value) and
76 if the index exists (or is created by the call), is loaded
77 with the value. The caller needs to destroy <i>res</i> after
78 use. Since <i>res</i> is destroyed when non-NULL, it must be
79 a valid cell with valid type.</p>
80
81 <p style="margin-left:11%; margin-top: 1em">Argument m is a
82 libmawk context previously returned by libmawk_initialize()
83 or libmawk_initialize_stage3().</p>
84
85 <h2>SEE ALSO
86 <a name="SEE ALSO"></a>
87 </h2>
88
89
90
91 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage</b>(3libmawk),
92 <b>libmawk_initialize</b>(3libmawk),
93 <b>libmawk_call_function</b>(3libmawk),
94 <b>libmawk_print_cell</b>(3libmawk).</p>
95 <hr>
96 </body>
97 </html>
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:31 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LIBMAWK_INITIALIZE</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LIBMAWK_INITIALIZE</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#RETURN VALUE">RETURN VALUE</a><br>
26 <a href="#SEE ALSO">SEE ALSO</a><br>
27
28 <hr>
29
30
31 <h2>NAME
32 <a name="NAME"></a>
33 </h2>
34
35
36
37 <p style="margin-left:11%; margin-top: 1em">libmawk_initialize
38 &minus; create a new libmawk context</p>
39
40 <h2>SYNOPSIS
41 <a name="SYNOPSIS"></a>
42 </h2>
43
44
45 <p style="margin-left:11%; margin-top: 1em"><b>#include
46 &lt;libmawk.h&gt;</b></p>
47
48
49 <p style="margin-left:11%; margin-top: 1em"><b>mawk_state_t
50 *libmawk_initialize(int</b> <i>s</i><b>, char
51 *</b><i>argv[]</i><b>);</b></p>
52
53 <h2>DESCRIPTION
54 <a name="DESCRIPTION"></a>
55 </h2>
56
57
58 <p style="margin-left:11%; margin-top: 1em">The
59 <b>libmawk_initialize</b>() function returns a pointer to a
60 newly created libmawk context. Any amount of libmawk
61 contexts can live in parallel in an application. Arguments
62 are the same as for a command line mawk session. Scripts are
63 loaded (either from command line or from files using -f),
64 variables are set (with -v), special options are set (with
65 -W), etc.</p>
66
67 <h2>RETURN VALUE
68 <a name="RETURN VALUE"></a>
69 </h2>
70
71
72 <p style="margin-left:11%; margin-top: 1em">A pointer to a
73 new libmawk context or NULL on error.</p>
74
75 <h2>SEE ALSO
76 <a name="SEE ALSO"></a>
77 </h2>
78
79
80
81 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage</b>(3libmawk),
82 <b>libmawk_uninitialize</b>(3libmawk),</p>
83 <hr>
84 </body>
85 </html>
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:32 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LIBMAWK_INITIALIZE_STAGE</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LIBMAWK_INITIALIZE_STAGE</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#RETURN VALUE">RETURN VALUE</a><br>
26 <a href="#SEE ALSO">SEE ALSO</a><br>
27
28 <hr>
29
30
31 <h2>NAME
32 <a name="NAME"></a>
33 </h2>
34
35
36
37 <p style="margin-left:11%; margin-top: 1em">libmawk_initialize_stage*
38 &minus; create a new libmawk context in 3 stages</p>
39
40 <h2>SYNOPSIS
41 <a name="SYNOPSIS"></a>
42 </h2>
43
44
45 <p style="margin-left:11%; margin-top: 1em"><b>#include
46 &lt;libmawk.h&gt;</b></p>
47
48
49 <p style="margin-left:11%; margin-top: 1em"><b>mawk_state_t
50 *libmawk_initialize_stage1(void);</b></p>
51
52
53 <p style="margin-left:11%; margin-top: 1em"><b>mawk_state_t
54 *libmawk_initialize_stage2(mawk_state_t *</b>
55 <i>m,</i><b>int</b> <i>s</i>
56 <b>,</b><i>char</i><b>*&quot;</b><i>argv[]</i><b>);</b></p>
57
58
59 <p style="margin-left:11%; margin-top: 1em"><b>mawk_state_t
60 *libmawk_initialize_stage3(mawk_state_t *</b>
61 <i>m</i><b>);</b></p>
62
63 <h2>DESCRIPTION
64 <a name="DESCRIPTION"></a>
65 </h2>
66
67
68 <p style="margin-left:11%; margin-top: 1em">The
69 <b>libmawk_initialize_stage*</b>() functions together do the
70 same as libmawk_initialize() but allows the application to
71 take actions between different stages.
72 <b>libmawk_initialize_stage1</b>() returns a pointer to a
73 newly created libmawk context. Any amount of libmawk
74 contexts can live in parallel in an application.</p>
75
76
77 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage2</b>()
78 can be called after a succesful stage1 call. <br>
79 Stage2 is responsible for processing the command line
80 arguments and loading any script.</p>
81
82 <p style="margin-left:11%; margin-top: 1em">Arguments are
83 the same as for a command line mawk session. Scripts are
84 loaded (either from command line or from files using -f),
85 variables are set (with -v), special options are set (with
86 -W), etc. Unlike with libmawk_initialize(), the application
87 may decide not to provide any script at this stage. All
88 command line arguments are processed.</p>
89
90 <p style="margin-left:11%; margin-top: 1em">The most common
91 case is that the application calls stage1 with no script,
92 then already having a context makes some manipulations on it
93 (for example registers some C functions that would be
94 already called in the BEGIN part of the script that will be
95 later loaded). Optionally before calling stage2 the
96 application loads the actual script(s) using
97 mawk_append_input_file().</p>
98
99
100 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage3</b>()
101 is called as a final step of the three-stage initialization
102 process. Stage3 is responsible for running all the BEGIN
103 parts of all scripts loaded at stage1 or stage2. It is
104 useful to have stage3 in a separate call to allow
105 applications to manipulate the context right before
106 initializing the scripts.</p>
107
108 <p style="margin-left:11%; margin-top: 1em">Stage2 gets the
109 pointer returned by stage1 and stage3 gets the pointer
110 returned by stage2. Subsequent calls to libmawk functions
111 should get the pointer returned by stage3.</p>
112
113 <h2>RETURN VALUE
114 <a name="RETURN VALUE"></a>
115 </h2>
116
117
118 <p style="margin-left:11%; margin-top: 1em">At stage 1 a
119 pointer to a new libmawk context or NULL on error.
120 Subsequent stages will return the same pointer or NULL on
121 error.</p>
122
123 <h2>SEE ALSO
124 <a name="SEE ALSO"></a>
125 </h2>
126
127
128
129 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage</b>(3libmawk),
130 <b>libmawk_uninitialize</b>(3libmawk),
131 <b>mawk_append_input_file(3libmawk).</b></p>
132 <hr>
133 </body>
134 </html>
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:32 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LIBMAWK_REGISTER_FUNCTION</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LIBMAWK_REGISTER_FUNCTION</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#RETURN VALUE">RETURN VALUE</a><br>
26 <a href="#SEE ALSO">SEE ALSO</a><br>
27
28 <hr>
29
30
31 <h2>NAME
32 <a name="NAME"></a>
33 </h2>
34
35
36
37 <p style="margin-left:11%; margin-top: 1em">libmawk_register_function
38 &minus; registers a C function with a callback</p>
39
40 <h2>SYNOPSIS
41 <a name="SYNOPSIS"></a>
42 </h2>
43
44
45 <p style="margin-left:11%; margin-top: 1em"><b>#include
46 &lt;libmawk.h&gt;</b></p>
47
48 <p style="margin-left:11%; margin-top: 1em"><b>typedef CELL
49 *libmawk_c_function(mawk_state_t *</b><i>m</i><b>, CELL
50 *</b><i>sp</i><b>, int</b> <i>a_args</i><b>); <br>
51 int libmawk_register_function(mawk_state_t
52 *</b><i>MAWK</i><b>, const char *</b><i>fname</i><b>,
53 libmawk_c_function *</b><i>callback</i><b>); <br>
54 CELL *libmawk_stackret(CELL
55 *</b><i>original_sp</i><b>);</b></p>
56
57 <h2>DESCRIPTION
58 <a name="DESCRIPTION"></a>
59 </h2>
60
61
62 <p style="margin-left:11%; margin-top: 1em">The
63 <b>libmawk_register_function</b>() call registers an user
64 defined function donated by the host application in a mawk
65 context so that it acts exactly like user defined functions
66 in written in awk. The name of the new function is given in
67 <i>fname</i> and should not match any of the user defined
68 function names in the awk script.</p>
69
70 <p style="margin-left:11%; margin-top: 1em">When the user
71 function is called back, argument <i>sp</i> is the stack
72 pointer and <i>a_args</i> holds the number of arguments. The
73 user function is responsible for managing the stack: it
74 should pop all arguments before returning.</p>
75
76 <p style="margin-left:11%; margin-top: 1em">The user
77 function should also generate a return value, which is done
78 by calling libmawk_set_cell() on the stack slot returned by
79 libmawk_stackret. Libmawk_stackret should be called with the
80 modified <i>sp</i> after popping all arguments.</p>
81
82 <p style="margin-left:11%; margin-top: 1em">Argument m is a
83 libmawk context previously returned by libmawk_initialize()
84 or libmawk_initialize_stage3().</p>
85
86 <p style="margin-left:11%; margin-top: 1em">For more
87 information about user function callbacks, especially on
88 stack handling, see manual page example(3libmawk).</p>
89
90 <h2>RETURN VALUE
91 <a name="RETURN VALUE"></a>
92 </h2>
93
94
95 <p style="margin-left:11%; margin-top: 1em">The user
96 function should return the stack pointer after popping all
97 arguments.</p>
98
99 <p style="margin-left:11%; margin-top: 1em">The
100 libmawk_register_function call returns 0 on success.</p>
101
102 <p style="margin-left:11%; margin-top: 1em">Call
103 libmawk_stackret returns a stack pointer to the slot where
104 the user function should store its return value.</p>
105
106 <h2>SEE ALSO
107 <a name="SEE ALSO"></a>
108 </h2>
109
110
111
112 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage</b>(3libmawk),
113 <b>libmawk_initialize</b>(3libmawk),
114 <b>libmawk_set_cell</b>(3libmawk),
115 <b>libmawk_print_cell</b>(3libmawk).</p>
116 <hr>
117 </body>
118 </html>
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:32 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LIBMAWK_RUN_MAIN</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LIBMAWK_RUN_MAIN</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#SEE ALSO">SEE ALSO</a><br>
26
27 <hr>
28
29
30 <h2>NAME
31 <a name="NAME"></a>
32 </h2>
33
34
35
36 <p style="margin-left:11%; margin-top: 1em">libmawk_run_main
37 &minus; run main parts of a script</p>
38
39 <h2>SYNOPSIS
40 <a name="SYNOPSIS"></a>
41 </h2>
42
43
44 <p style="margin-left:11%; margin-top: 1em"><b>#include
45 &lt;libmawk.h&gt;</b></p>
46
47 <p style="margin-left:11%; margin-top: 1em"><b>void
48 libmawk_run_main(mawk_state_t *</b><i>m</i><b>);</b></p>
49
50 <h2>DESCRIPTION
51 <a name="DESCRIPTION"></a>
52 </h2>
53
54
55 <p style="margin-left:11%; margin-top: 1em">The
56 <b>libmawk_run_main</b>() attempts to take and parse the
57 next input record and runs all main parts of the script that
58 matches. If there are multiple full records in the input
59 buffer, the process repeats until the buffer becomes empty
60 or contains a partial record. If there is no full record in
61 the buffer, the call returns with nothing done. The call
62 itself never blocks, but the script may. The input buffer
63 may be filled using the libmawk_append_input() call.</p>
64
65 <p style="margin-left:11%; margin-top: 1em">Argument m is a
66 libmawk context previously returned by libmawk_initialize()
67 or libmawk_initialize_stage3().</p>
68
69 <h2>SEE ALSO
70 <a name="SEE ALSO"></a>
71 </h2>
72
73
74
75 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage</b>(3libmawk),
76 <b>libmawk_initialize</b>(3libmawk),
77 <b>libmawk_append_input</b>(3libmawk),</p>
78 <hr>
79 </body>
80 </html>
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:32 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LIBMAWK_SET_CELL</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LIBMAWK_SET_CELL</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#RETURN VALUE">RETURN VALUE</a><br>
26 <a href="#SEE ALSO">SEE ALSO</a><br>
27
28 <hr>
29
30
31 <h2>NAME
32 <a name="NAME"></a>
33 </h2>
34
35
36
37 <p style="margin-left:11%; margin-top: 1em">libmawk_set_cell
38 &minus; set the value of a mawk cell.</p>
39
40 <h2>SYNOPSIS
41 <a name="SYNOPSIS"></a>
42 </h2>
43
44
45 <p style="margin-left:11%; margin-top: 1em"><b>#include
46 &lt;libmawk.h&gt;</b></p>
47
48 <p style="margin-left:11%; margin-top: 1em"><b>CELL
49 *libmawk_set_cell(mawk_state_t *</b><i>m</i><b>, CELL
50 *</b><i>cell</i><b>, const
51 char</b><i>argtype</i><b>,</b><i>...</i><b>); <br>
52 CELL *libmawk_set_cellp(mawk_state_t *</b><i>m</i><b>, CELL
53 *</b><i>cell</i><b>, const char</b><i>argtype</i><b>, void
54 *</b><i>argp</i><b>);</b></p>
55
56 <h2>DESCRIPTION
57 <a name="DESCRIPTION"></a>
58 </h2>
59
60
61 <p style="margin-left:11%; margin-top: 1em">The
62 <b>libmawk_set_cell</b>() function modifies the value of a
63 mawk cell (variable). Argumetn argtype is a format character
64 that describes the type of the payload (accessed trough
65 vararg).</p>
66
67 <p style="margin-left:11%; margin-top: 1em">The
68 <b>libmawk_set_cellp</b>() function performs the same action
69 but accepts a generic pointer to the payload.</p>
70
71 <p style="margin-left:11%; margin-top: 1em"><b>Format
72 character</b> is one of the followings: <br>
73 &rsquo;d&rsquo; for int payload <br>
74 &rsquo;f&rsquo; for double payload <br>
75 &rsquo;s&rsquo; for (zero terminated) char * payload.</p>
76
77 <p style="margin-top: 1em">Argument m is a libmawk context
78 previously returned by libmawk_initialize() or
79 libmawk_initialize_stage3().</p>
80
81 <h2>RETURN VALUE
82 <a name="RETURN VALUE"></a>
83 </h2>
84
85
86 <p style="margin-left:11%; margin-top: 1em">A pointer to
87 the cell modified.</p>
88
89 <h2>SEE ALSO
90 <a name="SEE ALSO"></a>
91 </h2>
92
93
94
95 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage</b>(3libmawk),
96 <b>libmawk_initialize</b>(3libmawk),
97 <b>libmawk_get_var</b>(3libmawk).</p>
98 <hr>
99 </body>
100 </html>
0 <!-- Creator : groff version 1.22.2 -->
1 <!-- CreationDate: Sat Jun 14 14:27:32 2014 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LIBMAWK_UNINITIALIZE</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LIBMAWK_UNINITIALIZE</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#SEE ALSO">SEE ALSO</a><br>
26
27 <hr>
28
29
30 <h2>NAME
31 <a name="NAME"></a>
32 </h2>
33
34
35
36 <p style="margin-left:11%; margin-top: 1em">libmawk_uninitialize
37 &minus; destroy a libmawk context</p>
38
39 <h2>SYNOPSIS
40 <a name="SYNOPSIS"></a>
41 </h2>
42
43
44 <p style="margin-left:11%; margin-top: 1em"><b>#include
45 &lt;libmawk.h&gt;</b></p>
46
47 <p style="margin-left:11%; margin-top: 1em"><b>void
48 libmawk_uninitialize(mawk_state_t *</b>
49 <i>m</i><b>);</b></p>
50
51 <h2>DESCRIPTION
52 <a name="DESCRIPTION"></a>
53 </h2>
54
55
56 <p style="margin-left:11%; margin-top: 1em">The
57 <b>libmawk_uninitialize</b>() function destroys a context
58 previously created using libmawk_initialize() or
59 libmawk_initialize_stage1() call. It unloads scripts and
60 frees all memory of the context.</p>
61
62 <h2>SEE ALSO
63 <a name="SEE ALSO"></a>
64 </h2>
65
66
67
68 <p style="margin-left:11%; margin-top: 1em"><b>libmawk_initialize_stage</b>(3libmawk),
69 <b>libmawk_initialize</b>(3libmawk),</p>
70 <hr>
71 </body>
72 </html>
0 <!-- Creator : groff version 1.22.3 -->
1 <!-- CreationDate: Sun Nov 11 07:32:01 2018 -->
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
3 "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta name="generator" content="groff -Thtml, see www.gnu.org">
7 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
8 <meta name="Content-Style" content="text/css">
9 <style type="text/css">
10 p { margin-top: 0; margin-bottom: 0; vertical-align: top }
11 pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
12 table { margin-top: 0; margin-bottom: 0; vertical-align: top }
13 h1 { text-align: center }
14 </style>
15 <title>LMAWK</title>
16
17 </head>
18 <body>
19
20 <h1 align="center">LMAWK</h1>
21
22 <a href="#NAME">NAME</a><br>
23 <a href="#SYNOPSIS">SYNOPSIS</a><br>
24 <a href="#DESCRIPTION">DESCRIPTION</a><br>
25 <a href="#OPTIONS">OPTIONS</a><br>
26 <a href="#THE AWK LANGUAGE">THE AWK LANGUAGE</a><br>
27 <a href="#EXAMPLES">EXAMPLES</a><br>
28 <a href="#COMPATIBILITY ISSUES">COMPATIBILITY ISSUES</a><br>
29 <a href="#SEE ALSO">SEE ALSO</a><br>
30 <a href="#BUGS">BUGS</a><br>
31 <a href="#AUTHOR">AUTHOR</a><br>
32
33 <hr>
34
35
36 <h2>NAME
37 <a name="NAME"></a>
38 </h2>
39
40
41 <p style="margin-left:11%; margin-top: 1em">lmawk &minus;
42 pattern scanning and text processing language</p>
43
44 <h2>SYNOPSIS
45 <a name="SYNOPSIS"></a>
46 </h2>
47
48
49 <p style="margin-left:11%; margin-top: 1em"><b>lmawk</b>
50 [&minus;<b>W</b> <i>option</i>] [&minus;<b>F</b>
51 <i>value</i>] [&minus;<b>v</b> <i>var=value</i>]
52 [&minus;&minus;] &rsquo;program text&rsquo; [file ...]
53 <b><br>
54 lmawk</b> [&minus;<b>W</b> <i>option</i>] [&minus;<b>F</b>
55 <i>value</i>] [&minus;<b>v</b> <i>var=value</i>]
56 [&minus;<b>f</b> <i>program-file</i>] [&minus;&minus;] [file
57 ...]</p>
58
59 <h2>DESCRIPTION
60 <a name="DESCRIPTION"></a>
61 </h2>
62
63
64 <p style="margin-left:11%; margin-top: 1em"><b>lmawk</b> is
65 an interpreter for the AWK Programming Language derived from
66 mawk. The AWK language is useful for manipulation of data
67 files, text retrieval and processing, and for prototyping
68 and experimenting with algorithms. <b>lmawk</b> is a <i>new
69 awk</i> meaning it implements the AWK language as defined in
70 Aho, Kernighan and Weinberger, <i>The AWK Programming
71 Language,</i> Addison-Wesley Publishing, 1988. (Hereafter
72 referred to as the AWK book.) <b>mawk</b> conforms to the
73 Posix 1003.2 (draft 11.3) definition of the AWK language
74 which contains a few features not described in the AWK book,
75 and <b>mawk</b> provides a small number of extensions.</p>
76
77 <p style="margin-left:11%; margin-top: 1em">An AWK program
78 is a sequence of <i>pattern {action}</i> pairs and function
79 definitions. Short programs are entered on the command line
80 usually enclosed in &rsquo; &rsquo; to avoid shell
81 interpretation. Longer programs can be read in from a file
82 with the &minus;f option. Data input is read from the list
83 of files on the command line or from standard input when the
84 list is empty. The input is broken into records as
85 determined by the record separator variable, <b>RS</b>.
86 Initially, <b>RS</b> = &quot;\n&quot; and records are
87 synonymous with lines. Each record is compared against each
88 <i>pattern</i> and if it matches, the program text for
89 <i>{action}</i> is executed.</p>
90
91 <h2>OPTIONS
92 <a name="OPTIONS"></a>
93 </h2>
94
95
96 <table width="100%" border="0" rules="none" frame="void"
97 cellspacing="0" cellpadding="0">
98 <tr valign="top" align="left">
99 <td width="11%"></td>
100 <td width="18%">
101
102
103 <p style="margin-top: 1em">&minus;<b>F</b> <i>value</i></p></td>
104 <td width="5%"></td>
105 <td width="66%">
106
107
108 <p style="margin-top: 1em">sets the field separator,
109 <b>FS</b>, to <i>value</i>.</p></td></tr>
110 <tr valign="top" align="left">
111 <td width="11%"></td>
112 <td width="18%">
113
114
115 <p>&minus;<b>f</b> <i>file</i></p></td>
116 <td width="5%"></td>
117 <td width="66%">
118
119
120 <p>Program text is read from <i>file</i> instead of from
121 the command line. Multiple <b>&minus;f</b> options are
122 allowed. As a libmawk extension, if file name starts with
123 plus (&rsquo;+&rsquo;), it is not loaded if the same file
124 has been loaded already by a previous -f or include from any
125 of the scripts already loaded.</p></td></tr>
126 <tr valign="top" align="left">
127 <td width="11%"></td>
128 <td width="18%">
129
130
131 <p>&minus;<b>b</b> <i>file</i></p></td>
132 <td width="5%"></td>
133 <td width="66%">
134
135
136 <p>Program bytecode is read from <i>file</i> . Multiple
137 <b>&minus;b</b> options are allowed. Bytecode can be
138 generated using -Wcompile. Libmawk may refuse to load
139 bytecode generated on a different system if byte order, type
140 sizes or dump version differs.</p></td></tr>
141 <tr valign="top" align="left">
142 <td width="11%"></td>
143 <td width="18%">
144
145
146 <p>&minus;<b>v</b> <i>var=value</i></p></td>
147 <td width="5%"></td>
148 <td width="66%">
149
150
151 <p>assigns <i>value</i> to program variable <i>var</i>.</p></td></tr>
152 <tr valign="top" align="left">
153 <td width="11%"></td>
154 <td width="18%">
155
156
157 <p>&minus;&minus;</p></td>
158 <td width="5%"></td>
159 <td width="66%">
160
161
162 <p>indicates the unambiguous end of options.</p></td></tr>
163 </table>
164
165 <p style="margin-left:11%; margin-top: 1em">The above
166 options will be available with any Posix compatible
167 implementation of AWK, and implementation specific options
168 are prefaced with <b>&minus;W</b>. <b>lmawk</b> provides
169 six:</p>
170
171 <table width="100%" border="0" rules="none" frame="void"
172 cellspacing="0" cellpadding="0">
173 <tr valign="top" align="left">
174 <td width="11%"></td>
175 <td width="21%">
176
177
178 <p style="margin-top: 1em">&minus;<b>W</b> version</p></td>
179 <td width="2%"></td>
180 <td width="66%">
181
182
183 <p style="margin-top: 1em"><b>lmawk</b> writes its version
184 and copyright to stdout and compiled limits to stderr and
185 exits 0.</p></td></tr>
186 <tr valign="top" align="left">
187 <td width="11%"></td>
188 <td width="21%">
189
190
191 <p>&minus;<b>W</b> debug</p></td>
192 <td width="2%"></td>
193 <td width="66%">
194
195
196 <p>include location info in the compiled code; location
197 information is visible in the dump and when debugging
198 libmawk.</p> </td></tr>
199 <tr valign="top" align="left">
200 <td width="11%"></td>
201 <td width="21%">
202
203
204 <p>&minus;<b>W</b> dump</p></td>
205 <td width="2%"></td>
206 <td width="66%">
207
208
209 <p>writes an assembler like listing of the internal
210 representation of the program to stdout and exits 0 (on
211 successful compilation).</p></td></tr>
212 <tr valign="top" align="left">
213 <td width="11%"></td>
214 <td width="21%">
215
216
217 <p>&minus;<b>W</b> dumpsym</p></td>
218 <td width="2%"></td>
219 <td width="66%">
220
221
222 <p>writes a list of global symbols to stdout and exits 0
223 (on successful compilation).</p></td></tr>
224 <tr valign="top" align="left">
225 <td width="11%"></td>
226 <td width="21%">
227
228
229 <p>&minus;<b>W</b> compile</p></td>
230 <td width="2%"></td>
231 <td width="66%">
232
233
234 <p>writes a binary dump of the bytecode to stdout. This
235 bytecode can be loaded using the &minus;<b>b</b> switch.</p></td></tr>
236 <tr valign="top" align="left">
237 <td width="11%"></td>
238 <td width="21%">
239
240
241 <p>&minus;<b>W</b> interactive</p></td>
242 <td width="2%"></td>
243 <td width="66%">
244
245
246 <p>sets unbuffered writes to stdout and line buffered reads
247 from stdin. Records from stdin are lines regardless of the
248 value of <b>RS</b>.</p></td></tr>
249 <tr valign="top" align="left">
250 <td width="11%"></td>
251 <td width="21%">
252
253
254 <p>&minus;<b>W</b> maxmem=<i>num</i></p></td>
255 <td width="2%"></td>
256 <td width="66%">
257
258
259 <p>limit dynamic memory allocation during compilation and
260 execution to <i>num</i> bytes and exit with
261 out-of-the-memory error if more memory is to be allocated.
262 Optional suffixes are k for kilobyte and m for megabyte. 0
263 means unlimited, which is also the default.</p></td></tr>
264 <tr valign="top" align="left">
265 <td width="11%"></td>
266 <td width="21%">
267
268
269 <p>&minus;<b>W</b> exec <i>file</i></p></td>
270 <td width="2%"></td>
271 <td width="66%">
272
273
274 <p>Program text is read from <i>file</i> and this is the
275 last option. Useful on systems that support the <b>#!</b>
276 &quot;magic number&quot; convention for executable
277 scripts.</p> </td></tr>
278 <tr valign="top" align="left">
279 <td width="11%"></td>
280 <td width="21%">
281
282
283 <p>&minus;<b>W</b> sprintf=<i>num</i></p></td>
284 <td width="2%"></td>
285 <td width="66%">
286
287
288 <p>adjusts the size of <b>lmawk&rsquo;s</b> internal
289 sprintf buffer to <i>num</i> bytes. More than rare use of
290 this option indicates <b>lmawk</b> should be recompiled.</p></td></tr>
291 <tr valign="top" align="left">
292 <td width="11%"></td>
293 <td width="21%">
294
295
296 <p>&minus;<b>W</b> posix_space</p></td>
297 <td width="2%"></td>
298 <td width="66%">
299
300
301 <p>forces <b>lmawk</b> not to consider &rsquo;\n&rsquo; to
302 be space.</p></td></tr>
303 </table>
304
305 <p style="margin-left:11%; margin-top: 1em">The short forms
306 <b>&minus;W</b>[vdiesp] are recognized and on some systems
307 <b>&minus;W</b>e is mandatory to avoid command line length
308 limitations.</p>
309
310 <h2>THE AWK LANGUAGE
311 <a name="THE AWK LANGUAGE"></a>
312 </h2>
313
314
315 <p style="margin-left:11%; margin-top: 1em"><b>1. Program
316 structure</b> <br>
317 An AWK program is a sequence of <i>pattern {action}</i>
318 pairs and user function definitions.</p>
319
320 <p style="margin-left:11%; margin-top: 1em">A pattern can
321 be:</p>
322
323 <p style="margin-left:22%;"><b>BEGIN <br>
324 END</b> <br>
325 expression <br>
326 expression , expression</p>
327
328 <p style="margin-left:11%; margin-top: 1em">One, but not
329 both, of <i>pattern {action}</i> can be omitted. If
330 <i>{action}</i> is omitted it is implicitly { print }. If
331 <i>pattern</i> is omitted, then it is implicitly matched.
332 <b>BEGIN</b> and <b>END</b> patterns require an action.</p>
333
334 <p style="margin-left:11%; margin-top: 1em">Statements are
335 terminated by newlines, semi-colons or both. Groups of
336 statements such as actions or loop bodies are blocked via {
337 ... } as in C. The last statement in a block doesn&rsquo;t
338 need a terminator. Blank lines have no meaning; an empty
339 statement is terminated with a semi-colon. Long statements
340 can be continued with a backslash, \. A statement can be
341 broken without a backslash after a comma, left brace,
342 &amp;&amp;, ||, <b>do</b>, <b>else</b>, the right
343 parenthesis of an <b>if</b>, <b>while</b> or <b>for</b>
344 statement, and the right parenthesis of a function
345 definition. A comment starts with # and extends to, but does
346 not include the end of line.</p>
347
348 <p style="margin-left:11%; margin-top: 1em">The following
349 statements control program flow inside blocks.</p>
350
351 <p style="margin-left:22%; margin-top: 1em"><b>if</b> (
352 <i>expr</i> ) <i>statement</i></p>
353
354 <p style="margin-left:22%; margin-top: 1em"><b>if</b> (
355 <i>expr</i> ) <i>statement</i> <b>else</b>
356 <i>statement</i></p>
357
358 <p style="margin-left:22%; margin-top: 1em"><b>while</b> (
359 <i>expr</i> ) <i>statement</i></p>
360
361 <p style="margin-left:22%; margin-top: 1em"><b>do</b>
362 <i>statement</i> <b>while</b> ( <i>expr</i> )</p>
363
364 <p style="margin-left:22%; margin-top: 1em"><b>for</b> (
365 <i>opt_expr</i> ; <i>opt_expr</i> ; <i>opt_expr</i> )
366 <i>statement</i></p>
367
368 <p style="margin-left:22%; margin-top: 1em"><b>for</b> (
369 <i>var</i> <b>in</b> <i>array</i> ) <i>statement</i></p>
370
371
372 <p style="margin-left:22%; margin-top: 1em"><b>continue</b></p>
373
374
375 <p style="margin-left:22%; margin-top: 1em"><b>break</b></p>
376
377 <p style="margin-left:11%; margin-top: 1em"><b>2. Data
378 types, conversion and comparison</b> <br>
379 There are two basic data types, numeric and string. Numeric
380 constants can be integer like &minus;2, decimal like 1.08,
381 or in scientific notation like &minus;1.1e4 or .28E&minus;3.
382 All numbers are represented internally and all computations
383 are done in floating point arithmetic. So for example, the
384 expression 0.2e2 == 20 is true and true is represented as
385 1.0.</p>
386
387 <p style="margin-left:11%; margin-top: 1em">String
388 constants are enclosed in double quotes.</p>
389
390 <p align="center" style="margin-top: 1em">&quot;This is a
391 string with a newline at the end.\n&quot;</p>
392
393 <p style="margin-top: 1em">Strings can be continued across
394 a line by escaping (\) the newline. The following escape
395 sequences are recognized.</p>
396
397 <table width="100%" border="0" rules="none" frame="void"
398 cellspacing="0" cellpadding="0">
399 <tr valign="top" align="left">
400 <td width="8%"></td>
401 <td width="7%">
402 </td>
403 <td width="8%">
404
405
406 <p>\\</p></td>
407 <td width="8%">
408 </td>
409 <td width="69%">
410
411
412 <p>\</p></td></tr>
413 <tr valign="top" align="left">
414 <td width="8%"></td>
415 <td width="7%">
416 </td>
417 <td width="8%">
418
419
420 <p>\&quot;</p></td>
421 <td width="8%">
422 </td>
423 <td width="69%">
424
425
426 <p>&quot;</p></td></tr>
427 <tr valign="top" align="left">
428 <td width="8%"></td>
429 <td width="7%">
430 </td>
431 <td width="8%">
432
433
434 <p>\a</p></td>
435 <td width="8%">
436 </td>
437 <td width="69%">
438
439
440 <p>alert, ascii 7</p></td></tr>
441 <tr valign="top" align="left">
442 <td width="8%"></td>
443 <td width="7%">
444 </td>
445 <td width="8%">
446
447
448 <p>\b</p></td>
449 <td width="8%">
450 </td>
451 <td width="69%">
452
453
454 <p>backspace, ascii 8</p></td></tr>
455 <tr valign="top" align="left">
456 <td width="8%"></td>
457 <td width="7%">
458 </td>
459 <td width="8%">
460
461
462 <p>\t</p></td>
463 <td width="8%">
464 </td>
465 <td width="69%">
466
467
468 <p>tab, ascii 9</p></td></tr>
469 <tr valign="top" align="left">
470 <td width="8%"></td>
471 <td width="7%">
472 </td>
473 <td width="8%">
474
475
476 <p>\n</p></td>
477 <td width="8%">
478 </td>
479 <td width="69%">
480
481
482 <p>newline, ascii 10</p></td></tr>
483 <tr valign="top" align="left">
484 <td width="8%"></td>
485 <td width="7%">
486 </td>
487 <td width="8%">
488
489
490 <p>\v</p></td>
491 <td width="8%">
492 </td>
493 <td width="69%">
494
495
496 <p>vertical tab, ascii 11</p></td></tr>
497 <tr valign="top" align="left">
498 <td width="8%"></td>
499 <td width="7%">
500 </td>
501 <td width="8%">
502
503
504 <p>\f</p></td>
505 <td width="8%">
506 </td>
507 <td width="69%">
508
509
510 <p>formfeed, ascii 12</p></td></tr>
511 <tr valign="top" align="left">
512 <td width="8%"></td>
513 <td width="7%">
514 </td>
515 <td width="8%">
516
517
518 <p>\r</p></td>
519 <td width="8%">
520 </td>
521 <td width="69%">
522
523
524 <p>carriage return, ascii 13</p></td></tr>
525 <tr valign="top" align="left">
526 <td width="8%"></td>
527 <td width="7%">
528 </td>
529 <td width="8%">
530
531
532 <p>\ddd</p></td>
533 <td width="8%">
534 </td>
535 <td width="69%">
536
537
538 <p>1, 2 or 3 octal digits for ascii ddd</p></td></tr>
539 <tr valign="top" align="left">
540 <td width="8%"></td>
541 <td width="7%">
542 </td>
543 <td width="8%">
544
545
546 <p>\xhh</p></td>
547 <td width="8%">
548 </td>
549 <td width="69%">
550
551
552 <p>1 or 2 hex digits for ascii hh</p></td></tr>
553 </table>
554
555 <p style="margin-left:11%; margin-top: 1em">If you escape
556 any other character \c, you get \c, i.e., <b>lmawk</b>
557 ignores the escape.</p>
558
559 <p style="margin-left:11%; margin-top: 1em">There are
560 really three basic data types; the third is <i>number and
561 string</i> which has both a numeric value and a string value
562 at the same time. User defined variables come into existence
563 when first referenced and are initialized to <i>null</i>, a
564 number and string value which has numeric value 0 and string
565 value &quot;&quot;. Non-trivial number and string typed data
566 come from input and are typically stored in fields. (See
567 section 4).</p>
568
569 <p style="margin-left:11%; margin-top: 1em">The type of an
570 expression is determined by its context and automatic type
571 conversion occurs if needed. For example, to evaluate the
572 statements</p>
573
574 <table width="100%" border="0" rules="none" frame="void"
575 cellspacing="0" cellpadding="0">
576 <tr valign="top" align="left">
577 <td width="8%"></td>
578 <td width="92%">
579
580
581 <p>y = x + 2 ; z = x &quot;hello&quot;</p></td></tr>
582 </table>
583
584 <p style="margin-left:11%; margin-top: 1em">The value
585 stored in variable y will be typed numeric. If x is not
586 numeric, the value read from x is converted to numeric
587 before it is added to 2 and stored in y. The value stored in
588 variable z will be typed string, and the value of x will be
589 converted to string if necessary and concatenated with
590 &quot;hello&quot;. (Of course, the value and type stored in
591 x is not changed by any conversions.) A string expression is
592 converted to numeric using its longest numeric prefix as
593 with <i>atof</i>(3). A numeric expression is converted to
594 string by replacing <i>expr</i> with <b>sprintf(CONVFMT</b>,
595 <i>expr</i>), unless <i>expr</i> can be represented on the
596 host machine as an exact integer then it is converted to
597 <b>sprintf</b>(&quot;%d&quot;, <i>expr</i>).
598 <b>Sprintf()</b> is an AWK built-in that duplicates the
599 functionality of <i>sprintf</i>(3), and <b>CONVFMT</b> is a
600 built-in variable used for internal conversion from number
601 to string and initialized to &quot;%.6g&quot;. Explicit type
602 conversions can be forced, <i>expr</i> &quot;&quot; is
603 string and <i>expr</i>+0 is numeric.</p>
604
605 <p style="margin-left:11%; margin-top: 1em">To evaluate,
606 <i>expr</i>1 <b>rel-op</b> <i>expr</i>2, if both operands
607 are numeric or number and string then the comparison is
608 numeric; if both operands are string the comparison is
609 string; if one operand is string, the non-string operand is
610 converted and the comparison is string. The result is
611 numeric, 1 or 0.</p>
612
613 <p style="margin-left:11%; margin-top: 1em">In boolean
614 contexts such as, <b>if</b> ( <i>expr</i> )
615 <i>statement</i>, a string expression evaluates true if and
616 only if it is not the empty string &quot;&quot;; numeric
617 values if and only if not numerically zero.</p>
618
619 <p style="margin-left:11%; margin-top: 1em"><b>3. Regular
620 expressions</b> <br>
621 In the AWK language, records, fields and strings are often
622 tested for matching a <i>regular expression</i>. Regular
623 expressions are enclosed in slashes, and</p>
624
625 <table width="100%" border="0" rules="none" frame="void"
626 cellspacing="0" cellpadding="0">
627 <tr valign="top" align="left">
628 <td width="8%"></td>
629 <td width="92%">
630
631
632 <p><i>expr</i> ~ /<i>r</i>/</p></td></tr>
633 </table>
634
635 <p style="margin-left:11%; margin-top: 1em">is an AWK
636 expression that evaluates to 1 if <i>expr</i>
637 &quot;matches&quot; <i>r</i>, which means a substring of
638 <i>expr</i> is in the set of strings defined by <i>r</i>.
639 With no match the expression evaluates to 0; replacing ~
640 with the &quot;not match&quot; operator, !~ , reverses the
641 meaning. As pattern-action pairs,</p>
642
643 <table width="100%" border="0" rules="none" frame="void"
644 cellspacing="0" cellpadding="0">
645 <tr valign="top" align="left">
646 <td width="8%"></td>
647 <td width="92%">
648
649
650 <p>/<i>r</i>/ { <i>action</i> } and <b>$0</b> ~ /<i>r</i>/
651 { <i>action</i> }</p></td></tr>
652 </table>
653
654 <p style="margin-left:11%; margin-top: 1em">are the same,
655 and for each input record that matches <i>r</i>,
656 <i>action</i> is executed. In fact, /<i>r</i>/ is an AWK
657 expression that is equivalent to (<b>$0</b> ~ /<i>r</i>/)
658 anywhere except when on the right side of a match operator
659 or passed as an argument to a built-in function that expects
660 a regular expression argument.</p>
661
662 <p style="margin-left:11%; margin-top: 1em">AWK uses
663 extended regular expressions as with <i>egrep</i>(1). The
664 regular expression metacharacters, i.e., those with special
665 meaning in regular expressions are</p>
666
667 <table width="100%" border="0" rules="none" frame="void"
668 cellspacing="0" cellpadding="0">
669 <tr valign="top" align="left">
670 <td width="8%"></td>
671 <td width="92%">
672
673
674 <p>&nbsp;^ $ . [ ] | ( ) * + ?</p></td></tr>
675 </table>
676
677 <p style="margin-left:11%; margin-top: 1em">Regular
678 expressions are built up from characters as follows:</p>
679
680 <table width="100%" border="0" rules="none" frame="void"
681 cellspacing="0" cellpadding="0">
682 <tr valign="top" align="left">
683 <td width="22%"></td>
684 <td width="18%">
685
686
687 <p style="margin-top: 1em"><i>c</i></p></td>
688 <td width="2%"></td>
689 <td width="58%">
690
691
692 <p style="margin-top: 1em">matches any non-metacharacter
693 <i>c</i>.</p> </td></tr>
694 <tr valign="top" align="left">
695 <td width="22%"></td>
696 <td width="18%">
697
698
699 <p>\<i>c</i></p></td>
700 <td width="2%"></td>
701 <td width="58%">
702
703
704 <p>matches a character defined by the same escape sequences
705 used in string constants or the literal character <i>c</i>
706 if \<i>c</i> is not an escape sequence.</p></td></tr>
707 <tr valign="top" align="left">
708 <td width="22%"></td>
709 <td width="18%">
710
711
712 <p>.</p></td>
713 <td width="2%"></td>
714 <td width="58%">
715
716
717 <p>matches any character (including newline).</p></td></tr>
718 <tr valign="top" align="left">
719 <td width="22%"></td>
720 <td width="18%">
721
722
723 <p>^</p></td>
724 <td width="2%"></td>
725 <td width="58%">
726
727
728 <p>matches the front of a string.</p></td></tr>
729 <tr valign="top" align="left">
730 <td width="22%"></td>
731 <td width="18%">
732
733
734 <p>$</p></td>
735 <td width="2%"></td>
736 <td width="58%">
737
738
739 <p>matches the back of a string.</p></td></tr>
740 <tr valign="top" align="left">
741 <td width="22%"></td>
742 <td width="18%">
743
744
745 <p>[c1c2c3...]</p></td>
746 <td width="2%"></td>
747 <td width="58%">
748
749
750 <p>matches any character in the class c1c2c3... . An
751 interval of characters is denoted c1&minus;c2 inside a class
752 [...].</p> </td></tr>
753 <tr valign="top" align="left">
754 <td width="22%"></td>
755 <td width="18%">
756
757
758 <p>[^c1c2c3...]</p></td>
759 <td width="2%"></td>
760 <td width="58%">
761
762
763 <p>matches any character not in the class c1c2c3...</p></td></tr>
764 </table>
765
766 <p style="margin-left:11%; margin-top: 1em">Regular
767 expressions are built up from other regular expressions as
768 follows:</p>
769
770 <table width="100%" border="0" rules="none" frame="void"
771 cellspacing="0" cellpadding="0">
772 <tr valign="top" align="left">
773 <td width="22%"></td>
774 <td width="10%">
775
776
777 <p style="margin-top: 1em"><i>r</i>1<i>r</i>2</p></td>
778 <td width="10%"></td>
779 <td width="58%">
780
781
782 <p style="margin-top: 1em">matches <i>r</i>1 followed
783 immediately by <i>r</i>2 (concatenation).</p></td></tr>
784 <tr valign="top" align="left">
785 <td width="22%"></td>
786 <td width="10%">
787
788
789 <p><i>r</i>1 | <i>r</i>2</p></td>
790 <td width="10%"></td>
791 <td width="58%">
792
793
794 <p>matches <i>r</i>1 or <i>r</i>2 (alternation).</p></td></tr>
795 <tr valign="top" align="left">
796 <td width="22%"></td>
797 <td width="10%">
798
799
800 <p><i>r</i>*</p></td>
801 <td width="10%"></td>
802 <td width="58%">
803
804
805 <p>matches <i>r</i> repeated zero or more times.</p></td></tr>
806 <tr valign="top" align="left">
807 <td width="22%"></td>
808 <td width="10%">
809
810
811 <p><i>r</i>+</p></td>
812 <td width="10%"></td>
813 <td width="58%">
814
815
816 <p>matches <i>r</i> repeated one or more times.</p></td></tr>
817 <tr valign="top" align="left">
818 <td width="22%"></td>
819 <td width="10%">
820
821
822 <p><i>r</i>?</p></td>
823 <td width="10%"></td>
824 <td width="58%">
825
826
827 <p>matches <i>r</i> zero or once.</p></td></tr>
828 <tr valign="top" align="left">
829 <td width="22%"></td>
830 <td width="10%">
831
832
833 <p>(<i>r</i>)</p></td>
834 <td width="10%"></td>
835 <td width="58%">
836
837
838 <p>matches <i>r</i>, providing grouping.</p></td></tr>
839 </table>
840
841 <p style="margin-left:11%; margin-top: 1em">The increasing
842 precedence of operators is alternation, concatenation and
843 unary (*, + or ?).</p>
844
845 <p style="margin-left:11%; margin-top: 1em">For
846 example,</p>
847
848
849 <p style="margin-left:11%; margin-top: 1em">/^[_a&minus;zA-Z][_a&minus;zA&minus;Z0&minus;9]*$/
850 and</p>
851
852 <table width="100%" border="0" rules="none" frame="void"
853 cellspacing="0" cellpadding="0">
854 <tr valign="top" align="left">
855 <td width="8%"></td>
856 <td width="92%">
857
858
859
860 <p>/^[&minus;+]?([0&minus;9]+\.?|\.[0&minus;9])[0&minus;9]*([eE][&minus;+]?[0&minus;9]+)?$/</p> </td></tr>
861 </table>
862
863 <p style="margin-left:11%; margin-top: 1em">are matched by
864 AWK identifiers and AWK numeric constants respectively. Note
865 that . has to be escaped to be recognized as a decimal
866 point, and that metacharacters are not special inside
867 character classes.</p>
868
869 <p style="margin-left:11%; margin-top: 1em">Any expression
870 can be used on the right hand side of the ~ or !~ operators
871 or passed to a built-in that expects a regular expression.
872 If needed, it is converted to string, and then interpreted
873 as a regular expression. For example,</p>
874
875 <table width="100%" border="0" rules="none" frame="void"
876 cellspacing="0" cellpadding="0">
877 <tr valign="top" align="left">
878 <td width="8%"></td>
879 <td width="92%">
880
881
882 <p>BEGIN { identifier =
883 &quot;[_a&minus;zA&minus;Z][_a&minus;zA&minus;Z0&minus;9]*&quot;
884 }</p> </td></tr>
885 <tr valign="top" align="left">
886 <td width="8%"></td>
887 <td width="92%">
888
889
890 <p>$0 ~ &quot;^&quot; identifier</p></td></tr>
891 </table>
892
893 <p style="margin-left:11%; margin-top: 1em">prints all
894 lines that start with an AWK identifier.</p>
895
896 <p style="margin-left:11%; margin-top: 1em"><b>lmawk</b>
897 recognizes the empty regular expression, //, which matches
898 the empty string and hence is matched by any string at the
899 front, back and between every character. For example,</p>
900
901 <table width="100%" border="0" rules="none" frame="void"
902 cellspacing="0" cellpadding="0">
903 <tr valign="top" align="left">
904 <td width="8%"></td>
905 <td width="92%">
906
907
908 <p>echo abc | lmawk { gsub(//, &quot;X&quot;) ; print }</p></td></tr>
909 <tr valign="top" align="left">
910 <td width="8%"></td>
911 <td width="92%">
912
913
914 <p>XaXbXcX</p></td></tr>
915 </table>
916
917 <p style="margin-left:11%; margin-top: 1em"><b>4. Records
918 and fields</b> <br>
919 Records are read in one at a time, and stored in the
920 <i>field</i> variable <b>$0</b>. The record is split into
921 <i>fields</i> which are stored in <b>$1</b>, <b>$2</b>, ...,
922 <b>$NF</b>. The built-in variable <b>NF</b> is set to the
923 number of fields, and <b>NR</b> and <b>FNR</b> are
924 incremented by 1. Fields above <b>$NF</b> are set to
925 &quot;&quot;.</p>
926
927 <p style="margin-left:11%; margin-top: 1em">Assignment to
928 <b>$0</b> causes the fields and <b>NF</b> to be recomputed.
929 Assignment to <b>NF</b> or to a field causes <b>$0</b> to be
930 reconstructed by concatenating the <b>$i&rsquo;s</b>
931 separated by <b>OFS</b>. Assignment to a field with index
932 greater than <b>NF</b>, increases <b>NF</b> and causes
933 <b>$0</b> to be reconstructed.</p>
934
935 <p style="margin-left:11%; margin-top: 1em">Data input
936 stored in fields is string, unless the entire field has
937 numeric form and then the type is number and string. For
938 example,</p>
939
940 <table width="100%" border="0" rules="none" frame="void"
941 cellspacing="0" cellpadding="0">
942 <tr valign="top" align="left">
943 <td width="8%"></td>
944 <td width="92%">
945
946
947 <p>echo 24 24E |</p></td></tr>
948 <tr valign="top" align="left">
949 <td width="8%"></td>
950 <td width="92%">
951
952
953 <p>lmawk &rsquo;{ print($1&gt;100, $1&gt;&quot;100&quot;,
954 $2&gt;100, $2&gt;&quot;100&quot;) }&rsquo;</p></td></tr>
955 <tr valign="top" align="left">
956 <td width="8%"></td>
957 <td width="92%">
958
959
960 <p>0 1 1 1</p></td></tr>
961 </table>
962
963 <p style="margin-left:11%; margin-top: 1em"><b>$0</b> and
964 <b>$2</b> are string and <b>$1</b> is number and string. The
965 first comparison is numeric, the second is string, the third
966 is string (100 is converted to &quot;100&quot;), and the
967 last is string.</p>
968
969 <p style="margin-left:11%; margin-top: 1em"><b>5.
970 Expressions and operators</b> <br>
971 The expression syntax is similar to C. Primary expressions
972 are numeric constants, string constants, variables, fields,
973 arrays and function calls. The identifier for a variable,
974 array or function can be a sequence of letters, digits and
975 underscores, that does not start with a digit. Variables are
976 not declared; they exist when first referenced and are
977 initialized to <i>null</i>.</p>
978
979 <p style="margin-left:11%; margin-top: 1em">New expressions
980 are composed with the following operators in order of
981 increasing precedence.</p>
982
983 <table width="100%" border="0" rules="none" frame="void"
984 cellspacing="0" cellpadding="0">
985 <tr valign="top" align="left">
986 <td width="22%"></td>
987 <td width="-14%"></td>
988 <td width="7%"></td>
989 <td width="8%">
990
991
992 <p><i>assignment</i></p></td>
993 <td width="8%"></td>
994 <td width="7%"></td>
995 <td width="62%">
996 </td></tr>
997 <tr valign="top" align="left">
998 <td width="22%"></td>
999 <td width="-14%"></td>
1000 <td width="7%"></td>
1001 <td width="8%"></td>
1002 <td width="8%"></td>
1003 <td width="7%"></td>
1004 <td width="62%">
1005
1006
1007 <p>= += &minus;= *= /= %= ^=</p></td></tr>
1008 <tr valign="top" align="left">
1009 <td width="22%"></td>
1010 <td width="-14%"></td>
1011 <td width="7%"></td>
1012 <td width="8%">
1013
1014
1015 <p><i>conditional</i></p></td>
1016 <td width="8%"></td>
1017 <td width="7%"></td>
1018 <td width="62%">
1019 </td></tr>
1020 <tr valign="top" align="left">
1021 <td width="22%"></td>
1022 <td width="-14%"></td>
1023 <td width="7%"></td>
1024 <td width="8%"></td>
1025 <td width="8%"></td>
1026 <td width="7%"></td>
1027 <td width="62%">
1028
1029
1030 <p>? :</p></td></tr>
1031 <tr valign="top" align="left">
1032 <td width="22%"></td>
1033 <td width="-14%"></td>
1034 <td width="7%"></td>
1035 <td width="8%">
1036
1037
1038 <p><i>logical or</i></p></td>
1039 <td width="8%"></td>
1040 <td width="7%"></td>
1041 <td width="62%">
1042 </td></tr>
1043 <tr valign="top" align="left">
1044 <td width="22%"></td>
1045 <td width="-14%"></td>
1046 <td width="7%"></td>
1047 <td width="8%"></td>
1048 <td width="8%"></td>
1049 <td width="7%"></td>
1050 <td width="62%">
1051
1052
1053 <p>||</p></td></tr>
1054 <tr valign="top" align="left">
1055 <td width="22%"></td>
1056 <td width="-14%"></td>
1057 <td width="7%"></td>
1058 <td width="8%">
1059
1060
1061 <p><i>logical and</i></p></td>
1062 <td width="8%"></td>
1063 <td width="7%"></td>
1064 <td width="62%">
1065 </td></tr>
1066 <tr valign="top" align="left">
1067 <td width="22%"></td>
1068 <td width="-14%"></td>
1069 <td width="7%"></td>
1070 <td width="8%"></td>
1071 <td width="8%"></td>
1072 <td width="7%"></td>
1073 <td width="62%">
1074
1075
1076 <p>&amp;&amp;</p></td></tr>
1077 <tr valign="top" align="left">
1078 <td width="22%"></td>
1079 <td width="-14%"></td>
1080 <td width="7%"></td>
1081 <td width="8%">
1082
1083
1084 <p><i>array membership</i></p></td>
1085 <td width="8%"></td>
1086 <td width="7%"></td>
1087 <td width="62%">
1088
1089
1090 <p><b>in</b></p></td></tr>
1091 <tr valign="top" align="left">
1092 <td width="22%"></td>
1093 <td width="-14%"></td>
1094 <td width="7%"></td>
1095 <td width="8%">
1096
1097
1098 <p><i>matching</i></p></td>
1099 <td width="8%"></td>
1100 <td width="7%">
1101 </td>
1102 <td width="62%">
1103
1104
1105 <p>~ !~</p></td></tr>
1106 <tr valign="top" align="left">
1107 <td width="22%"></td>
1108 <td width="-14%"></td>
1109 <td width="7%"></td>
1110 <td width="8%">
1111
1112
1113 <p><i>relational</i></p></td>
1114 <td width="8%"></td>
1115 <td width="7%"></td>
1116 <td width="62%">
1117 </td></tr>
1118 <tr valign="top" align="left">
1119 <td width="22%"></td>
1120 <td width="-14%"></td>
1121 <td width="7%"></td>
1122 <td width="8%"></td>
1123 <td width="8%"></td>
1124 <td width="7%"></td>
1125 <td width="62%">
1126
1127
1128 <p>&lt; &gt; &lt;= &gt;= == !=</p></td></tr>
1129 <tr valign="top" align="left">
1130 <td width="22%"></td>
1131 <td width="-14%"></td>
1132 <td width="7%"></td>
1133 <td width="8%">
1134
1135
1136 <p><i>concatenation</i></p></td>
1137 <td width="8%"></td>
1138 <td width="7%"></td>
1139 <td width="62%">
1140 </td></tr>
1141 <tr valign="top" align="left">
1142 <td width="22%"></td>
1143 <td width="-14%"></td>
1144 <td width="7%"></td>
1145 <td width="8%"></td>
1146 <td width="8%"></td>
1147 <td width="7%"></td>
1148 <td width="62%">
1149
1150
1151 <p>(no explicit operator)</p></td></tr>
1152 <tr valign="top" align="left">
1153 <td width="22%"></td>
1154 <td width="-14%"></td>
1155 <td width="7%"></td>
1156 <td width="8%">
1157
1158
1159 <p><i>add ops</i></p></td>
1160 <td width="8%"></td>
1161 <td width="7%">
1162 </td>
1163 <td width="62%">
1164 </td></tr>
1165 <tr valign="top" align="left">
1166 <td width="22%"></td>
1167 <td width="-14%"></td>
1168 <td width="7%"></td>
1169 <td width="8%"></td>
1170 <td width="8%"></td>
1171 <td width="7%"></td>
1172 <td width="62%">
1173
1174
1175 <p>+ &minus;</p></td></tr>
1176 <tr valign="top" align="left">
1177 <td width="22%"></td>
1178 <td width="-14%"></td>
1179 <td width="7%"></td>
1180 <td width="8%">
1181
1182
1183 <p><i>mul ops</i></p></td>
1184 <td width="8%"></td>
1185 <td width="7%">
1186 </td>
1187 <td width="62%">
1188 </td></tr>
1189 <tr valign="top" align="left">
1190 <td width="22%"></td>
1191 <td width="-14%"></td>
1192 <td width="7%"></td>
1193 <td width="8%"></td>
1194 <td width="8%"></td>
1195 <td width="7%"></td>
1196 <td width="62%">
1197
1198
1199 <p>* / %</p></td></tr>
1200 <tr valign="top" align="left">
1201 <td width="22%"></td>
1202 <td width="-14%"></td>
1203 <td width="7%"></td>
1204 <td width="8%">
1205
1206
1207 <p><i>unary</i></p></td>
1208 <td width="8%"></td>
1209 <td width="7%">
1210 </td>
1211 <td width="62%">
1212 </td></tr>
1213 <tr valign="top" align="left">
1214 <td width="22%"></td>
1215 <td width="-14%"></td>
1216 <td width="7%"></td>
1217 <td width="8%"></td>
1218 <td width="8%"></td>
1219 <td width="7%"></td>
1220 <td width="62%">
1221
1222
1223 <p>+ &minus;</p></td></tr>
1224 <tr valign="top" align="left">
1225 <td width="22%"></td>
1226 <td width="-14%"></td>
1227 <td width="7%"></td>
1228 <td width="8%">
1229
1230
1231 <p><i>logical not</i></p></td>
1232 <td width="8%"></td>
1233 <td width="7%"></td>
1234 <td width="62%">
1235 </td></tr>
1236 <tr valign="top" align="left">
1237 <td width="22%"></td>
1238 <td width="-14%"></td>
1239 <td width="7%"></td>
1240 <td width="8%"></td>
1241 <td width="8%"></td>
1242 <td width="7%"></td>
1243 <td width="62%">
1244
1245
1246 <p>!</p></td></tr>
1247 <tr valign="top" align="left">
1248 <td width="22%"></td>
1249 <td width="-14%"></td>
1250 <td width="7%"></td>
1251 <td width="8%">
1252
1253
1254 <p><i>exponentiation</i></p></td>
1255 <td width="8%"></td>
1256 <td width="7%"></td>
1257 <td width="62%">
1258 </td></tr>
1259 <tr valign="top" align="left">
1260 <td width="22%"></td>
1261 <td width="-14%"></td>
1262 <td width="7%"></td>
1263 <td width="8%"></td>
1264 <td width="8%"></td>
1265 <td width="7%"></td>
1266 <td width="62%">
1267
1268
1269 <p>^</p></td></tr>
1270 <tr valign="top" align="left">
1271 <td width="22%"></td>
1272 <td width="-14%"></td>
1273 <td width="7%"></td>
1274 <td width="8%">
1275
1276
1277 <p><i>inc and dec</i></p></td>
1278 <td width="8%"></td>
1279 <td width="7%"></td>
1280 <td width="62%">
1281 </td></tr>
1282 <tr valign="top" align="left">
1283 <td width="22%"></td>
1284 <td width="-14%"></td>
1285 <td width="7%"></td>
1286 <td width="8%"></td>
1287 <td width="8%"></td>
1288 <td width="7%"></td>
1289 <td width="62%">
1290
1291
1292 <p>++ &minus;&minus; (both post and pre)</p></td></tr>
1293 <tr valign="top" align="left">
1294 <td width="22%"></td>
1295 <td width="-14%"></td>
1296 <td width="7%"></td>
1297 <td width="8%">
1298
1299
1300 <p><i>field</i></p></td>
1301 <td width="8%"></td>
1302 <td width="7%">
1303 </td>
1304 <td width="62%">
1305 </td></tr>
1306 <tr valign="top" align="left">
1307 <td width="22%"></td>
1308 <td width="-14%"></td>
1309 <td width="7%"></td>
1310 <td width="8%"></td>
1311 <td width="8%"></td>
1312 <td width="7%"></td>
1313 <td width="62%">
1314
1315
1316 <p>$</p></td></tr>
1317 </table>
1318
1319 <p style="margin-left:11%; margin-top: 1em">Assignment,
1320 conditional and exponentiation associate right to left; the
1321 other operators associate left to right. Any expression can
1322 be parenthesized.</p>
1323
1324 <p style="margin-left:11%; margin-top: 1em"><b>6.
1325 Arrays</b> <br>
1326 Awk provides one-dimensional arrays. Array elements are
1327 expressed as <i>array</i>[<i>expr</i>]. <i>Expr</i> is
1328 internally converted to string type, so, for example, A[1]
1329 and A[&quot;1&quot;] are the same element and the actual
1330 index is &quot;1&quot;. Arrays indexed by strings are called
1331 associative arrays. Initially an array is empty; elements
1332 exist when first accessed. An expression, <i>expr</i>
1333 <b>in</b> <i>array</i> evaluates to 1 if
1334 <i>array</i>[<i>expr</i>] exists, else to 0.</p>
1335
1336 <p style="margin-left:11%; margin-top: 1em">There is a form
1337 of the <b>for</b> statement that loops over each index of an
1338 array.</p>
1339
1340 <table width="100%" border="0" rules="none" frame="void"
1341 cellspacing="0" cellpadding="0">
1342 <tr valign="top" align="left">
1343 <td width="8%"></td>
1344 <td width="92%">
1345
1346
1347 <p><b>for</b> ( <i>var</i> <b>in</b> <i>array</i> )
1348 <i>statement</i></p> </td></tr>
1349 </table>
1350
1351 <p style="margin-left:11%; margin-top: 1em">sets <i>var</i>
1352 to each index of <i>array</i> and executes <i>statement</i>.
1353 The order that <i>var</i> transverses the indices of
1354 <i>array</i> is not defined.</p>
1355
1356 <p style="margin-left:11%; margin-top: 1em">The statement,
1357 <b>delete</b> <i>array</i>[<i>expr</i>], causes
1358 <i>array</i>[<i>expr</i>] not to exist. <b>lmawk</b>
1359 supports an extension, <b>delete</b> <i>array</i>, which
1360 deletes all elements of <i>array</i>.</p>
1361
1362
1363 <p style="margin-left:11%; margin-top: 1em">Multidimensional
1364 arrays are synthesized with concatenation using the built-in
1365 variable <b>SUBSEP</b>.
1366 <i>array</i>[<i>expr</i>1,<i>expr</i>2] is equivalent to
1367 <i>array</i>[<i>expr</i>1 <b>SUBSEP</b> <i>expr</i>2].
1368 Testing for a multidimensional element uses a parenthesized
1369 index, such as</p>
1370
1371 <table width="100%" border="0" rules="none" frame="void"
1372 cellspacing="0" cellpadding="0">
1373 <tr valign="top" align="left">
1374 <td width="8%"></td>
1375 <td width="92%">
1376
1377
1378 <p>if ( (i, j) in A ) print A[i, j]</p></td></tr>
1379 </table>
1380
1381 <p style="margin-left:11%; margin-top: 1em"><b>7.
1382 Builtin-variables</b> <br>
1383 The following variables are built-in and initialized before
1384 program execution.</p>
1385
1386 <table width="100%" border="0" rules="none" frame="void"
1387 cellspacing="0" cellpadding="0">
1388 <tr valign="top" align="left">
1389 <td width="22%"></td>
1390 <td width="12%">
1391
1392
1393 <p style="margin-top: 1em"><b>ARGC</b></p></td>
1394 <td width="3%"></td>
1395 <td width="63%">
1396
1397
1398 <p style="margin-top: 1em">number of command line
1399 arguments.</p> </td></tr>
1400 <tr valign="top" align="left">
1401 <td width="22%"></td>
1402 <td width="12%">
1403
1404
1405 <p><b>ARGV</b></p></td>
1406 <td width="3%"></td>
1407 <td width="63%">
1408
1409
1410 <p>array of command line arguments, 0..ARGC-1.</p></td></tr>
1411 <tr valign="top" align="left">
1412 <td width="22%"></td>
1413 <td width="12%">
1414
1415
1416 <p><b>CONVFMT</b></p></td>
1417 <td width="3%"></td>
1418 <td width="63%">
1419
1420
1421 <p>format for internal conversion of numbers to string,
1422 initially = &quot;%.6g&quot;.</p></td></tr>
1423 <tr valign="top" align="left">
1424 <td width="22%"></td>
1425 <td width="12%">
1426
1427
1428 <p><b>ENVIRON</b></p></td>
1429 <td width="3%"></td>
1430 <td width="63%">
1431
1432
1433 <p>array indexed by environment variables. An environment
1434 string, <i>var=value</i> is stored as
1435 <b>ENVIRON</b>[<i>var</i>] = <i>value</i>.</p></td></tr>
1436 <tr valign="top" align="left">
1437 <td width="22%"></td>
1438 <td width="12%">
1439
1440
1441 <p><b>FILENAME</b></p></td>
1442 <td width="3%"></td>
1443 <td width="63%">
1444
1445
1446 <p>name of the current input file.</p></td></tr>
1447 <tr valign="top" align="left">
1448 <td width="22%"></td>
1449 <td width="12%">
1450
1451
1452 <p><b>FNR</b></p></td>
1453 <td width="3%"></td>
1454 <td width="63%">
1455
1456
1457 <p>current record number in <b>FILENAME</b>.</p></td></tr>
1458 <tr valign="top" align="left">
1459 <td width="22%"></td>
1460 <td width="12%">
1461
1462
1463 <p><b>FS</b></p></td>
1464 <td width="3%"></td>
1465 <td width="63%">
1466
1467
1468 <p>splits records into fields as a regular expression.</p></td></tr>
1469 <tr valign="top" align="left">
1470 <td width="22%"></td>
1471 <td width="12%">
1472
1473
1474 <p><b>NF</b></p></td>
1475 <td width="3%"></td>
1476 <td width="63%">
1477
1478
1479 <p>number of fields in the current record.</p></td></tr>
1480 <tr valign="top" align="left">
1481 <td width="22%"></td>
1482 <td width="12%">
1483
1484
1485 <p><b>NR</b></p></td>
1486 <td width="3%"></td>
1487 <td width="63%">
1488
1489
1490 <p>current record number in the total input stream.</p></td></tr>
1491 <tr valign="top" align="left">
1492 <td width="22%"></td>
1493 <td width="12%">
1494
1495
1496 <p><b>OFMT</b></p></td>
1497 <td width="3%"></td>
1498 <td width="63%">
1499
1500
1501 <p>format for printing numbers; initially =
1502 &quot;%.6g&quot;.</p> </td></tr>
1503 <tr valign="top" align="left">
1504 <td width="22%"></td>
1505 <td width="12%">
1506
1507
1508 <p><b>OFS</b></p></td>
1509 <td width="3%"></td>
1510 <td width="63%">
1511
1512
1513 <p>inserted between fields on output, initially = &quot;
1514 &quot;.</p> </td></tr>
1515 <tr valign="top" align="left">
1516 <td width="22%"></td>
1517 <td width="12%">
1518
1519
1520 <p><b>ORS</b></p></td>
1521 <td width="3%"></td>
1522 <td width="63%">
1523
1524
1525 <p>terminates each record on output, initially =
1526 &quot;\n&quot;.</p> </td></tr>
1527 <tr valign="top" align="left">
1528 <td width="22%"></td>
1529 <td width="12%">
1530
1531
1532 <p><b>RLENGTH</b></p></td>
1533 <td width="3%"></td>
1534 <td width="63%">
1535
1536
1537 <p>length set by the last call to the built-in function,
1538 <b>match()</b>.</p> </td></tr>
1539 <tr valign="top" align="left">
1540 <td width="22%"></td>
1541 <td width="12%">
1542
1543
1544 <p><b>RS</b></p></td>
1545 <td width="3%"></td>
1546 <td width="63%">
1547
1548
1549 <p>input record separator, initially = &quot;\n&quot;.</p></td></tr>
1550 <tr valign="top" align="left">
1551 <td width="22%"></td>
1552 <td width="12%">
1553
1554
1555 <p><b>RSTART</b></p></td>
1556 <td width="3%"></td>
1557 <td width="63%">
1558
1559
1560 <p>index set by the last call to <b>match()</b>.</p></td></tr>
1561 <tr valign="top" align="left">
1562 <td width="22%"></td>
1563 <td width="12%">
1564
1565
1566 <p><b>SUBSEP</b></p></td>
1567 <td width="3%"></td>
1568 <td width="63%">
1569
1570
1571 <p>used to build multiple array subscripts, initially =
1572 &quot;\034&quot;.</p> </td></tr>
1573 <tr valign="top" align="left">
1574 <td width="22%"></td>
1575 <td width="12%">
1576
1577
1578 <p><b>ERRNO</b></p></td>
1579 <td width="3%"></td>
1580 <td width="63%">
1581
1582
1583 <p>misc built-in functions (libmawk extensions) use this
1584 variable to rerport error. All extension calls will set this
1585 variable before returning, therefor ERRNO holds the result
1586 of the last call. An empty string value means no error.
1587 Error messages are formatted in a way that the first word is
1588 an unique integer, followed by a human readable error
1589 message from the second word. int(ERRNO) can be used to
1590 acquire the error code, which then can be used as a
1591 secondary output from the extension function. For example,
1592 an awk program can use valueof() to determine if a global
1593 symbol exists and is a function or a variable or anything
1594 else.</p> </td></tr>
1595 <tr valign="top" align="left">
1596 <td width="22%"></td>
1597 <td width="12%">
1598
1599
1600 <p><b>LIBPATH</b></p></td>
1601 <td width="3%"></td>
1602 <td width="63%">
1603
1604
1605 <p>is a semicolon separated list of search paths. When
1606 loading an awk script by file name (-f command line argument
1607 or include from another awk script) these paths are inserted
1608 before the file name, in order, one by one, until the first
1609 path that allows opening the file. An empty path is
1610 equivalent to the current working directory. LIBPATH can be
1611 modified from the command line using -v, as arguments are
1612 scanned before loading the scripts. Setting LIBPATH to empty
1613 string results in the original behaviour of mawk. LIBPATH is
1614 ignored for script file names starting with slash
1615 (&rsquo;/&rsquo;) as those are assumed to be absolute
1616 paths.</p> </td></tr>
1617 </table>
1618
1619 <p style="margin-left:11%; margin-top: 1em"><b>8. Built-in
1620 functions</b> <br>
1621 String functions</p>
1622
1623 <p style="margin-left:22%;">gsub(<i>r,s,t</i>)
1624 gsub(<i>r,s</i>)</p>
1625
1626 <p style="margin-left:32%;">Global substitution, every
1627 match of regular expression <i>r</i> in variable <i>t</i> is
1628 replaced by string <i>s</i>. The number of replacements is
1629 returned. If <i>t</i> is omitted, <b>$0</b> is used. An
1630 &amp; in the replacement string <i>s</i> is replaced by the
1631 matched substring of <i>t</i>. \&amp; and \\ put literal
1632 &amp; and \, respectively, in the replacement string.</p>
1633
1634 <p style="margin-left:22%;">index(<i>s,t</i>)</p>
1635
1636 <p style="margin-left:32%;">If <i>t</i> is a substring of
1637 <i>s</i>, then the position where <i>t</i> starts is
1638 returned, else 0 is returned. The first character of
1639 <i>s</i> is in position 1.</p>
1640
1641 <p style="margin-left:22%;">length(<i>s</i>)</p>
1642
1643 <p style="margin-left:32%;">Returns the length of string
1644 <i>s</i>.</p>
1645
1646 <p style="margin-left:22%;">match(<i>s,r</i>)</p>
1647
1648 <p style="margin-left:32%;">Returns the index of the first
1649 longest match of regular expression <i>r</i> in string
1650 <i>s</i>. Returns 0 if no match. As a side effect,
1651 <b>RSTART</b> is set to the return value. <b>RLENGTH</b> is
1652 set to the length of the match or &minus;1 if no match. If
1653 the empty string is matched, <b>RLENGTH</b> is set to 0, and
1654 1 is returned if the match is at the front, and
1655 length(<i>s</i>)+1 is returned if the match is at the
1656 back.</p>
1657
1658 <p style="margin-left:22%;">split(<i>s,A,r</i>)
1659 split(<i>s,A</i>)</p>
1660
1661 <p style="margin-left:32%;">String <i>s</i> is split into
1662 fields by regular expression <i>r</i> and the fields are
1663 loaded into array <i>A</i>. The number of fields is
1664 returned. See section 11 below for more detail. If <i>r</i>
1665 is omitted, <b>FS</b> is used.</p>
1666
1667
1668 <p style="margin-left:22%;">sprintf(<i>format,expr-list</i>)</p>
1669
1670 <p style="margin-left:32%;">Returns a string constructed
1671 from <i>expr-list</i> according to <i>format</i>. See the
1672 description of printf() below.</p>
1673
1674 <p style="margin-left:22%;">sub(<i>r,s,t</i>)
1675 sub(<i>r,s</i>)</p>
1676
1677 <p style="margin-left:32%;">Single substitution, same as
1678 gsub() except at most one substitution.</p>
1679
1680 <p style="margin-left:22%;">substr(<i>s,i,n</i>)
1681 substr(<i>s,i</i>)</p>
1682
1683 <p style="margin-left:32%;">Returns the substring of string
1684 <i>s</i>, starting at index <i>i</i>, of length <i>n</i>. If
1685 <i>n</i> is omitted, the suffix of <i>s</i>, starting at
1686 <i>i</i> is returned.</p>
1687
1688 <p style="margin-left:22%;">tolower(<i>s</i>)</p>
1689
1690 <p style="margin-left:32%;">Returns a copy of <i>s</i> with
1691 all upper case characters converted to lower case.</p>
1692
1693 <p style="margin-left:22%;">toupper(<i>s</i>)</p>
1694
1695 <p style="margin-left:32%;">Returns a copy of <i>s</i> with
1696 all lower case characters converted to upper case.</p>
1697
1698 <p style="margin-left:11%; margin-top: 1em">Arithmetic
1699 functions</p>
1700
1701
1702 <p style="margin-left:22%; margin-top: 1em">atan2(<i>y,x</i>)
1703 Arctan of <i>y</i>/<i>x</i> between -PI and PI.</p>
1704
1705 <table width="100%" border="0" rules="none" frame="void"
1706 cellspacing="0" cellpadding="0">
1707 <tr valign="top" align="left">
1708 <td width="22%"></td>
1709 <td width="-14%"></td>
1710 <td width="7%"></td>
1711 <td width="8%">
1712
1713
1714 <p>cos(<i>x</i>)</p></td>
1715 <td width="8%"></td>
1716 <td width="69%">
1717 </td></tr>
1718 <tr valign="top" align="left">
1719 <td width="22%"></td>
1720 <td width="-14%"></td>
1721 <td width="7%"></td>
1722 <td width="8%"></td>
1723 <td width="8%"></td>
1724 <td width="69%">
1725
1726
1727 <p>Cosine function, <i>x</i> in radians.</p></td></tr>
1728 <tr valign="top" align="left">
1729 <td width="22%"></td>
1730 <td width="-14%"></td>
1731 <td width="7%"></td>
1732 <td width="8%">
1733
1734
1735 <p>exp(<i>x</i>)</p></td>
1736 <td width="8%"></td>
1737 <td width="69%">
1738 </td></tr>
1739 <tr valign="top" align="left">
1740 <td width="22%"></td>
1741 <td width="-14%"></td>
1742 <td width="7%"></td>
1743 <td width="8%"></td>
1744 <td width="8%"></td>
1745 <td width="69%">
1746
1747
1748 <p>Exponential function.</p></td></tr>
1749 <tr valign="top" align="left">
1750 <td width="22%"></td>
1751 <td width="-14%"></td>
1752 <td width="7%"></td>
1753 <td width="8%">
1754
1755
1756 <p>int(<i>x</i>)</p></td>
1757 <td width="8%"></td>
1758 <td width="69%">
1759 </td></tr>
1760 <tr valign="top" align="left">
1761 <td width="22%"></td>
1762 <td width="-14%"></td>
1763 <td width="7%"></td>
1764 <td width="8%"></td>
1765 <td width="8%"></td>
1766 <td width="69%">
1767
1768
1769 <p>Returns <i>x</i> truncated towards zero.</p></td></tr>
1770 <tr valign="top" align="left">
1771 <td width="22%"></td>
1772 <td width="-14%"></td>
1773 <td width="7%"></td>
1774 <td width="8%">
1775
1776
1777 <p>log(<i>x</i>)</p></td>
1778 <td width="8%"></td>
1779 <td width="69%">
1780 </td></tr>
1781 <tr valign="top" align="left">
1782 <td width="22%"></td>
1783 <td width="-14%"></td>
1784 <td width="7%"></td>
1785 <td width="8%"></td>
1786 <td width="8%"></td>
1787 <td width="69%">
1788
1789
1790 <p>Natural logarithm.</p></td></tr>
1791 <tr valign="top" align="left">
1792 <td width="22%"></td>
1793 <td width="-14%"></td>
1794 <td width="7%"></td>
1795 <td width="8%">
1796
1797
1798 <p>rand()</p></td>
1799 <td width="8%"></td>
1800 <td width="69%">
1801 </td></tr>
1802 <tr valign="top" align="left">
1803 <td width="22%"></td>
1804 <td width="-14%"></td>
1805 <td width="7%"></td>
1806 <td width="8%"></td>
1807 <td width="8%"></td>
1808 <td width="69%">
1809
1810
1811 <p>Returns a random number between zero and one.</p></td></tr>
1812 <tr valign="top" align="left">
1813 <td width="22%"></td>
1814 <td width="-14%"></td>
1815 <td width="7%"></td>
1816 <td width="8%">
1817
1818
1819 <p>sin(<i>x</i>)</p></td>
1820 <td width="8%"></td>
1821 <td width="69%">
1822 </td></tr>
1823 <tr valign="top" align="left">
1824 <td width="22%"></td>
1825 <td width="-14%"></td>
1826 <td width="7%"></td>
1827 <td width="8%"></td>
1828 <td width="8%"></td>
1829 <td width="69%">
1830
1831
1832 <p>Sine function, <i>x</i> in radians.</p></td></tr>
1833 <tr valign="top" align="left">
1834 <td width="22%"></td>
1835 <td width="-14%"></td>
1836 <td width="7%"></td>
1837 <td width="8%">
1838
1839
1840 <p>sqrt(<i>x</i>)</p></td>
1841 <td width="8%"></td>
1842 <td width="69%">
1843 </td></tr>
1844 <tr valign="top" align="left">
1845 <td width="22%"></td>
1846 <td width="-14%"></td>
1847 <td width="7%"></td>
1848 <td width="8%"></td>
1849 <td width="8%"></td>
1850 <td width="69%">
1851
1852
1853 <p>Returns square root of <i>x</i>.</p></td></tr>
1854 </table>
1855
1856 <p style="margin-left:22%;">srand(<i>expr</i>) srand()</p>
1857
1858 <p style="margin-left:32%;">Seeds the random number
1859 generator, using the clock if <i>expr</i> is omitted, and
1860 returns the value of the previous seed. <b>lmawk</b> seeds
1861 the random number generator from the clock at startup so
1862 there is no real need to call srand(). Srand(<i>expr</i>) is
1863 useful for repeating pseudo random sequences.</p>
1864
1865 <p style="margin-left:11%; margin-top: 1em">Misc functions
1866 (libmawk extensions)</p>
1867
1868
1869 <p style="margin-left:22%;">call(<i>fname,arg1,arg2,...</i>)</p>
1870
1871 <p style="margin-left:32%;">Call awk function <i>fname</i>
1872 with the supplied arguments. If the call fails, empty value,
1873 else the return value of the callee is returned. Built-in
1874 variable ERRNO is always set.</p>
1875
1876
1877 <p style="margin-left:22%;">acall(<i>fname,arrname</i>)</p>
1878
1879 <p style="margin-left:32%;">Call awk function <i>fname</i>
1880 with arguments supplied in array named <i>arrname</i> (both
1881 arguments are strings naming an existing object). The array
1882 should be indexed from 1. Number of arguments is determined
1883 by looking for the first empty (non-existing) index in the
1884 array. If the call fails, empty value, else the return value
1885 of the callee is returned. Built-in variable ERRNO is always
1886 set.</p>
1887
1888 <p style="margin-left:22%;">valueof(<i>vname
1889 [,idx]</i>)</p>
1890
1891 <p style="margin-left:32%;">Return the value of variable
1892 <i>fname</i>; if the variable is an array, return the
1893 element indexed by <i>idx</i> (which must be present in this
1894 case). If index is not present or is empty (&quot;&quot;),
1895 the variable is expected to be scalar. Built-in variable
1896 ERRNO is always set. NOTE: valueof() has access to the
1897 global symbol table only. It will fail to resolve anything
1898 else than global objects; most notably it will fail on local
1899 variables, $ arguments and on most of the built-in
1900 variables.</p>
1901
1902 <p style="margin-left:11%; margin-top: 1em"><b>9. Input and
1903 output</b> <br>
1904 There are two output statements, <b>print</b> and
1905 <b>printf</b>.</p>
1906
1907 <table width="100%" border="0" rules="none" frame="void"
1908 cellspacing="0" cellpadding="0">
1909 <tr valign="top" align="left">
1910 <td width="22%"></td>
1911 <td width="7%">
1912
1913
1914 <p>print</p></td>
1915 <td width="3%"></td>
1916 <td width="53%">
1917
1918
1919 <p>writes <b>$0 ORS</b> to standard output.</p></td>
1920 <td width="15%">
1921 </td></tr>
1922 </table>
1923
1924 <p style="margin-left:22%;">print <i>expr</i>1,
1925 <i>expr</i>2, ..., <i>expr</i>n</p>
1926
1927 <p style="margin-left:32%;">writes <i>expr</i>1 <b>OFS</b>
1928 <i>expr</i>2 <b>OFS</b> ... <i>expr</i>n <b>ORS</b> to
1929 standard output. Numeric expressions are converted to string
1930 with <b>OFMT</b>.</p>
1931
1932 <p style="margin-left:22%;">printf <i>format,
1933 expr-list</i></p>
1934
1935 <p style="margin-left:32%;">duplicates the printf C library
1936 function writing to standard output. The complete ANSI C
1937 format specifications are recognized with conversions %c,
1938 %d, %e, %E, %f, %g, %G, %i, %o, %s, %u, %x, %X and %%, and
1939 conversion qualifiers h and l.</p>
1940
1941 <p style="margin-left:11%; margin-top: 1em">The argument
1942 list to print or printf can optionally be enclosed in
1943 parentheses. Print formats numbers using <b>OFMT</b> or
1944 &quot;%d&quot; for exact integers. &quot;%c&quot; with a
1945 numeric argument prints the corresponding 8 bit character,
1946 with a string argument it prints the first character of the
1947 string. The output of print and printf can be redirected to
1948 a file or command by appending &gt; <i>file</i>, &gt;&gt;
1949 <i>file</i> or | <i>command</i> to the end of the print
1950 statement. Redirection opens <i>file</i> or <i>command</i>
1951 only once, subsequent redirections append to the already
1952 open stream. By convention, <b>lmawk</b> associates the
1953 filename &quot;/dev/stderr&quot; with stderr which allows
1954 print and printf to be redirected to stderr. <b>lmawk</b>
1955 also associates &quot;&minus;&quot; and
1956 &quot;/dev/stdout&quot; with stdin and stdout which allows
1957 these streams to be passed to functions. Opening /dev/fd/N
1958 will do an fdopen() on file descriptor N, where N is an
1959 integer - this is a libmawk extension. If any of the /dev
1960 heuristics needs to be bypassed (i.e. the script wants to
1961 open the real /dev/stdout or the real /dev/fd/5), the
1962 leading slash should be doubled (e.g. //dev/fd/5).</p>
1963
1964 <p style="margin-left:11%; margin-top: 1em">The input
1965 function <b>getline</b> has the following variations.</p>
1966
1967 <p style="margin-left:22%;">getline</p>
1968
1969 <p style="margin-left:32%;">reads into <b>$0</b>, updates
1970 the fields, <b>NF</b>, <b>NR</b> and <b>FNR</b>.</p>
1971
1972 <p style="margin-left:22%;">getline &lt; <i>file</i></p>
1973
1974 <p style="margin-left:32%;">reads into <b>$0</b> from
1975 <i>file</i>, updates the fields and <b>NF</b>.</p>
1976
1977 <p style="margin-left:22%;">getline <i>var</i></p>
1978
1979 <p style="margin-left:32%;">reads the next record into
1980 <i>var</i>, updates <b>NR</b> and <b>FNR</b>.</p>
1981
1982 <p style="margin-left:22%;">getline <i>var</i> &lt;
1983 <i>file</i></p>
1984
1985 <p style="margin-left:32%;">reads the next record of
1986 <i>file</i> into <i>var</i>.</p>
1987
1988 <p style="margin-left:22%;"><i>command</i> | getline</p>
1989
1990 <p style="margin-left:32%;">pipes a record from
1991 <i>command</i> into <b>$0</b> and updates the fields and
1992 <b>NF</b>.</p>
1993
1994 <p style="margin-left:22%;"><i>command</i> | getline
1995 <i>var</i></p>
1996
1997 <p style="margin-left:32%;">pipes a record from
1998 <i>command</i> into <i>var</i>.</p>
1999
2000 <p style="margin-left:11%; margin-top: 1em">Getline returns
2001 0 on end-of-file, &minus;1 on error, otherwise 1.</p>
2002
2003 <p style="margin-left:11%; margin-top: 1em">Commands on the
2004 end of pipes are executed by /bin/sh.</p>
2005
2006 <p style="margin-left:11%; margin-top: 1em">The function
2007 <b>close</b>(<i>expr</i>) closes the file or pipe associated
2008 with <i>expr</i>. Close returns 0 if <i>expr</i> is an open
2009 file, the exit status if <i>expr</i> is a piped command, and
2010 &minus;1 otherwise. Close is used to reread a file or
2011 command, make sure the other end of an output pipe is
2012 finished or conserve file resources.</p>
2013
2014 <p style="margin-left:11%; margin-top: 1em">The function
2015 <b>fflush</b>(<i>expr</i>) flushes the output file or pipe
2016 associated with <i>expr</i>. Fflush returns 0 if <i>expr</i>
2017 is an open output stream else &minus;1. Fflush without an
2018 argument flushes stdout. Fflush with an empty argument
2019 (&quot;&quot;) flushes all open output.</p>
2020
2021 <p style="margin-left:11%; margin-top: 1em">The function
2022 <b>system</b>(<i>expr</i>) uses /bin/sh to execute
2023 <i>expr</i> and returns the exit status of the command
2024 <i>expr</i>. Changes made to the <b>ENVIRON</b> array are
2025 not passed to commands executed with <b>system</b> or
2026 pipes.</p>
2027
2028 <p style="margin-left:11%; margin-top: 1em"><b>10. User
2029 defined functions</b> <br>
2030 The syntax for a user defined function is</p>
2031
2032
2033 <p style="margin-left:11%; margin-top: 1em"><b>function</b>
2034 name( <i>args</i> ) { <i>statements</i> }</p>
2035
2036 <p style="margin-left:11%; margin-top: 1em">The function
2037 body can contain a return statement</p>
2038
2039 <p style="margin-left:11%; margin-top: 1em"><b>return</b>
2040 <i>opt_expr</i></p>
2041
2042 <p style="margin-left:11%; margin-top: 1em">A return
2043 statement is not required. Function calls may be nested or
2044 recursive. Functions are passed expressions by value and
2045 arrays by reference. Extra arguments serve as local
2046 variables and are initialized to <i>null</i>. For example,
2047 csplit(<i>s,A</i>) puts each character of <i>s</i> into
2048 array <i>A</i> and returns the length of <i>s</i>.</p>
2049
2050 <p style="margin-left:11%; margin-top: 1em">function
2051 csplit(s, A, n, i)</p>
2052
2053 <table width="100%" border="0" rules="none" frame="void"
2054 cellspacing="0" cellpadding="0">
2055 <tr valign="top" align="left">
2056 <td width="8%"></td>
2057 <td width="7%"></td>
2058 <td width="85%">
2059
2060
2061 <p>{</p></td></tr>
2062 <tr valign="top" align="left">
2063 <td width="8%"></td>
2064 <td width="7%"></td>
2065 <td width="85%">
2066
2067
2068 <p>n = length(s)</p></td></tr>
2069 <tr valign="top" align="left">
2070 <td width="8%"></td>
2071 <td width="7%"></td>
2072 <td width="85%">
2073
2074
2075 <p>for( i = 1 ; i &lt;= n ; i++ ) A[i] = substr(s, i,
2076 1)</p> </td></tr>
2077 <tr valign="top" align="left">
2078 <td width="8%"></td>
2079 <td width="7%"></td>
2080 <td width="85%">
2081
2082
2083 <p>return n</p></td></tr>
2084 <tr valign="top" align="left">
2085 <td width="8%"></td>
2086 <td width="7%"></td>
2087 <td width="85%">
2088
2089
2090 <p>}</p></td></tr>
2091 </table>
2092
2093 <p style="margin-left:11%; margin-top: 1em">Putting extra
2094 space between passed arguments and local variables is
2095 conventional. Functions can be referenced before they are
2096 defined, but the function name and the &rsquo;(&rsquo; of
2097 the arguments must touch to avoid confusion with
2098 concatenation.</p>
2099
2100 <p style="margin-left:11%; margin-top: 1em"><b>11.
2101 Splitting strings, records and files</b> <br>
2102 Awk programs use the same algorithm to split strings into
2103 arrays with split(), and records into fields on <b>FS</b>.
2104 <b>lmawk</b> uses essentially the same algorithm to split
2105 files into records on <b>RS</b>.</p>
2106
2107
2108 <p style="margin-left:11%; margin-top: 1em">Split(<i>expr,A,sep</i>)
2109 works as follows:</p>
2110
2111 <table width="100%" border="0" rules="none" frame="void"
2112 cellspacing="0" cellpadding="0">
2113 <tr valign="top" align="left">
2114 <td width="22%"></td>
2115 <td width="4%">
2116
2117
2118 <p>(1)</p></td>
2119 <td width="6%"></td>
2120 <td width="68%">
2121
2122
2123 <p>If <i>sep</i> is omitted, it is replaced by <b>FS</b>.
2124 <i>Sep</i> can be an expression or regular expression. If it
2125 is an expression of non-string type, it is converted to
2126 string.</p> </td></tr>
2127 <tr valign="top" align="left">
2128 <td width="22%"></td>
2129 <td width="4%">
2130
2131
2132 <p>(2)</p></td>
2133 <td width="6%"></td>
2134 <td width="68%">
2135
2136
2137 <p>If <i>sep</i> = &quot; &quot; (a single space), then
2138 &lt;SPACE&gt; is trimmed from the front and back of
2139 <i>expr</i>, and <i>sep</i> becomes &lt;SPACE&gt;.
2140 <b>lmawk</b> defines &lt;SPACE&gt; as the regular expression
2141 /[&nbsp;\t\n]+/. Otherwise <i>sep</i> is treated as a
2142 regular expression, except that meta-characters are ignored
2143 for a string of length 1, e.g., split(x, A, &quot;*&quot;)
2144 and split(x, A, /\*/) are the same.</p></td></tr>
2145 <tr valign="top" align="left">
2146 <td width="22%"></td>
2147 <td width="4%">
2148
2149
2150 <p>(3)</p></td>
2151 <td width="6%"></td>
2152 <td width="68%">
2153
2154
2155 <p>If <i>expr</i> is not string, it is converted to string.
2156 If <i>expr</i> is then the empty string &quot;&quot;,
2157 split() returns 0 and <i>A</i> is set empty. Otherwise, all
2158 non-overlapping, non-null and longest matches of <i>sep</i>
2159 in <i>expr</i>, separate <i>expr</i> into fields which are
2160 loaded into <i>A</i>. The fields are placed in A[1], A[2],
2161 ..., A[n] and split() returns n, the number of fields which
2162 is the number of matches plus one. Data placed in <i>A</i>
2163 that looks numeric is typed number and string.</p></td></tr>
2164 </table>
2165
2166 <p style="margin-left:11%; margin-top: 1em">Splitting
2167 records into fields works the same except the pieces are
2168 loaded into <b>$1</b>, <b>$2</b>,..., <b>$NF</b>. If
2169 <b>$0</b> is empty, <b>NF</b> is set to 0 and all <b>$i</b>
2170 to &quot;&quot;.</p>
2171
2172 <p style="margin-left:11%; margin-top: 1em"><b>lmawk</b>
2173 splits files into records by the same algorithm, but with
2174 the slight difference that <b>RS</b> is really a terminator
2175 instead of a separator. (<b>ORS</b> is really a terminator
2176 too).</p>
2177
2178 <p style="margin-left:22%; margin-top: 1em">E.g., if
2179 <b>FS</b> = &quot;:+&quot; and <b>$0</b> = &quot;a::b:&quot;
2180 , then <b>NF</b> = 3 and <b>$1</b> = &quot;a&quot;,
2181 <b>$2</b> = &quot;b&quot; and <b>$3</b> = &quot;&quot;, but
2182 if &quot;a::b:&quot; is the contents of an input file and
2183 <b>RS</b> = &quot;:+&quot;, then there are two records
2184 &quot;a&quot; and &quot;b&quot;.</p>
2185
2186 <p style="margin-left:11%; margin-top: 1em"><b>RS</b> =
2187 &quot; &quot; is not special.</p>
2188
2189 <p style="margin-left:11%; margin-top: 1em">If <b>FS</b> =
2190 &quot;&quot;, then <b>lmawk</b> breaks the record into
2191 individual characters, and, similarly,
2192 split(<i>s,A,</i>&quot;&quot;) places the individual
2193 characters of <i>s</i> into <i>A</i>.</p>
2194
2195 <p style="margin-left:11%; margin-top: 1em"><b>12.
2196 Multi-line records</b> <br>
2197 Since <b>lmawk</b> interprets <b>RS</b> as a regular
2198 expression, multi-line records are easy. Setting <b>RS</b> =
2199 &quot;\n\n+&quot;, makes one or more blank lines separate
2200 records. If <b>FS</b> = &quot; &quot; (the default), then
2201 single newlines, by the rules for &lt;SPACE&gt; above,
2202 become space and single newlines are field separators.</p>
2203
2204 <p style="margin-left:22%; margin-top: 1em">For example, if
2205 a file is &quot;a&nbsp;b\nc\n\n&quot;, <b>RS</b> =
2206 &quot;\n\n+&quot; and <b>FS</b> = &quot;&nbsp;&quot;, then
2207 there is one record &quot;a&nbsp;b\nc&quot; with three
2208 fields &quot;a&quot;, &quot;b&quot; and &quot;c&quot;.
2209 Changing <b>FS</b> = &quot;\n&quot;, gives two fields
2210 &quot;a b&quot; and &quot;c&quot;; changing <b>FS</b> =
2211 &quot;&quot;, gives one field identical to the record.</p>
2212
2213 <p style="margin-left:11%; margin-top: 1em">If you want
2214 lines with spaces or tabs to be considered blank, set
2215 <b>RS</b> = &quot;\n([&nbsp;\t]*\n)+&quot;. For
2216 compatibility with other awks, setting <b>RS</b> =
2217 &quot;&quot; has the same effect as if blank lines are
2218 stripped from the front and back of files and then records
2219 are determined as if <b>RS</b> = &quot;\n\n+&quot;. Posix
2220 requires that &quot;\n&quot; always separates records when
2221 <b>RS</b> = &quot;&quot; regardless of the value of
2222 <b>FS</b>. <b>lmawk</b> does not support this convention,
2223 because defining &quot;\n&quot; as &lt;SPACE&gt; makes it
2224 unnecessary.</p>
2225
2226 <p style="margin-left:11%; margin-top: 1em">Most of the
2227 time when you change <b>RS</b> for multi-line records, you
2228 will also want to change <b>ORS</b> to &quot;\n\n&quot; so
2229 the record spacing is preserved on output.</p>
2230
2231 <p style="margin-left:11%; margin-top: 1em"><b>13. Program
2232 execution</b> <br>
2233 This section describes the order of program execution. First
2234 <b>ARGC</b> is set to the total number of command line
2235 arguments passed to the execution phase of the program.
2236 <b>ARGV[0]</b> is set the name of the AWK interpreter and
2237 <b>ARGV[1]</b> ... <b>ARGV[ARGC-1]</b> holds the remaining
2238 command line arguments exclusive of options and program
2239 source. For example with</p>
2240
2241 <p style="margin-left:11%; margin-top: 1em">lmawk &minus;f
2242 prog v=1 A t=hello B</p>
2243
2244 <p style="margin-left:11%; margin-top: 1em"><b>ARGC</b> = 5
2245 with <b>ARGV[0]</b> = &quot;lmawk&quot;, <b>ARGV[1]</b> =
2246 &quot;v=1&quot;, <b>ARGV[2]</b> = &quot;A&quot;,
2247 <b>ARGV[3]</b> = &quot;t=hello&quot; and <b>ARGV[4]</b> =
2248 &quot;B&quot;.</p>
2249
2250 <p style="margin-left:11%; margin-top: 1em">Next, each
2251 <b>BEGIN</b> block is executed in order. If the program
2252 consists entirely of <b>BEGIN</b> blocks, then execution
2253 terminates, else an input stream is opened and execution
2254 continues. If <b>ARGC</b> equals 1, the input stream is set
2255 to stdin, else the command line arguments <b>ARGV[1]</b> ...
2256 <b>ARGV[ARGC-1]</b> are examined for a file argument.</p>
2257
2258 <p style="margin-left:11%; margin-top: 1em">The command
2259 line arguments divide into three sets: file arguments,
2260 assignment arguments and empty strings &quot;&quot;. An
2261 assignment has the form <i>var</i>=<i>string</i>. When an
2262 <b>ARGV[i]</b> is examined as a possible file argument, if
2263 it is empty it is skipped; if it is an assignment argument,
2264 the assignment to <i>var</i> takes place and <b>i</b> skips
2265 to the next argument; else <b>ARGV[i]</b> is opened for
2266 input. If it fails to open, execution terminates with exit
2267 code 2. If no command line argument is a file argument, then
2268 input comes from stdin. Getline in a <b>BEGIN</b> action
2269 opens input. &quot;&minus;&quot; as a file argument denotes
2270 stdin.</p>
2271
2272 <p style="margin-left:11%; margin-top: 1em">Once an input
2273 stream is open, each input record is tested against each
2274 <i>pattern</i>, and if it matches, the associated
2275 <i>action</i> is executed. An expression pattern matches if
2276 it is boolean true (see the end of section 2). A
2277 <b>BEGIN</b> pattern matches before any input has been read,
2278 and an <b>END</b> pattern matches after all input has been
2279 read. A range pattern, <i>expr</i>1,<i>expr</i>2 , matches
2280 every record between the match of <i>expr</i>1 and the match
2281 <i>expr</i>2 inclusively.</p>
2282
2283 <p style="margin-left:11%; margin-top: 1em">When end of
2284 file occurs on the input stream, the remaining command line
2285 arguments are examined for a file argument, and if there is
2286 one it is opened, else the <b>END</b> <i>pattern</i> is
2287 considered matched and all <b>END</b> <i>actions</i> are
2288 executed.</p>
2289
2290 <p style="margin-left:11%; margin-top: 1em">In the example,
2291 the assignment v=1 takes place after the <b>BEGIN</b>
2292 <i>actions</i> are executed, and the data placed in v is
2293 typed number and string. Input is then read from file A. On
2294 end of file A, t is set to the string &quot;hello&quot;, and
2295 B is opened for input. On end of file B, the <b>END</b>
2296 <i>actions</i> are executed.</p>
2297
2298 <p style="margin-left:11%; margin-top: 1em">Program flow at
2299 the <i>pattern {action}</i> level can be changed with
2300 the</p>
2301
2302
2303 <p style="margin-left:11%; margin-top: 1em"><b>next</b></p>
2304
2305 <table width="100%" border="0" rules="none" frame="void"
2306 cellspacing="0" cellpadding="0">
2307 <tr valign="top" align="left">
2308 <td width="8%"></td>
2309 <td width="92%">
2310
2311
2312 <p><b>exit</b> <i>opt_expr</i></p></td></tr>
2313 </table>
2314
2315 <p style="margin-left:11%; margin-top: 1em">statements. A
2316 <b>next</b> statement causes the next input record to be
2317 read and pattern testing to restart with the first
2318 <i>pattern {action}</i> pair in the program. An <b>exit</b>
2319 statement causes immediate execution of the <b>END</b>
2320 actions or program termination if there are none or if the
2321 <b>exit</b> occurs in an <b>END</b> action. The
2322 <i>opt_expr</i> sets the exit value of the program unless
2323 overridden by a later <b>exit</b> or subsequent error.</p>
2324
2325 <p style="margin-left:11%; margin-top: 1em"><b>14.
2326 include</b> <br>
2327 libmawk introduces source inclusion feature. Syntax is:</p>
2328
2329 <table width="100%" border="0" rules="none" frame="void"
2330 cellspacing="0" cellpadding="0">
2331 <tr valign="top" align="left">
2332 <td width="8%"></td>
2333 <td width="92%">
2334
2335
2336 <p>include &quot;filename&quot;</p></td></tr>
2337 </table>
2338
2339 <p style="margin-left:11%; margin-top: 1em">Include
2340 statements must be on top level (outside of blocks). If file
2341 name <br>
2342 starts with a plus sign (&rsquo;+&rsquo;), the script file
2343 is not loaded if it has <br>
2344 been already loaded (by another include or -f command line
2345 argument).</p>
2346
2347 <h2>EXAMPLES
2348 <a name="EXAMPLES"></a>
2349 </h2>
2350
2351
2352 <p style="margin-left:11%; margin-top: 1em">1. emulate
2353 cat.</p>
2354
2355 <table width="100%" border="0" rules="none" frame="void"
2356 cellspacing="0" cellpadding="0">
2357 <tr valign="top" align="left">
2358 <td width="8%"></td>
2359 <td width="92%">
2360
2361
2362 <p>{ print }</p></td></tr>
2363 </table>
2364
2365 <p style="margin-left:11%; margin-top: 1em">2. emulate
2366 wc.</p>
2367
2368 <table width="100%" border="0" rules="none" frame="void"
2369 cellspacing="0" cellpadding="0">
2370 <tr valign="top" align="left">
2371 <td width="8%"></td>
2372 <td width="92%">
2373
2374
2375 <p>{ chars += length($0) + 1 # add one for the \n</p></td></tr>
2376 <tr valign="top" align="left">
2377 <td width="8%"></td>
2378 <td width="92%">
2379
2380
2381 <p>words += NF</p></td></tr>
2382 <tr valign="top" align="left">
2383 <td width="8%"></td>
2384 <td width="92%">
2385
2386
2387 <p>}</p></td></tr>
2388 <tr valign="top" align="left">
2389 <td width="8%"></td>
2390 <td width="92%">
2391
2392
2393 <p>END{ print NR, words, chars }</p></td></tr>
2394 </table>
2395
2396 <p style="margin-left:11%; margin-top: 1em">3. count the
2397 number of unique &quot;real words&quot;.</p>
2398
2399 <table width="100%" border="0" rules="none" frame="void"
2400 cellspacing="0" cellpadding="0">
2401 <tr valign="top" align="left">
2402 <td width="8%"></td>
2403 <td width="92%">
2404
2405
2406 <p>BEGIN { FS = &quot;[^A-Za-z]+&quot; }</p></td></tr>
2407 <tr valign="top" align="left">
2408 <td width="8%"></td>
2409 <td width="92%">
2410
2411
2412 <p>{ for(i = 1 ; i &lt;= NF ; i++) word[$i] = &quot;&quot;
2413 }</p> </td></tr>
2414 <tr valign="top" align="left">
2415 <td width="8%"></td>
2416 <td width="92%">
2417
2418
2419 <p>END { delete word[&quot;&quot;]</p></td></tr>
2420 <tr valign="top" align="left">
2421 <td width="8%"></td>
2422 <td width="92%">
2423
2424
2425 <p>for ( i in word ) cnt++</p></td></tr>
2426 <tr valign="top" align="left">
2427 <td width="8%"></td>
2428 <td width="92%">
2429
2430
2431 <p>print cnt</p></td></tr>
2432 <tr valign="top" align="left">
2433 <td width="8%"></td>
2434 <td width="92%">
2435
2436
2437 <p>}</p></td></tr>
2438 </table>
2439
2440 <p style="margin-left:11%; margin-top: 1em">4. sum the
2441 second field of every record based on the first field.</p>
2442
2443 <table width="100%" border="0" rules="none" frame="void"
2444 cellspacing="0" cellpadding="0">
2445 <tr valign="top" align="left">
2446 <td width="8%"></td>
2447 <td width="92%">
2448
2449
2450 <p>$1 ~ /credit|gain/ { sum += $2 }</p></td></tr>
2451 <tr valign="top" align="left">
2452 <td width="8%"></td>
2453 <td width="92%">
2454
2455
2456 <p>$1 ~ /debit|loss/ { sum &minus;= $2 }</p></td></tr>
2457 <tr valign="top" align="left">
2458 <td width="8%"></td>
2459 <td width="92%">
2460
2461
2462 <p>END { print sum }</p></td></tr>
2463 </table>
2464
2465 <p style="margin-left:11%; margin-top: 1em">5. sort a file,
2466 comparing as string</p>
2467
2468 <table width="100%" border="0" rules="none" frame="void"
2469 cellspacing="0" cellpadding="0">
2470 <tr valign="top" align="left">
2471 <td width="8%"></td>
2472 <td width="7%"></td>
2473 <td width="8%">
2474
2475
2476 <p>{ line[NR] = $0 &quot;&quot; } # make sure of comparison
2477 type</p> </td>
2478 <td width="8%"></td>
2479 <td width="15%"></td>
2480 <td width="8%"></td>
2481 <td width="46%">
2482 </td></tr>
2483 <tr valign="top" align="left">
2484 <td width="8%"></td>
2485 <td width="7%">
2486 </td>
2487 <td width="8%">
2488 </td>
2489 <td width="8%">
2490 </td>
2491 <td width="15%"></td>
2492 <td width="8%"></td>
2493 <td width="46%">
2494 </td></tr>
2495 <tr valign="top" align="left">
2496 <td width="8%"></td>
2497 <td width="7%"></td>
2498 <td width="8%"></td>
2499 <td width="8%">
2500
2501
2502 <p># in case some lines look numeric</p></td>
2503 <td width="15%"></td>
2504 <td width="8%"></td>
2505 <td width="46%">
2506 </td></tr>
2507 <tr valign="top" align="left">
2508 <td width="8%"></td>
2509 <td width="7%"></td>
2510 <td width="8%">
2511
2512
2513 <p>END { isort(line, NR)</p></td>
2514 <td width="8%"></td>
2515 <td width="15%"></td>
2516 <td width="8%"></td>
2517 <td width="46%">
2518 </td></tr>
2519 <tr valign="top" align="left">
2520 <td width="8%"></td>
2521 <td width="7%"></td>
2522 <td width="8%">
2523
2524
2525 <p>for(i = 1 ; i &lt;= NR ; i++) print line[i]</p></td>
2526 <td width="8%"></td>
2527 <td width="15%"></td>
2528 <td width="8%"></td>
2529 <td width="46%">
2530 </td></tr>
2531 <tr valign="top" align="left">
2532 <td width="8%"></td>
2533 <td width="7%"></td>
2534 <td width="8%">
2535
2536
2537 <p>}</p></td>
2538 <td width="8%"></td>
2539 <td width="15%"></td>
2540 <td width="8%"></td>
2541 <td width="46%">
2542 </td></tr>
2543 <tr valign="top" align="left">
2544 <td width="8%"></td>
2545 <td width="7%"></td>
2546 <td width="8%">
2547
2548
2549 <p>#insertion sort of A[1..n]</p></td>
2550 <td width="8%"></td>
2551 <td width="15%"></td>
2552 <td width="8%"></td>
2553 <td width="46%">
2554 </td></tr>
2555 <tr valign="top" align="left">
2556 <td width="8%"></td>
2557 <td width="7%">
2558 </td>
2559 <td width="8%">
2560
2561
2562 <p>function isort( A, n,</p></td>
2563 <td width="8%"></td>
2564 <td width="15%"></td>
2565 <td width="8%"></td>
2566 <td width="46%">
2567
2568
2569 <p>i, j, hold)</p></td></tr>
2570 <tr valign="top" align="left">
2571 <td width="8%"></td>
2572 <td width="7%"></td>
2573 <td width="8%">
2574
2575
2576 <p>{</p></td>
2577 <td width="8%"></td>
2578 <td width="15%"></td>
2579 <td width="8%"></td>
2580 <td width="46%">
2581 </td></tr>
2582 <tr valign="top" align="left">
2583 <td width="8%"></td>
2584 <td width="7%"></td>
2585 <td width="8%">
2586
2587
2588 <p>for( i = 2 ; i &lt;= n ; i++)</p></td>
2589 <td width="8%"></td>
2590 <td width="15%"></td>
2591 <td width="8%"></td>
2592 <td width="46%">
2593 </td></tr>
2594 <tr valign="top" align="left">
2595 <td width="8%"></td>
2596 <td width="7%"></td>
2597 <td width="8%">
2598
2599
2600 <p>{</p></td>
2601 <td width="8%"></td>
2602 <td width="15%"></td>
2603 <td width="8%"></td>
2604 <td width="46%">
2605 </td></tr>
2606 <tr valign="top" align="left">
2607 <td width="8%"></td>
2608 <td width="7%"></td>
2609 <td width="8%">
2610
2611
2612 <p>hold = A[j = i]</p></td>
2613 <td width="8%"></td>
2614 <td width="15%"></td>
2615 <td width="8%"></td>
2616 <td width="46%">
2617 </td></tr>
2618 <tr valign="top" align="left">
2619 <td width="8%"></td>
2620 <td width="7%"></td>
2621 <td width="8%">
2622
2623
2624 <p>while ( A[j&minus;1] &gt; hold )</p></td>
2625 <td width="8%"></td>
2626 <td width="15%"></td>
2627 <td width="8%"></td>
2628 <td width="46%">
2629 </td></tr>
2630 <tr valign="top" align="left">
2631 <td width="8%"></td>
2632 <td width="7%"></td>
2633 <td width="8%">
2634
2635
2636 <p>{ j&minus;&minus; ; A[j+1] = A[j] }</p></td>
2637 <td width="8%"></td>
2638 <td width="15%"></td>
2639 <td width="8%"></td>
2640 <td width="46%">
2641 </td></tr>
2642 <tr valign="top" align="left">
2643 <td width="8%"></td>
2644 <td width="7%"></td>
2645 <td width="8%">
2646
2647
2648 <p>A[j] = hold</p></td>
2649 <td width="8%"></td>
2650 <td width="15%"></td>
2651 <td width="8%"></td>
2652 <td width="46%">
2653 </td></tr>
2654 <tr valign="top" align="left">
2655 <td width="8%"></td>
2656 <td width="7%"></td>
2657 <td width="8%">
2658
2659
2660 <p>}</p></td>
2661 <td width="8%"></td>
2662 <td width="15%"></td>
2663 <td width="8%"></td>
2664 <td width="46%">
2665 </td></tr>
2666 <tr valign="top" align="left">
2667 <td width="8%"></td>
2668 <td width="7%"></td>
2669 <td width="8%">
2670
2671
2672 <p># sentinel A[0] = &quot;&quot; will be created if
2673 needed</p> </td>
2674 <td width="8%"></td>
2675 <td width="15%"></td>
2676 <td width="8%"></td>
2677 <td width="46%">
2678 </td></tr>
2679 <tr valign="top" align="left">
2680 <td width="8%"></td>
2681 <td width="7%"></td>
2682 <td width="8%">
2683
2684
2685 <p>}</p></td>
2686 <td width="8%"></td>
2687 <td width="15%"></td>
2688 <td width="8%"></td>
2689 <td width="46%">
2690 </td></tr>
2691 </table>
2692
2693 <h2>COMPATIBILITY ISSUES
2694 <a name="COMPATIBILITY ISSUES"></a>
2695 </h2>
2696
2697
2698 <p style="margin-left:11%; margin-top: 1em">The Posix
2699 1003.2(draft 11.3) definition of the AWK language is AWK as
2700 described in the AWK book with a few extensions that
2701 appeared in SystemVR4 nawk. The extensions are:</p>
2702
2703 <p style="margin-left:22%; margin-top: 1em">New functions:
2704 toupper() and tolower(); libmawk extensions: call(),
2705 acall(), valueof().</p>
2706
2707 <p style="margin-left:22%; margin-top: 1em">New variables:
2708 ENVIRON[] and CONVFMT; libmawk extension: ERRNO, LIBPATH. As
2709 a libmawk extension, ENVIRON affects the environment of
2710 children processes.</p>
2711
2712 <p style="margin-left:22%; margin-top: 1em">As a libmawk
2713 extension, new built-in variable LIBPATH is used as a list
2714 of search paths while loading scripts from the command line
2715 or from include.</p>
2716
2717 <p style="margin-left:22%; margin-top: 1em">If a script
2718 name starts with plus (&rsquo;+&rsquo;), the file is not
2719 loaded if it has been loaded earlier (to avoid double
2720 loading libs trough -f and/or include). This is a libmawk
2721 extension.</p>
2722
2723 <p style="margin-left:22%; margin-top: 1em">It is possible
2724 to include a script from another script using keyword
2725 include &quot;scriptname.awk&quot; (libmawk extension).</p>
2726
2727 <p style="margin-left:22%; margin-top: 1em">ANSI C
2728 conversion specifications for printf() and sprintf().</p>
2729
2730 <p style="margin-left:22%; margin-top: 1em">New command
2731 options: &minus;v var=value, multiple -f options and
2732 implementation options as arguments to &minus;W.</p>
2733
2734 <p style="margin-left:11%; margin-top: 1em">Posix AWK is
2735 oriented to operate on files a line at a time. <b>RS</b> can
2736 be changed from &quot;\n&quot; to another single character,
2737 but it is hard to find any use for this &mdash; there are no
2738 examples in the AWK book. By convention, <b>RS</b> =
2739 &quot;&quot;, makes one or more blank lines separate
2740 records, allowing multi-line records. When <b>RS</b> =
2741 &quot;&quot;, &quot;\n&quot; is always a field separator
2742 regardless of the value in <b>FS</b>.</p>
2743
2744 <p style="margin-left:11%; margin-top: 1em"><b>lmawk</b>,
2745 on the other hand, allows <b>RS</b> to be a regular
2746 expression. When &quot;\n&quot; appears in records, it is
2747 treated as space, and <b>FS</b> always determines
2748 fields.</p>
2749
2750 <p style="margin-left:11%; margin-top: 1em">Removing the
2751 line at a time paradigm can make some programs simpler and
2752 can often improve performance. For example, redoing example
2753 3 from above,</p>
2754
2755 <table width="100%" border="0" rules="none" frame="void"
2756 cellspacing="0" cellpadding="0">
2757 <tr valign="top" align="left">
2758 <td width="8%"></td>
2759 <td width="92%">
2760
2761
2762 <p>BEGIN { RS = &quot;[^A-Za-z]+&quot; }</p></td></tr>
2763 <tr valign="top" align="left">
2764 <td width="8%"></td>
2765 <td width="92%">
2766
2767
2768 <p>{ word[ $0 ] = &quot;&quot; }</p></td></tr>
2769 <tr valign="top" align="left">
2770 <td width="8%"></td>
2771 <td width="92%">
2772
2773
2774 <p>END { delete word[ &quot;&quot; ]</p></td></tr>
2775 <tr valign="top" align="left">
2776 <td width="8%"></td>
2777 <td width="92%">
2778
2779
2780 <p>for( i in word ) cnt++</p></td></tr>
2781 <tr valign="top" align="left">
2782 <td width="8%"></td>
2783 <td width="92%">
2784
2785
2786 <p>print cnt</p></td></tr>
2787 <tr valign="top" align="left">
2788 <td width="8%"></td>
2789 <td width="92%">
2790
2791
2792 <p>}</p></td></tr>
2793 </table>
2794
2795 <p style="margin-left:11%; margin-top: 1em">counts the
2796 number of unique words by making each word a record. On
2797 moderate size files, <b>lmawk</b> executes twice as fast,
2798 because of the simplified inner loop.</p>
2799
2800 <p style="margin-left:11%; margin-top: 1em">The following
2801 program replaces each comment by a single space in a C
2802 program file,</p>
2803
2804 <table width="100%" border="0" rules="none" frame="void"
2805 cellspacing="0" cellpadding="0">
2806 <tr valign="top" align="left">
2807 <td width="8%"></td>
2808 <td width="7%"></td>
2809 <td width="8%">
2810
2811
2812 <p>BEGIN {</p></td>
2813 <td width="77%">
2814 </td></tr>
2815 <tr valign="top" align="left">
2816 <td width="8%"></td>
2817 <td width="7%"></td>
2818 <td width="8%">
2819
2820
2821 <p>RS = &quot;/\*([^*]|\*+[^/*])*\*+/&quot;</p></td>
2822 <td width="77%">
2823 </td></tr>
2824 <tr valign="top" align="left">
2825 <td width="8%"></td>
2826 <td width="7%">
2827 </td>
2828 <td width="8%">
2829 </td>
2830 <td width="77%">
2831
2832
2833 <p># comment is record separator</p></td></tr>
2834 <tr valign="top" align="left">
2835 <td width="8%"></td>
2836 <td width="7%"></td>
2837 <td width="8%">
2838
2839
2840 <p>ORS = &quot; &quot;</p></td>
2841 <td width="77%">
2842 </td></tr>
2843 <tr valign="top" align="left">
2844 <td width="8%"></td>
2845 <td width="7%"></td>
2846 <td width="8%">
2847
2848
2849 <p>getline hold</p></td>
2850 <td width="77%">
2851 </td></tr>
2852 </table>
2853
2854 <p style="margin-left:11%;">}</p>
2855
2856 <p style="margin-left:11%; margin-top: 1em">{ print hold ;
2857 hold = $0 }</p>
2858
2859 <p style="margin-left:11%; margin-top: 1em">END { printf
2860 &quot;%s&quot; , hold }</p>
2861
2862 <p style="margin-left:11%; margin-top: 1em">Buffering one
2863 record is needed to avoid terminating the last record with a
2864 space.</p>
2865
2866 <p style="margin-left:11%; margin-top: 1em">With
2867 <b>lmawk</b>, the following are all equivalent,</p>
2868
2869 <table width="100%" border="0" rules="none" frame="void"
2870 cellspacing="0" cellpadding="0">
2871 <tr valign="top" align="left">
2872 <td width="8%"></td>
2873 <td width="92%">
2874
2875
2876 <p>x ~ /a\+b/ x ~ &quot;a\+b&quot; x ~
2877 &quot;a\\+b&quot;</p> </td></tr>
2878 </table>
2879
2880 <p style="margin-left:11%; margin-top: 1em">The strings get
2881 scanned twice, once as string and once as regular
2882 expression. On the string scan, <b>lmawk</b> ignores the
2883 escape on non-escape characters while the AWK book advocates
2884 <i>\c</i> be recognized as <i>c</i> which necessitates the
2885 double escaping of meta-characters in strings. Posix
2886 explicitly declines to define the behavior which passively
2887 forces programs that must run under a variety of awks to use
2888 the more portable but less readable, double escape.</p>
2889
2890 <p style="margin-left:11%; margin-top: 1em">Posix AWK does
2891 not recognize &quot;/dev/std{out,err}&quot; or \x hex escape
2892 sequences in strings. Unlike ANSI C, <b>lmawk</b> limits the
2893 number of digits that follows \x to two as the current
2894 implementation only supports 8 bit characters. The built-in
2895 <b>fflush</b> first appeared in a recent (1993) AT&amp;T awk
2896 released to netlib, and is not part of the posix standard.
2897 Aggregate deletion with <b>delete</b> <i>array</i> is not
2898 part of the posix standard.</p>
2899
2900 <p style="margin-left:11%; margin-top: 1em">Posix
2901 explicitly leaves the behavior of <b>FS</b> = &quot;&quot;
2902 undefined, and mentions splitting the record into characters
2903 as a possible interpretation, but currently this use is not
2904 portable across implementations.</p>
2905
2906 <p style="margin-left:11%; margin-top: 1em">Finally, here
2907 is how <b>lmawk</b> handles exceptional cases not discussed
2908 in the AWK book or the Posix draft. It is unsafe to assume
2909 consistency across awks and safe to skip to the next
2910 section.</p>
2911
2912 <p style="margin-left:22%; margin-top: 1em">substr(s, i, n)
2913 returns the characters of s in the intersection of the
2914 closed interval [1, length(s)] and the half-open interval
2915 [i, i+n). When this intersection is empty, the empty string
2916 is returned; so substr(&quot;ABC&quot;, 1, 0) = &quot;&quot;
2917 and substr(&quot;ABC&quot;, &minus;4, 6) =
2918 &quot;A&quot;.</p>
2919
2920 <p style="margin-left:22%; margin-top: 1em">Every string,
2921 including the empty string, matches the empty string at the
2922 front so, s ~ // and s ~ &quot;&quot;, are always 1 as is
2923 match(s, //) and match(s, &quot;&quot;). The last two set
2924 <b>RLENGTH</b> to 0.</p>
2925
2926 <p style="margin-left:22%; margin-top: 1em">index(s, t) is
2927 always the same as match(s, t1) where t1 is the same as t
2928 with metacharacters escaped. Hence consistency with match
2929 requires that index(s, &quot;&quot;) always returns 1. Also
2930 the condition, index(s,t) != 0 if and only t is a substring
2931 of s, requires index(&quot;&quot;,&quot;&quot;) = 1.</p>
2932
2933 <p style="margin-left:22%; margin-top: 1em">If getline
2934 encounters end of file, getline var, leaves var unchanged.
2935 Similarly, on entry to the <b>END</b> actions, <b>$0</b>,
2936 the fields and <b>NF</b> have their value unaltered from the
2937 last record.</p>
2938
2939 <h2>SEE ALSO
2940 <a name="SEE ALSO"></a>
2941 </h2>
2942
2943
2944
2945 <p style="margin-left:11%; margin-top: 1em"><i>egrep</i>(1),
2946 <i>mawk</i>(1)</p>
2947
2948 <p style="margin-left:11%; margin-top: 1em">Aho, Kernighan
2949 and Weinberger, <i>The AWK Programming Language</i>,
2950 Addison-Wesley Publishing, 1988, (the AWK book), defines the
2951 language, opening with a tutorial and advancing to many
2952 interesting programs that delve into issues of software
2953 design and analysis relevant to programming in any
2954 language.</p>
2955
2956 <p style="margin-left:11%; margin-top: 1em"><i>The GAWK
2957 Manual</i>, The Free Software Foundation, 1991, is a
2958 tutorial and language reference that does not attempt the
2959 depth of the AWK book and assumes the reader may be a novice
2960 programmer. The section on AWK arrays is excellent. It also
2961 discusses Posix requirements for AWK.</p>
2962
2963 <h2>BUGS
2964 <a name="BUGS"></a>
2965 </h2>
2966
2967
2968 <p style="margin-left:11%; margin-top: 1em"><b>lmawk</b>
2969 cannot handle ascii NUL \0 in the source or data files. You
2970 can output NUL using printf with %c, and any other 8 bit
2971 character is acceptable input.</p>
2972
2973 <p style="margin-left:11%; margin-top: 1em"><b>lmawk</b>
2974 implements printf() and sprintf() using the C library
2975 functions, printf and sprintf, so full ANSI compatibility
2976 requires an ANSI C library. In practice this means the h
2977 conversion qualifier may not be available. Also <b>lmawk</b>
2978 inherits any bugs or limitations of the library
2979 functions.</p>
2980
2981 <p style="margin-left:11%; margin-top: 1em">Implementors of
2982 the AWK language have shown a consistent lack of imagination
2983 when naming their programs.</p>
2984
2985 <h2>AUTHOR
2986 <a name="AUTHOR"></a>
2987 </h2>
2988
2989
2990 <p style="margin-left:11%; margin-top: 1em"><b>mawk:</b>
2991 Mike Brennan (brennan@whidbey.com).</p>
2992
2993 <p style="margin-left:11%; margin-top: 1em"><b>libmawk
2994 extensions:</b> Tibor Palinkas (libmawk@igor2.repo.hu).</p>
2995 <hr>
2996 </body>
2997 </html>
0 <HTML>
1 <BODY>
2 <H1> libmawk numerics </H1>
3 Mawk implemented all numeric calculations using double precision floating
4 point numbers. Libmawk has a compile-time option for using different
5 types for numerics, with the following choices available:
6 <UL>
7 <LI> double (default)
8 <LI> int
9 </UL>
10
11 <H2> handling exceptions and NaNs </H2>
12 Mawk was geared towards catching floating point errors (such as
13 division by zero or log(-1)) and report a runtime error as soon as
14 possible. Libmawk, targeting embedded script application, should minimize
15 runtime errors by providing means for the script to check for them and
16 recover.
17 <p>
18 There are multiple approaches for handling suc errors. A design decision
19 has been made for exclusively using NaN (<I>Not a Number</I>) - on platforms where it is not
20 implemented by the FPU or by libc, it's emulated. NaN support shall work
21 the same way for all available numeric types.
22 <p>
23 Rules about NaN are few and simple:
24 <UL>
25 <LI> 1. NaN should be a sepcial value that can not be mistaken for a valid number by the script
26 <LI> 2. math library calls (e.g. log()) should return NaN for invalid input; library calls shall accept NaN as input and return NaN as output
27 <LI> 3. other library functions should handle NaN properly (i.e. printf %f or print shall write "nan" and a string-to-number conversion shall be able to understand "nan")
28 <LI> 4. if any input of a calculation is NaN, the result shall be NaN (e.g. NaN+1 is NaN); such calculations never cause runtime error
29 <LI> 5. 1/0, 0/0 and similar corner cases are all NaN - there is no inf
30 <LI> 6. the only runtime error that may be caused by NaNs is when a conditional jump depends on a NaN (e.g. if (nan) {})
31 <LI> 7. isnan(x) returns 1 if x is NaN.
32 </UL>
33 <p>
34 In practice this means a block of numeric calculations can be done safely,
35 without checking any input or intermediate results. At the end of the
36 block the result(s) shall be checked with isnan(). As long as the results
37 (even indirectly) depend on an input or intermediate result that is NaN,
38 the result is guaranteed to be NaN too, without the risk of a runtime error.
39
40
41 <H2> Implementation </H2>
42 <H3> type: double </H3>
43 If the system has FPE, it's disabled. If the system does not have native
44 NaN, a special NaN value is defined (using HUGE_VAL) and
45 before each operation all inputs are checked for NaN to make sure the
46 output is NaN too. On systems with NaN
47 ### TODO: inf? ###
48
49 <H3> type: int </h3>
50 ### TODO: ###
51
52 <H3> division by zero </H3>
53 Before divisions input is always checked and division by zero is
54 replaced by a NaN. The same mechanism is in place for all numeric types.
55
56
57 </BODY>
58 </HTML>
0 <HTML>
1 <BODY>
2 <H1> Portability with scconfig </H1>
3
4 Libmawk is configured using an embedded copy of scconfig. In a distribution
5 tarball, it's a snapshot of scconfig; in an svn repository it is an
6 svn external, which guarantees libmawk is using the latest version
7 of scconfig.
8 <P>
9 Scconfig is a self-contained project configuration tool which depends
10 only on Make and an ANSI (C89) C compiler. Scconfig can test different
11 things on a system, often by compiling and running test programs. Besides
12 saving test results in a text file, it can also generate text files like
13 Makefiles or include files with content depending on those test results.
14 <P>
15 There are artificial limits on portability tho. While in theory it is
16 possible to scretch the system so that it really works on all operating
17 systems ever existed, or at least on all UNIX-like systems, it is not the
18 goal. This decision is a trade-off between portability and maintainability.
19 Also between portability and code size (or bloat). The artificial limits are:
20 <UL>
21 <LI> a C compiler that fully supports ANSI (C89) C is required
22 <LI> make supporting traditional Makefiles is required
23 <LI> no efforts for systems older than 80s UNIX systems; for example libmawk depends on pipe(2), and if it is missing, some of the functionality will be missing
24 <LI> mawk had support for DOS - this is removed, because
25 <UL>
26 <LI> it was already marked as somewhat obsolete or at least untested in version 1.3.3, which is the base for libmawk; documentation suggested users should use an older version of mawk on DOS
27 <LI> since DOS poses drastic limitation on memory, and mawk seemed to be a memory hog, it is hard to believe someone would actually write an application that would share memory with libmawk and still do something useful - and after all, the purpose of libmawk is exactly embedding awk in applications
28 <LI> too many #ifdefs scattered the code for supporting DOS
29 </UL>
30 </UL>
31 <P>
32 Libmawk 0.9.7 is reported to configure and compile on the
33 following systems:
34 <TABLE border=1>
35 <TR><TD> system <TD> compiles
36 <BR> out of
37 <BR> the box <TD> FPE problems <TD> awklib<BR> test <TD> binary save/load<BR> save/load
38 <TR><TD>[i386] GNU/Linux <TD> yes <TD> no <TD> ok <TD> ok
39 <TR><TD>[amd64] GNU/Linux <TD> yes <TD> no <TD> ok <TD> ok
40 <TR><TD>[i386] Minix <TD> <TD> <TD> <TD>
41 <TR><TD>[i386] NetBSD 4.0 <TD> yes <TD> no <TD> ok <TD> ok
42 <TR><TD>[i386] open
43 solaris 5.11 <TD> <TD> <TD> <TD>
44 <TR><TD>[i386] OpenBSD 5.0<TD> yes <TD> no <TD> ok <TD> ok
45 <TR><TD>[i386] FreeBSD 9.0<TD> yes <TD> no <TD> ok <TD> ok
46 <TR><TD>[IP22] IRIX 5.3 <TD> no <TD> minor <TD> <TD> doesn't work
47 <TR><TD>[i386] Dragonfly
48 BSD 2.10 <TD> yes <TD> no <TD> ok <TD> ok
49
50 </table>
51
52
53 <P>
54 Libmawk 0.9.6 is reported to configure and compile on the
55 following systems:
56 <TABLE border=1>
57 <TR><TD> system <TD> compiles
58 <BR> out of
59 <BR> the box <TD> FPE problems <TD> awklib<BR> test <TD> binary save/load<BR> save/load
60 <TR><TD>i386 GNU/Linux <TD> yes <TD> no <TD> ok <TD> ok
61 <TR><TD>amd64 GNU/Linux <TD> yes <TD> no <TD> ok <TD> ok
62 <TR><TD>i386 Minix <TD> yes <TD> yes <TD> ok <TD> ok
63 <TR><TD>i386 NetBSD 4.0 <TD> yes <TD> yes <TD> ok <TD> ok
64 <TR><TD>i386 open
65 solaris 5.11 <TD> yes <TD> no <TD> ok <TD> ok
66 <TR><TD>i386 OpenBSD 5.0<TD> yes <TD> yes <TD> ok <TD> ok
67 <TR><TD>i386 FreeBSD 9.0<TD> yes <TD> yes <TD> ok <TD> ok
68 <TR><TD>IP22 IRIX 5.3 <TD> yes <TD> no <TD> ok <TD> doesn't work
69 <TR><TD>i386 Dragonfly
70 BSD 2.10 <TD> yes <TD> yes <TD> ok <TD> ok
71
72 </table>
73
74 </BODY>
75 </HTML>
0 <HTML>
1 <BODY>
2 <H1> Semi-dependency on GNU utils </H1>
3 Some of the features depend on GNU-specific implementation of standard
4 software. These are all semi-dependencies, which means if an user doesn't
5 have GNU software on a system, it is still possible for him/her to compile
6 libmawk. Unfortunately editing some parts of the source on such a system
7 would not result in the desired updates. Obviously a main goal is to
8 minimize this sort of dependency, but sometimes it is very hard or impossible
9 to avoid. This document describes these dependencies explaining the tradeoff
10 and the ways around.
11 <H2> 1. Bison </H2>
12 <H3> 1.1. Rationale </H3>
13 There are four GNU-specific features in use:
14 <UL>
15 <LI> %pure-parser for getting a reentrant parser
16 <LI> %parse-param to pass mawk state around to avoid global variables
17 <LI> %lex-param for the same reason as %parse-param
18 <LI> --name-prefix to avoid namespace pollution
19 </UL>
20 The first three features are critical for having a reentrant/thread safe
21 libmawk. Without those three, there could be only one mawk context in
22 an application, or at least parsing more than one script in the same
23 time would cause both context mangled.
24 <P>
25 The fourth feature, --name-prefix helps avoiding namespace pollution -
26 the application may have its own parsers with or without name prefixing,
27 and libmawk shouldn't collide with those.
28
29 <H3> 1.2. effects, restrictions </H3>
30 Scconfig detects presence of bison; in case bison is not installed,
31 Makefile.conf is generated in a way that bison is never run. Output
32 of bison is included in the source tree (parse.c/parse.h).
33 <P>
34 <B>Not having bison on a systam means editing parse.y will not
35 update the actual parser code in parse.c</B>.
36
37 <H3> 1.3. how to bypass </H3>
38 It is possible to use traditional yacc for compiling parse.y. Besides
39 editing Makefile.conf and parse.y for removing those 4 features,
40 scan.c/scan.h should be edited too, because arguments for the scanner
41 depends on these settings. A global variable for the mawk context for
42 the script currently being parsed should be introduced. Actions should
43 be made to ensure no concurrent loading of scripts is possible.
44
45 <H2> 2. Makefile.dep needs gcc </H2>
46 <H3> 2.1. Rationale </H3>
47 Source file dependencies are generated using <I>gcc -MM</I> and are
48 stored in Makefile.dep shipped with the source package.
49
50 <H3> 2.2. effects, restrictions </H3>
51 After changing #include lines in the source, running <I>make depend</I>
52 will not update Makefile.dep but will zap it.
53
54 <H3> 2.3. how to bypass </H3>
55 It is easily possible to keep Makefile.dep in sync by hand. Another option
56 is to ignore Makefile.dep and run <I>make clean</I> before compilation.
57
58 </BODY>
59 </HTML>
0 # --- configuration part --
1 SRC=src/
2 BIN=src/
3
4 # - generic configuration -
5 # what cflags to use to compile scconfig
6 USER_CFLAGS = -g -DGENCALL
7
8 # what ldflags to use to link scconfig
9 USER_LDFLAGS =
10
11 # in case hooks.c needs to link to something local
12 USER_OBJS =
13
14 # what to build - a ./configure
15 all: configure
16
17 # This line imports scconfig core and default tests
18 include src/default/Makefile.plugin
19
20 #
21 # - PLUGINS -
22 #
23 # Comment this line if you are not interested in c99 features
24 #include src/c99/Makefile.plugin
25
26 # Comment this line if you do not need script libs to be detected
27 #include src/scripts/Makefile.plugin
28
29 # Comment this line if you do not need parser libs to be detected
30 #include src/parser/Makefile.plugin
31
32 # Comment this line if you do not need to detect parser generators
33 include src/parsgen/Makefile.plugin
34
35 # Comment this line if you do not need math related libs
36 include src/math/Makefile.plugin
37
38 # Comment this line if you do not need socket/networking
39 #include src/socket/Makefile.plugin
40
41 # Comment this line if you do not need tmpasm (templating)
42 include src/tmpasm/Makefile.plugin
43
44 # --- you shouldn't edit the lines below ---
45 OBJS = $(USER_OBJS) hooks.o $(DEFAULT_OBJS) $(SCRIPT_OBJS) $(PARSER_OBJS) $(TMPASM_OBJS) $(C99_OBJS) $(PARSGEN_OBJS) $(MATH_OBJS) $(SOCKET_OBJS)
46 CFLAGS = $(USER_CFLAGS) $(DEFAULT_CFLAGS) $(SCRIPT_CFLAGS) $(PARSER_CFLAGS) $(TMPASM_CFLAGS) $(C99_CFLAGS) $(PARSGEN_CFLAGS) $(MATH_CFLAGS) $(SOCKET_CFLAGS) -Isrc/default
47 LDFLAGS = $(USER_LDFLAGS) $(DEFAULT_LDFLAGS) $(SCRIPT_LDFLAGS) $(PARSER_LDFLAGS) $(TMPASM_LDFLAGS) $(C99_LDFLAGS) $(PARSGEN_LDFLAGS) $(MATH_LDFLAGS) $(SOCKET_LDFLAGS)
48
49 configure: $(OBJS)
50 $(CC) -o configure $(OBJS)
51
52 clean:
53 -rm $(OBJS) configure
54
0 #include <string.h>
1 #include "arg.h"
2 #include "log.h"
3 #include "dep.h"
4 #include "db.h"
5 #include "tmpasm_scconfig.h"
6
7 #define VER1 "1"
8 #define VER2 "0"
9 #define VER3 "0"
10
11 static void help(void)
12 {
13 printf("./configure: configure libmawk.\n");
14 printf("\n");
15 printf("Usage: ./configure [options]\n");
16 printf("\n");
17 printf("options are:\n");
18 printf(" --prefix=path change installation prefix from /usr/local to path\n");
19 printf(" --debug build full debug version (-g -O0, extra asserts)\n");
20 printf(" --profile build profiling version if available (-pg)\n");
21 printf(" --symbols include symbols (add -g, but no -O0 or extra asserts)\n");
22 printf(" --numeric=int change the internal numeric type (default is double)\n");
23 printf("\n");
24 }
25
26 /* Runs when a custom command line argument is found
27 returns true if no furhter argument processing should be done */
28 int hook_custom_arg(const char *key, const char *value)
29 {
30 if (strcmp(key, "prefix") == 0) {
31 put("/local/prefix", value);
32 return 1;
33 }
34 if (strcmp(key, "debug") == 0) {
35 put("/local/debug", strue);
36 return 1;
37 }
38 if (strcmp(key, "symbols") == 0) {
39 put("/local/symbols", strue);
40 return 1;
41 }
42 if (strcmp(key, "profile") == 0) {
43 put("/local/profile", strue);
44 return 1;
45 }
46 if (strcmp(key, "numeric") == 0) {
47 if ((strcmp(value, "int") == 0) || (strcmp(value, "double") == 0))
48 put("/local/numeric", value);
49 else {
50 fprintf(stderr, "Error: invalid numeric format. Must be int or double\n");
51 exit(1);
52 }
53 return 1;
54 }
55 if (strcmp(key, "help") == 0) {
56 help();
57 exit(0);
58 }
59
60 return 0;
61 }
62
63
64 /* Runs before anything else */
65 int hook_preinit()
66 {
67 return 0;
68 }
69
70 /* Runs after initialization */
71 int hook_postinit()
72 {
73 db_mkdir("/local");
74
75 /* defaults */
76 put("/local/prefix", "/usr/local");
77 put("/local/debug", sfalse);
78 put("/local/symbols", sfalse);
79 put("/local/profile", sfalse);
80
81 report("Configuring libmawk.\n");
82 logprintf(0, "Configuring libmawk.\n");
83 return 0;
84 }
85
86 /* Runs after all arguments are read and parsed */
87 int hook_postarg()
88 {
89 if (get("/local/numeric") == NULL)
90 put("/local/numeric", "double");
91 return 0;
92 }
93
94 /* Runs when things should be detected for the host system */
95 int hook_detect_host()
96 {
97 return 0;
98 }
99
100 /* Runs when things should be detected for the target system */
101 int hook_detect_target()
102 {
103 put("/local/version", VER1 "." VER2 "." VER3);
104 put("/local/version/1", VER1);
105 put("/local/version/2", VER2);
106 put("/local/version/3", VER3);
107
108 /* if there was no custom requirement from the command line, run all requirements in non-fatal mode */
109 if (num_custom_reqs < 1) {
110 if (istrue(get("/local/debug"))) {
111 require("cc/argstd/pedantic", 0, 0);
112 require("cc/argstd/ansi", 0, 0);
113 require("cc/argstd/Wall", 0, 0);
114 append("/target/cc/cflags", " -O0 ");
115 append("/target/cc/cflags", get("cc/argstd/ansi"));
116 append("/target/cc/cflags", " ");
117 append("/target/cc/cflags", get("cc/argstd/pedantic"));
118 append("/target/cc/cflags", " ");
119 append("/target/cc/cflags", get("cc/argstd/Wall"));
120 }
121 else
122 append("/target/cc/cflags", " -O3 ");
123 if (istrue(get("/local/debug")) || istrue(get("/local/symbols")))
124 append("/target/cc/cflags", " -g ");
125 if (istrue(get("/local/profile"))) {
126 require("cc/argstd/pg", 0, 0);
127 require("cc/argstd/no-pie", 0, 0);
128 append("/target/cc/cflags", " ");
129 append("/target/cc/cflags", get("cc/argstd/pg"));
130 append("/target/cc/cflags", " ");
131 append("/target/cc/cflags", get("cc/argstd/no-pie"));
132 }
133
134
135 require("cc/cc", 0, 1);
136 require("cc/fpic", 0, 1);
137 require("cc/soname", 0, 0);
138 require("cc/rdynamic", 0, 0);
139 require("fstools/chmodx", 0, 1);
140 require("fstools/cp", 0, 1);
141 require("fstools/rm", 0, 1);
142 require("fstools/ln", 0, 1);
143 require("fstools/mkdir", 0, 1);
144 require("sys/types/size_t/includes", 0, 0);
145 require("libs/fs/realpath/presents", 0, 0);
146 require("libs/env/putenv", 0, 1);
147 require("libs/io/pipe/presents", 0, 0);
148 require("libs/math/cc/log/*", 0, 1);
149 require("libs/math/nan/*", 0, 0);
150 require("libs/math/isnan/*", 0, 0);
151 require("libs/math/nanop/*", 0, 0);
152
153 require("parsgen/bison", 0, 0);
154 printf("Numeric format: %s\n", get("/local/numeric"));
155 }
156 return 0;
157 }
158
159 /* Runs after detection hooks, should generate the output (Makefiles, etc.) */
160 int hook_generate()
161 {
162 printf("Generating libmawk/Makefile... ");
163 fflush(stdout);
164 if (tmpasm("../src/libmawk", "Makefile.conf.in", "Makefile.conf") == 0)
165 printf("OK\n");
166 else
167 printf("failed\n");
168
169 printf("Generating libmawk/conf.h... ");
170 fflush(stdout);
171 if (tmpasm("../src/libmawk", "conf.h.in", "conf.h") == 0)
172 printf("OK\n");
173 else
174 printf("failed\n");
175
176 printf("Generating awklib/Makefile... ");
177 fflush(stdout);
178 if (tmpasm("../src/awklib", "Makefile.in", "Makefile") == 0)
179 printf("OK\n");
180 else
181 printf("failed\n");
182
183 printf("Generating awklib/regression/Makefile... ");
184 fflush(stdout);
185 db_mkdir("/local");
186 if (tmpasm("../src/awklib/regression", "Makefile.in", "Makefile") == 0)
187 printf("OK\n");
188 else
189 printf("failed\n");
190
191 return 0;
192 }
193
194 /* Runs before everything is uninitialized */
195 void hook_preuninit()
196 {
197 }
198
199 /* Runs at the very end, when everything is already uninitialized */
200 void hook_postuninit()
201 {
202 }
203
0 DEFAULT_NOMAIN_OBJS = \
1 $(BIN)/default/find_cc.o \
2 $(BIN)/default/lib_compile.o \
3 $(BIN)/default/lib_uniqinc.o \
4 $(BIN)/default/lib_file.o \
5 $(BIN)/default/lib_try.o \
6 $(BIN)/default/str.o \
7 $(BIN)/default/ht.o \
8 $(BIN)/default/log.o \
9 $(BIN)/default/arg.o \
10 $(BIN)/default/db.o \
11 $(BIN)/default/dep.o \
12 $(BIN)/default/deps_default.o \
13 $(BIN)/default/find_libs.o \
14 $(BIN)/default/find_fscalls.o \
15 $(BIN)/default/find_printf.o \
16 $(BIN)/default/find_proc.o \
17 $(BIN)/default/find_fstools.o \
18 $(BIN)/default/find_uname.o \
19 $(BIN)/default/find_target.o \
20 $(BIN)/default/find_thread.o \
21 $(BIN)/default/find_io.o \
22 $(BIN)/default/find_time.o \
23 $(BIN)/default/find_types.o \
24 $(BIN)/default/find_signal.o \
25 $(BIN)/default/find_environ.o \
26 $(BIN)/default/regex.o \
27 $(BIN)/default/lib_filelist.o \
28 $(BIN)/default/lib_srctree.o \
29 $(BIN)/default/lib_pkg_config.o \
30 $(BIN)/default/find_str.o \
31 $(BIN)/default/find_sys.o
32
33 DEFAULT_MAIN_OBJS = \
34 $(BIN)/default/main.o \
35 $(BIN)/default/main_custom_args.o \
36 $(BIN)/default/main_lib.o
37
38 DEFAULT_OBJS = $(DEFAULT_NOMAIN_OBJS) $(DEFAULT_MAIN_OBJS)
39
40 $(BIN)/default/lib_compile.o: $(SRC)/default/lib_compile.c $(SRC)/default/dep.h $(SRC)/default/libs.h
41 $(CC) $(CFLAGS) -c $(SRC)/default/lib_compile.c -o $(BIN)/default/lib_compile.o
42
43 $(BIN)/default/lib_file.o: $(SRC)/default/lib_file.c $(SRC)/default/dep.h $(SRC)/default/libs.h
44 $(CC) $(CFLAGS) -c $(SRC)/default/lib_file.c -o $(BIN)/default/lib_file.o
45
46 $(BIN)/default/lib_try.o: $(SRC)/default/lib_try.c $(SRC)/default/log.h $(SRC)/default/dep.h $(SRC)/default/libs.h
47 $(CC) $(CFLAGS) -c $(SRC)/default/lib_try.c -o $(BIN)/default/lib_try.o
48
49 $(BIN)/default/str.o: $(SRC)/default/str.c $(SRC)/default/dep.h $(SRC)/default/libs.h
50 $(CC) $(CFLAGS) -c $(SRC)/default/str.c -o $(BIN)/default/str.o
51
52 $(BIN)/default/ht.o: $(SRC)/default/ht.c $(SRC)/default/dep.h $(SRC)/default/libs.h
53 $(CC) $(CFLAGS) -c $(SRC)/default/ht.c -o $(BIN)/default/ht.o
54
55 $(BIN)/default/log.o: $(SRC)/default/log.c $(SRC)/default/dep.h $(SRC)/default/libs.h
56 $(CC) $(CFLAGS) -c $(SRC)/default/log.c -o $(BIN)/default/log.o
57
58 $(BIN)/default/arg.o: $(SRC)/default/arg.c $(SRC)/default/dep.h $(SRC)/default/libs.h
59 $(CC) $(CFLAGS) -c $(SRC)/default/arg.c -o $(BIN)/default/arg.o
60
61 $(BIN)/default/db.o: $(SRC)/default/db.c $(SRC)/default/dep.h $(SRC)/default/libs.h
62 $(CC) $(CFLAGS) -c $(SRC)/default/db.c -o $(BIN)/default/db.o
63
64 $(BIN)/default/dep.o: $(SRC)/default/dep.c $(SRC)/default/dep.h $(SRC)/default/libs.h
65 $(CC) $(CFLAGS) -c $(SRC)/default/dep.c -o $(BIN)/default/dep.o
66
67 $(BIN)/default/deps_default.o: $(SRC)/default/deps_default.c $(SRC)/default/dep.h $(SRC)/default/libs.h
68 $(CC) $(CFLAGS) -c $(SRC)/default/deps_default.c -o $(BIN)/default/deps_default.o
69
70 $(BIN)/default/find_libs.o: $(SRC)/default/find_libs.c $(SRC)/default/dep.h $(SRC)/default/libs.h
71 $(CC) $(CFLAGS) -c $(SRC)/default/find_libs.c -o $(BIN)/default/find_libs.o
72
73 $(BIN)/default/find_fscalls.o: $(SRC)/default/find_fscalls.c $(SRC)/default/dep.h $(SRC)/default/libs.h
74 $(CC) $(CFLAGS) -c $(SRC)/default/find_fscalls.c -o $(BIN)/default/find_fscalls.o
75
76 $(BIN)/default/find_signal.o: $(SRC)/default/find_signal.c $(SRC)/default/dep.h $(SRC)/default/libs.h
77 $(CC) $(CFLAGS) -c $(SRC)/default/find_signal.c -o $(BIN)/default/find_signal.o
78
79 $(BIN)/default/find_printf.o: $(SRC)/default/find_printf.c $(SRC)/default/dep.h $(SRC)/default/libs.h
80 $(CC) $(CFLAGS) -c $(SRC)/default/find_printf.c -o $(BIN)/default/find_printf.o
81
82 $(BIN)/default/find_proc.o: $(SRC)/default/find_proc.c $(SRC)/default/dep.h $(SRC)/default/libs.h
83 $(CC) $(CFLAGS) -c $(SRC)/default/find_proc.c -o $(BIN)/default/find_proc.o
84
85 $(BIN)/default/find_fstools.o: $(SRC)/default/find_fstools.c $(SRC)/default/dep.h $(SRC)/default/libs.h
86 $(CC) $(CFLAGS) -c $(SRC)/default/find_fstools.c -o $(BIN)/default/find_fstools.o
87
88 $(BIN)/default/find_uname.o: $(SRC)/default/find_uname.c $(SRC)/default/dep.h $(SRC)/default/libs.h
89 $(CC) $(CFLAGS) -c $(SRC)/default/find_uname.c -o $(BIN)/default/find_uname.o
90
91 $(BIN)/default/find_target.o: $(SRC)/default/find_target.c $(SRC)/default/dep.h $(SRC)/default/libs.h
92 $(CC) $(CFLAGS) -c $(SRC)/default/find_target.c -o $(BIN)/default/find_target.o
93
94 $(BIN)/default/regex.o: $(SRC)/default/regex.c $(SRC)/default/dep.h $(SRC)/default/libs.h
95 $(CC) $(CFLAGS) -c $(SRC)/default/regex.c -o $(BIN)/default/regex.o
96
97 $(BIN)/default/lib_filelist.o: $(SRC)/default/lib_filelist.c $(SRC)/default/dep.h $(SRC)/default/libs.h
98 $(CC) $(CFLAGS) -c $(SRC)/default/lib_filelist.c -o $(BIN)/default/lib_filelist.o
99
100 $(BIN)/default/lib_srctree.o: $(SRC)/default/lib_srctree.c $(SRC)/default/dep.h $(SRC)/default/libs.h
101 $(CC) $(CFLAGS) -c $(SRC)/default/lib_srctree.c -o $(BIN)/default/lib_srctree.o
102
103 $(BIN)/default/lib_pkg_config.o: $(SRC)/default/lib_pkg_config.c $(SRC)/default/dep.h $(SRC)/default/libs.h
104 $(CC) $(CFLAGS) -c $(SRC)/default/lib_pkg_config.c -o $(BIN)/default/lib_pkg_config.o
105
106 $(BIN)/default/lib_uniqinc.o: $(SRC)/default/lib_uniqinc.c $(SRC)/default/dep.h $(SRC)/default/libs.h
107 $(CC) $(CFLAGS) -c $(SRC)/default/lib_uniqinc.c -o $(BIN)/default/lib_uniqinc.o
108
109 $(BIN)/default/find_sys.o: $(SRC)/default/find_sys.c $(SRC)/default/dep.h $(SRC)/default/libs.h
110 $(CC) $(CFLAGS) -c $(SRC)/default/find_sys.c -o $(BIN)/default/find_sys.o
111
112 $(BIN)/default/find_str.o: $(SRC)/default/find_str.c $(SRC)/default/dep.h $(SRC)/default/libs.h
113 $(CC) $(CFLAGS) -c $(SRC)/default/find_str.c -o $(BIN)/default/find_str.o
114
115 $(BIN)/default/find_cc.o: $(SRC)/default/find_cc.c $(SRC)/default/dep.h $(SRC)/default/libs.h
116 $(CC) $(CFLAGS) -c $(SRC)/default/find_cc.c -o $(BIN)/default/find_cc.o
117
118 $(BIN)/default/find_environ.o: $(SRC)/default/find_environ.c $(SRC)/default/dep.h $(SRC)/default/libs.h
119 $(CC) $(CFLAGS) -c $(SRC)/default/find_environ.c -o $(BIN)/default/find_environ.o
120
121 $(BIN)/default/find_io.o: $(SRC)/default/find_io.c $(SRC)/default/dep.h $(SRC)/default/libs.h
122 $(CC) $(CFLAGS) -c $(SRC)/default/find_io.c -o $(BIN)/default/find_io.o
123
124 $(BIN)/default/find_time.o: $(SRC)/default/find_time.c $(SRC)/default/dep.h $(SRC)/default/libs.h
125 $(CC) $(CFLAGS) -c $(SRC)/default/find_time.c -o $(BIN)/default/find_time.o
126
127 $(BIN)/default/find_types.o: $(SRC)/default/find_types.c $(SRC)/default/dep.h $(SRC)/default/libs.h
128 $(CC) $(CFLAGS) -c $(SRC)/default/find_types.c -o $(BIN)/default/find_types.o
129
130 $(BIN)/default/main.o: $(SRC)/default/main.c $(SRC)/default/dep.h $(SRC)/default/libs.h Makefile
131 $(CC) $(CFLAGS) -c $(SRC)/default/main.c -o $(BIN)/default/main.o
132
133 $(BIN)/default/main_custom_args.o: $(SRC)/default/main_custom_args.c
134 $(CC) $(CFLAGS) -c $(SRC)/default/main_custom_args.c -o $(BIN)/default/main_custom_args.o
135
136 $(BIN)/default/main_lib.o: $(SRC)/default/main_lib.c
137 $(CC) $(CFLAGS) -c $(SRC)/default/main_lib.c -o $(BIN)/default/main_lib.o
138
139 $(BIN)/default/find_thread.o: $(SRC)/default/find_thread.c $(SRC)/default/dep.h $(SRC)/default/libs.h
140 $(CC) $(CFLAGS) -c $(SRC)/default/find_thread.c -o $(BIN)/default/find_thread.o
0 /*
1 scconfig - command line argument processing
2 Copyright (C) 2009..2012 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include "db.h"
25 #include "arg.h"
26 #include "dep.h"
27 #include "log.h"
28 #include "libs.h"
29
30 argtbl_t main_argument_table[] = {
31 {"import", NULL, import_args, "Import saved config (sub)tree"},
32 {"target", "/arg/sys/target", NULL, "set cross compilation target (prefix)"},
33 {"target-name", "/arg/sys/target-name", NULL, "set cross compilation target (system name)"},
34 {"target-shell","/arg/sys/target-shell",NULL, "set the shell on cross compilation target"},
35 {"emu", "/arg/sys/emu", NULL, "emulator for testing cross compiled executables with"},
36 {"pkg-config", "/arg/sys/pkg-config", NULL, "path to pkg-config to use"},
37 {"pkg-config-zap","/arg/sys/pkg-config-zap",NULL, "ignore pkg-config results by this regex pattern"},
38
39 /* wildcard rules for icl() control */
40 {"^ldflags/", NULL, import_icl, NULL},
41 {"^cflags/", NULL, import_icl, NULL},
42 {"^includes/", NULL, import_icl, NULL},
43 {"^prefix/", NULL, import_icl, NULL},
44
45 /* the followings are autoconf compatibility translations */
46 {"CC", "/arg/cc/cc", NULL, "Force using a C compiler (command line)"},
47 {"CFLAGS", "/arg/cc/cflags", NULL, "Force using a CFLAGS for C compilation"},
48 {"LDFLAGS", "/arg/cc/ldflags", NULL, "Force using a LDFLAGS for linking"},
49 {"LDL", "/arg/libs/ldl", NULL, "Force using -ldl string"},
50
51 {"gpmi-prefix", "/arg/gpmi/prefix", NULL, NULL},
52 {NULL, NULL, NULL, NULL}
53 };
54
55 void process_args(int argc, char *argv[])
56 {
57 int n;
58 char *key, *value;
59 argtbl_t *a;
60 int found, tainted = 0;
61
62 db_mkdir("/arg");
63
64 logprintf(0, "CLI arg 0: '%s'\n", argv[0]);
65 for(n = 1; n < argc; n++) {
66 key = argv[n];
67 logprintf(0, "CLI arg %d: '%s'\n", n, key);
68 while(*key == '-') key++;
69 value = str_chr(key, '=');
70 found = 0;
71 if (value != NULL) {
72 *value = '\0';
73 value++;
74 /* Look in the argument translate table */
75 for(a = main_argument_table; a->arg != NULL; a++) {
76 if (((a->arg[0] == '^') && (strncmp(a->arg+1, key, strlen(a->arg+1)) == 0)) || (strcmp(a->arg, key) == 0)) {
77 found = 1;
78 if (a->callback != NULL) {
79 if (a->callback(key, value) != 0) {
80 error("Processing argument '%s' failed in the callback\n", argv[n]);
81 abort();
82 }
83 }
84 if (a->path != NULL)
85 put(a->path, value);
86 }
87 }
88 /* Look in known deps table or /arg */
89 if (found == 0) {
90 if ((is_dep_known(key)) || (strncmp(key, "/arg/", 5) == 0)) {
91 put(key, value);
92 found = 1;
93 }
94 }
95 }
96 if (found == 0) {
97 if (custom_arg(key, value) == 0) {
98 error("Unknown argument '%s'\n", key);
99 tainted++;
100 }
101 }
102 }
103 if (tainted)
104 exit(1);
105 }
0 #ifndef SCC_ARG_H
1 #define SCC_ARG_H
2
3 typedef struct {
4 char *arg;
5 char *path;
6 int (*callback)(const char *key, const char *value);
7 char *help;
8 } argtbl_t;
9
10 extern argtbl_t main_argument_table[];
11
12
13
14 void process_args(int argc, char *argv[]);
15
16
17 /* main.c: */
18 extern int custom_arg(const char *key, const char *value);
19 extern int num_custom_reqs;
20
21 #endif
0 /*
1 scconfig - database
2 Copyright (C) 2009..2012 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <assert.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include "db.h"
28 #include "log.h"
29 #include "libs.h"
30
31 ht_t *DBs = NULL;
32 char *db_cwd = NULL;
33
34 void append(const char *key, const char *value)
35 {
36 const char *orig;
37 char *new;
38 int l1, l2;
39
40 assert(key != NULL);
41 assert(value != NULL);
42 if (*value == '\0')
43 return;
44
45 orig = get(key);
46 if (orig == NULL) {
47 put(key, value);
48 return;
49 }
50
51 l1 = strlen(orig);
52 l2 = strlen(value);
53 new = malloc(l1 + l2 + 1);
54 memcpy(new, orig, l1);
55 memcpy(new + l1, value, l2);
56 new[l1+l2] = '\0';
57 put(key, new);
58 }
59
60
61 static const char *db_split_path(const char *key, ht_t **ht, char **fld)
62 {
63 size_t fld_len;
64 const char *path;
65 char first_level_dir[32];
66
67 path = str_chr((char *)(key+1), '/');
68 assert(path != NULL);
69 fld_len = path - key;
70 path++;
71 if (*path == '\0') {
72 *ht = NULL;
73 if (fld != NULL)
74 *fld = NULL;
75 return NULL;
76 }
77 assert(fld_len < sizeof(first_level_dir));
78 strncpy(first_level_dir, key, fld_len);
79 first_level_dir[fld_len] = '\0';
80 *ht = ht_get(DBs, first_level_dir+1);
81 if (fld != NULL)
82 *fld = first_level_dir;
83 return path;
84 }
85
86 static void export_qs(FILE *f, const char *s)
87 {
88 fputc('"', f);
89 for(;*s != '\0';s++) {
90 switch(*s) {
91 case '"': fputc('\\', f); fputc('"', f); break;
92 case '\n': fputc('\\', f); fputc('n', f); break;
93 case '\r': fputc('\\', f); fputc('r', f); break;
94 case '\t': fputc('\\', f); fputc('t', f); break;
95 default: fputc(*s, f);
96 }
97 }
98
99 fputc('"', f);
100 fputc('\n', f);
101 }
102
103 static int needs_quote(const char *s) {
104 for(; *s != '\0'; s++)
105 if ((*s < 32) || (*s > 126) || (*s == '"')) return 1;
106 return 0;
107 }
108
109 int export_(FILE *f, int export_empty, ht_t *table, const char *fld)
110 {
111 ht_entry_t *h;
112
113 for(h = ht_first(table); h != NULL; h = ht_next(table, h))
114 if (export_empty || ((h->value != NULL) && (*(char *)h->value != '\0'))) {
115 fprintf(f, "/%s/%s=", fld, h->key);
116 if (h->value != NULL) {
117 if (needs_quote((char *)h->value))
118 export_qs(f, (const char *)h->value);
119 else
120 fprintf(f, "%s\n", (char *)h->value);
121 }
122 else
123 fprintf(f, "\n");
124 }
125 return 0;
126 }
127
128 int export(const char *fn, int export_empty, const char *root)
129 {
130 FILE *f;
131 int ret;
132 /* ht_t *table; */
133 ht_entry_t *h;
134
135 if (fn != NULL) {
136 f = fopen(fn, "w");
137 if (f == NULL)
138 return -1;
139 }
140 else
141 f = stdout;
142
143 if ((root == NULL) || ((root[0] == '/') && (root[1] == '\0'))) {
144 /* export all directories */
145 for(h = ht_first(DBs); h != NULL; h = ht_next(DBs, h))
146 ret += export_(f, export_empty, h->value, h->key);
147 }
148 else {
149 error("not yet implemented\n");
150 abort();
151 /* db_split_path(); */
152 }
153
154 if (f != stdout)
155 fclose(f);
156
157 return ret;
158 }
159
160 /* append a single character, grow the buffer as needed */
161 #define qappend(chr) \
162 do { \
163 if (used >= alloced) { \
164 alloced += 256; \
165 res = realloc(res, alloced); \
166 } \
167 res[used] = chr; \
168 used++; \
169 } while(0)
170
171 /* read until end of quote and interpret backslash sequences if do_esc is non-zero */
172 static char *readq(FILE *f, char *str, long strmax, int quote, int do_esc, int *num_lines, const char *fn)
173 {
174 int bs = 0;
175 long used = 0, alloced = 0;
176 char *res = NULL, *s;
177
178 for(;;) {
179 for(s = str; *s != '\0'; s++) {
180 if (*s == '\n') (*num_lines)++;
181
182 if (bs) { /* character escaped by backslash */
183 switch(*s) {
184 case '\\': qappend('\\'); break;
185 case 'n': qappend('\n'); break;
186 case 'r': qappend('\r'); break;
187 case 't': qappend('\t'); break;
188 default: qappend(*s); break;
189 }
190 bs = 0;
191 }
192 else if (*s == quote) { /* end */
193 qappend('\0');
194 if ((s[1] != '\r') && (s[1] != '\n') && (s[1] != '\0'))
195 fprintf(stderr, "Warning: trailing text after quote ignored in %s:%d\n", fn, (*num_lines)+1);
196 return res;
197 }
198 else if (do_esc && (*s == '\\')) bs = 1; /* backslash start */
199 else qappend(*s); /* plain character */
200 }
201
202 /* get the next chunk */
203 fgets(str, strmax, f);
204 }
205
206 return NULL; /* can't get here */
207 }
208
209 int import(const char *fn)
210 {
211 char line[1024];
212 char *key, *value, *nl, *slash;
213 int num_records, num_lines;
214 FILE *f;
215
216 f = fopen(fn, "r");
217 if (f == NULL)
218 return -1;
219
220 for(num_records = 0, num_lines = 0; !feof(f); num_lines++) {
221 *line = '\0';
222 fgets(line, sizeof(line) - 1, f);
223 if ((*line != '#') && (*line != '\n') && (*line != '\r') && (*line != '\0')) {
224 int quote, do_esc=0;
225 key = line;
226 value = str_chr(key, '=');
227 if (value == NULL) {
228 error("Error importing: missing '=' in line %d in file %s.\n", num_lines, fn);
229 abort();
230 }
231 num_records++;
232 *value = '\0';
233 value++;
234 if (*value == '"') {
235 quote=*value;
236 value++;
237 do_esc=1;
238 }
239 else if (*value == '\'') {
240 quote=*value;
241 value++;
242 }
243 else
244 quote=0;
245
246 if (!quote) {
247 nl = str_chr(value, '\n');
248 if (nl != NULL)
249 *nl = '\0';
250 }
251 else
252 value = readq(f, value, sizeof(line) - (value - line) - 4, quote, do_esc, &num_lines, fn);
253
254 slash = str_chr(key+1, '/');
255 if (slash == NULL) {
256 error("Error importing: no directory name for %s.\n", key);
257 abort();
258 }
259 *slash = '\0';
260 db_mkdir(key);
261 *slash = '/';
262 put(key, value);
263 logprintf(0, "(Import from '%s': '%s'='%s')\n", fn, key, value);
264 if (quote)
265 free(value);
266 }
267 }
268
269 fclose(f);
270 return num_records;
271 }
272
273 int import_args(const char *key, const char *fn)
274 {
275 (void) key; /* suppress compiler warnings for unused key; needed because function pointers to this function from arg.c */
276 db_mkdir("/target");
277 db_mkdir("/host");
278
279 return import(fn) < 0;
280 }
281
282
283 static const char *db_get(const char *key)
284 {
285 const char *path;
286 ht_t *ht;
287
288 path = db_split_path(key, &ht, NULL);
289 if (ht == NULL)
290 return NULL;
291 return ht_get(ht, path);
292 }
293
294 static const char *db_put(const char *key, const char *value)
295 {
296 const char *path;
297 ht_t *ht;
298
299 path = db_split_path(key, &ht, NULL);
300 if (ht == NULL) {
301 error("db_put: can't find top level hash for '%s'\n", key);
302 abort();
303 }
304 return ht_set(ht, path, (void *)value);
305 }
306
307 #define assamble_path \
308 assert(strlen(key) + strlen(db_cwd) < sizeof(tmp)-1); \
309 sprintf(tmp, "%s/%s", db_cwd, key);
310
311 const char *get(const char *key)
312 {
313 char tmp[256];
314
315 if (*key == '/')
316 return db_get(key);
317 assamble_path;
318 return db_get(tmp);
319 }
320
321 const char *put(const char *key, const char *value)
322 {
323 char tmp[256];
324
325 if (*key == '/')
326 return db_put(key, value);
327 assamble_path;
328 return db_put(tmp, value);
329 }
330
331 void db_init(void)
332 {
333 DBs = ht_resize(ht_alloc(0), 16);
334 }
335
336 void db_uninit(void)
337 {
338 ht_entry_t *h;
339 ht_t *dir;
340
341 for(h = ht_first(DBs); h != NULL; h = ht_next(DBs, h)) {
342 dir = h->value;
343 dir->refcount--;
344 if (dir->refcount == 0)
345 ht_free(dir);
346 }
347 ht_free(DBs);
348 if (db_cwd != NULL)
349 free(db_cwd);
350 /* Just in case someone calls db_init again... */
351 db_cwd = NULL;
352 DBs = NULL;
353 }
354
355 void db_cd(const char *path)
356 {
357 assert(*path == '/');
358 if (db_cwd != NULL)
359 free(db_cwd);
360 db_cwd = strclone(path);
361 }
362
363 void db_mkdir(const char *path)
364 {
365 ht_t *ht, *target;
366 assert(*path == '/');
367 target = ht_get(DBs, path+1);
368 if (target == NULL) {
369 ht = ht_resize(ht_alloc(1), 256);
370 ht_set(DBs, path+1, ht);
371 }
372 }
373
374 void db_rmdir(const char *path)
375 {
376 ht_t *ht;
377 assert(*path == '/');
378 ht = ht_get(DBs, path+1);
379 if (ht == NULL)
380 return;
381 ht_del(DBs, path+1);
382 /* ht_free(ht); */
383 }
384
385 void db_link(const char *existing, const char *new)
386 {
387 ht_t *ht;
388
389 assert(*new == '/');
390 ht = ht_get(DBs, existing+1);
391 assert(ht != NULL);
392 ht_set(DBs, new+1, ht);
393 ht->refcount++;
394 }
395
396 char *concat_nodes(const char *prefix, ...)
397 {
398 char *buff;
399 const char *node, *value;
400 int allocated = 256, len, totallen;
401
402 va_list ap;
403 va_start(ap, prefix);
404 buff = malloc(allocated);
405 if (prefix != NULL) {
406 strcpy(buff, prefix);
407 totallen = strlen(prefix);
408 buff[totallen] = ' ';
409 totallen++;
410 }
411 else
412 totallen = 0;
413
414 while((node = va_arg(ap, const char *)) != NULL) {
415 value = get(node);
416 if (value != NULL) {
417 len = strlen(value);
418 if (totallen + len >= allocated) {
419 allocated = totallen + len + 256;
420 buff = realloc(buff, allocated);
421 }
422 memcpy(buff + totallen, value, len);
423 totallen += len;
424 buff[totallen] = ' ';
425 totallen++;
426
427 buff[totallen] = '\0';
428 }
429 }
430
431 buff[totallen - 1] = '\0';
432 va_end(ap);
433 return buff;
434 }
435
436 int node_istrue(const char *key)
437 {
438 const char *s = get(key);
439 if (s == NULL)
440 return 0;
441 return istrue(s);
442 }
0 #include "ht.h"
1
2
3 #define strue "true"
4 #define sfalse "false"
5 #define istrue(s) ((s != NULL) && (*s == 't'))
6 #define isfalse(s) ((s != NULL) && (*s == 'f'))
7 /* the 3rd option is "unknown" */
8
9 /* accessors */
10 const char *get(const char *key);
11 const char *put(const char *key, const char *data);
12 void append(const char *key, const char *value);
13 char *concat_nodes(const char *prefix, ...);
14 int node_istrue(const char *key);
15
16
17 /* init/uninit */
18 void db_init(void);
19 void db_uninit(void);
20
21 /* export/import */
22 int export(const char *fn, int export_empty, const char *root);
23 int import(const char *fn);
24 int import_args(const char *key, const char *fn);
25
26 /* file system features */
27 extern char *db_cwd;
28 void db_cd(const char *path);
29 void db_mkdir(const char *path);
30 void db_link(const char *existing, const char *new);
31 void db_rmdir(const char *path);
32
33 extern ht_t *DBs;
34 #define iscross (ht_get(DBs, "target") != ht_get(DBs, "host"))
35 #define in_cross_target (iscross && (strcmp(db_cwd, "/target") == 0))
36 #define in_cross_host (iscross && (strcmp(db_cwd, "/host") == 0))
0 /*
1 scconfig - dependencies
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include "dep.h"
25 #include "db.h"
26 #include "log.h"
27 #include "libs.h"
28
29 typedef struct {
30 int (*fn)(const char *name, int logdepth, int fatal);
31 } fn_wrap_t;
32
33
34 static ht_t *deps = NULL;
35
36
37 /* find name_ and decide if it was a wildcard request;
38 NOTE: there are requests and servers, both can be wildcard independently.
39 - if a request ends with a / *, it is an explicit wildcard request (*wild=1)
40 - if a request names a "directory" that is wildcard-server, that's a wildcard request (*wild=1)
41 - else the request is a normal request (*wild=0).
42 For normal requests, a required node was explicitly named; if that node is
43 not created by the detection function, that's a failure. For wildcard
44 requests we don't look for any specific node to be created.
45 TODO: we may still check if at least the directory is created
46 */
47 fn_wrap_t *get_wrap(const char *name_, int *wild, int *missing)
48 {
49 fn_wrap_t *w;
50 char *name, *sep;
51 int len;
52
53 len = strlen(name_);
54 *wild = name_[len-1] == '*';
55
56 if (*wild) {
57 char *pres;
58 pres = malloc(len+16);
59 memcpy(pres, name_, len-1);
60 strcpy(pres+len-1, "presents");
61 *missing = get(pres) == NULL;
62 if (*missing) { /* if there's no /presents, it may be a non-directory node with an actual non-empty string value */
63 const char *val;
64 pres[len-2] = '\0';
65 val = get(pres);
66 if (val != NULL)
67 *missing = !strlen(val);
68 }
69 free(pres);
70 if (!(*missing)) /* already detected, won't be detected again */
71 return NULL;
72 }
73 *missing = 1;
74
75 /* try full match first */
76 w = ht_get(deps, name_);
77 if (w != NULL)
78 return w;
79
80
81 /* try substituting the last part of the path with * for wildcard matches */
82 name = malloc(len+3); /* worst case: ends in a / and we need to append *\0; allocate a bit more */
83 memcpy(name, name_, len+1); /* make a copy we can modify */
84 if (name[len-1] != '/') {
85 name[len] = '/'; /* append a / - if name_ was a "directory", this will result in name/ * */
86 name[len+1] = '\0';
87 }
88
89 *wild = 1; /* if we append a / *, then it's a wildcard request */
90 for(;;) {
91 sep = str_rchr(name, '/');
92 if (sep == NULL)
93 goto error;
94 sep[1] = '*';
95 sep[2] = '\0';
96 w = ht_get(deps, name);
97 if (w != NULL) {
98 free(name);
99 return w;
100 }
101 *sep = '\0';
102 *wild = 0; /* cutting back the second layer - not wildcard request anymore, but a request to a specific node served by a wildcard */
103 }
104
105 /* no match, exit with error */
106 error:;
107 *wild = 0;
108 free(name);
109 return NULL;
110 }
111
112
113 int require(const char *name, int logdepth, int fatal)
114 {
115 fn_wrap_t *w;
116 int wild, missing;
117
118 if (get(name) == NULL) {
119 w = get_wrap(name, &wild, &missing);
120 if (!missing)
121 return 0;
122 if ((w == NULL) || (w->fn == NULL)) {
123 error("Node %s is required but I don't know how to detect it.\n", name);
124 abort();
125 }
126
127 logprintf(logdepth, "(Required node: '%s')\n", name);
128 if (w->fn(name, logdepth+1, fatal) != 0) {
129 if (fatal) {
130 error("Node %s is required but provided detection callback fails to find that feature on that system.\n", name);
131 abort();
132 }
133 else {
134 logprintf(logdepth, "(Feature not found, but it is not fatal)");
135 return 1;
136 }
137 }
138 if ((!wild) && (get(name) == NULL)) {
139 error("Node %s is required but provided detection callback didn't create it (looks like an internal error in scconfig). (db_cwd='%s')\n", name, db_cwd);
140 abort();
141 }
142 }
143 return 0;
144 }
145
146 const char *dep_add(const char *name, int (*finder)(const char *name, int logdepth, int fatal))
147 {
148 fn_wrap_t *w;
149 w = malloc(sizeof(fn_wrap_t));
150 w->fn = finder;
151 return ht_set(deps, name, w);
152 }
153
154 int asked_for(const char *cando, const char *needtodo)
155 {
156 int len;
157
158 /* foo/bar/baz matches /foo/bar/baz */
159 if (strcmp(cando, needtodo) == 0)
160 goto yes;
161
162 len = strlen(needtodo);
163 if (len == 0)
164 return 0;
165
166 /* foo/bar/baz matches /foo/bar/ * */
167 if ((needtodo[len-1] == '*') && (strncmp(cando, needtodo, len-1) == 0))
168 goto yes;
169
170 return 0;
171
172
173 yes:; /* asked for it, but have to see if it's already detected */
174 if (get(cando) != NULL)
175 return 0;
176
177 return 1;
178 }
179
180 int is_dep_wild(const char *path)
181 {
182 int len = strlen(path);
183 if (len == 0)
184 return 0;
185 return (path[len-1] == '*');
186 }
187
188 const char *det_list_target(const char *path)
189 {
190 const char *res;
191
192 if (path == NULL)
193 goto unk;
194
195 res = strrchr(path, '/');
196 if (res == NULL)
197 goto unk;
198
199 return res + 1;
200 unk:;
201 return "<unknown>";
202 }
203
204
205 void dep_init(void)
206 {
207 deps = ht_resize(ht_alloc(0), 128);
208 }
209
210 void dep_uninit(void)
211 {
212 ht_free(deps);
213 }
214
215 int is_dep_known(const char *name)
216 {
217 return (ht_get(deps, name) != NULL);
218 }
219
220 void require_all(int fatal)
221 {
222 ht_entry_t *h;
223
224 for(h = ht_first(deps); h != NULL; h = ht_next(deps, h))
225 require(h->key, 0, fatal);
226 }
0 #include "ht.h"
1
2 int is_dep_known(const char *name);
3 int require(const char *name, int logdepth, int fatal);
4 const char *dep_add(const char *name, int (*finder)(const char *name, int logdepth, int fatal));
5 void require_all(int fatal);
6
7 /* Returns if dependency is a wildcard one (ending in / *) */
8 int is_dep_wild(const char *path);
9
10 /* Almost 'basename': returns the last portion of the path, which may
11 be '*'. Returns "<unknown>" on error. */
12 const char *det_list_target(const char *path);
13
14 /* Returns 1 if the user asked for detecting a feature; needtodo is
15 the first argument passed to the detection function (the target the caller
16 wants to get detected), cando is the output path of the test that the
17 detector could do next. */
18 int asked_for(const char *cando, const char *needtodo);
19
20 /* for internal use */
21 void dep_init(void);
22 void dep_uninit(void);
23
0 /*
1 scconfig - dependency list of default tests
2 Copyright (C) 2009..2012 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include "dep.h"
23 #include "find.h"
24
25 void deps_default_init(void)
26 {
27 dep_add("cc/cc", find_cc);
28 dep_add("cc/argstd/*", find_cc_argstd);
29 dep_add("cc/cflags", find_cc);
30 dep_add("cc/ldflags", find_cc);
31 dep_add("cc/inline", find_inline);
32 dep_add("cc/varargmacro", find_varargmacro);
33 dep_add("cc/funcmacro", find_funcmacro);
34 dep_add("cc/constructor", find_constructor);
35 dep_add("cc/destructor", find_destructor);
36 dep_add("cc/rdynamic", find_rdynamic);
37 dep_add("cc/soname", find_soname);
38 dep_add("cc/wlrpath", find_wlrpath);
39 dep_add("cc/wloutimplib", find_cc_wloutimplib);
40 dep_add("cc/wloutputdef", find_cc_wloutputdef);
41 dep_add("cc/fpic", find_fpic);
42 dep_add("cc/fpie/*", find_cc_fpie);
43 dep_add("cc/fnopie/*", find_cc_fnopie);
44 dep_add("cc/fnopic/*", find_cc_fnopic);
45 dep_add("cc/alloca/*", find_alloca);
46 dep_add("cc/_exit/*", find__exit);
47 dep_add("cc/ldflags_dynlib", find_ldflags_dynlib);
48 dep_add("cc/ldflags_dll", find_ldflags_dll);
49 dep_add("cc/ldflags_so", find_ldflags_so);
50 dep_add("cc/func_attr/unused/*", find_fattr_unused);
51 dep_add("cc/declspec/dllimport/*", find_declspec_dllimport);
52 dep_add("cc/declspec/dllexport/*", find_declspec_dllexport);
53 dep_add("cc/argmachine/*", find_cc_argmachine);
54 dep_add("libs/ldl", find_lib_ldl);
55 dep_add("libs/LoadLibrary/*", find_lib_LoadLibrary);
56 dep_add("libs/lpthread", find_lib_lpthread);
57 dep_add("libs/lpthread-recursive", find_lib_lpthread);
58 dep_add("thread/semget/*", find_thread_semget);
59 dep_add("thread/pthread_create/*", find_thread_pthread_create);
60 dep_add("thread/CreateSemaphore/*", find_thread_CreateSemaphore);
61 dep_add("thread/CreateThread/*", find_thread_CreateThread);
62 dep_add("libs/errno/*", find_lib_errno);
63 dep_add("libs/printf_x", find_printf_x);
64 dep_add("libs/printf_ptrcast", find_printf_ptrcast);
65 dep_add("libs/snprintf", find_snprintf);
66 dep_add("libs/snprintf_safe", find_snprintf);
67 dep_add("libs/dprintf", find_dprintf);
68 dep_add("libs/vdprintf", find_vdprintf);
69 dep_add("libs/vsnprintf", find_vsnprintf);
70 dep_add("libs/proc/_spawnvp/*", find_proc__spawnvp);
71 dep_add("libs/proc/fork/*", find_proc_fork);
72 dep_add("libs/proc/wait/*", find_proc_wait);
73 dep_add("libs/fs/realpath/*", find_fs_realpath);
74 dep_add("libs/fs/_fullpath/*", find_fs__fullpath);
75 dep_add("libs/fs/readdir/*", find_fs_readdir);
76 dep_add("libs/fs/findnextfile/*", find_fs_findnextfile);
77 dep_add("libs/fs/stat/macros/*", find_fs_stat_macros);
78 dep_add("libs/fs/stat/fields/*", find_fs_stat_fields);
79 dep_add("libs/fs/access/*", find_fs_access);
80 dep_add("libs/fs/access/macros/*", find_fs_access_macros);
81 dep_add("libs/fs/lstat/*", find_fs_lstat);
82 dep_add("libs/fs/statlstat/*", find_fs_statlstat);
83 dep_add("libs/fs/getcwd/*", find_fs_getcwd);
84 dep_add("libs/fs/_getcwd/*", find_fs__getcwd);
85 dep_add("libs/fs/getwd/*", find_fs_getwd);
86 dep_add("libs/fs/mkdir/*", find_fs_mkdir);
87 dep_add("libs/fs/_mkdir/*", find_fs__mkdir);
88 dep_add("libs/fs/mkdtemp/*", find_fs_mkdtemp);
89 dep_add("libs/fs/mmap/*", find_fs_mmap);
90 dep_add("libs/fsmount/next_dev/*", find_fsmount_next_dev);
91 dep_add("libs/fsmount/struct_fsstat/*",find_fsmount_fsstat_fields);
92 dep_add("libs/fsmount/struct_statfs/*",find_fsmount_statfs_fields);
93 dep_add("libs/fsmount/struct_statvfs/*",find_fsmount_statvfs_fields);
94 dep_add("libs/fs/ustat/*", find_fs_ustat);
95 dep_add("libs/fs/statfs/*", find_fs_statfs);
96 dep_add("libs/fs/statvfs/*", find_fs_statvfs);
97 dep_add("libs/fs/flock/*", find_fs_flock);
98
99 dep_add("libs/io/pipe/*", find_io_pipe);
100 dep_add("libs/io/dup2/*", find_io_dup2);
101 dep_add("libs/io/fileno/*", find_io_fileno);
102 dep_add("libs/io/lseek/*", find_io_lseek);
103 dep_add("libs/io/popen/*", find_io_popen);
104 dep_add("libs/time/usleep/*", find_time_usleep);
105 dep_add("libs/types/stdint/*", find_types_stdint);
106 dep_add("sys/types/size/*", find_types_sizes);
107 dep_add("libs/time/Sleep/*", find_time_Sleep);
108 dep_add("libs/time/gettimeofday/*", find_time_gettimeofday);
109 dep_add("libs/time/ftime/*", find_time_ftime);
110 dep_add("libs/time/timegm/*", find_time_timegm);
111 dep_add("libs/time/_mkgmtime/*", find_time_mkgmtime);
112 dep_add("libs/time/gmtime_r/*", find_time_gmtime_r);
113 dep_add("libs/time/gmtime_s/*", find_time_gmtime_s);
114 dep_add("libs/env/main_3arg/*", find_main_arg3);
115 dep_add("libs/env/putenv/*", find_putenv);
116 dep_add("libs/env/setenv/*", find_setenv);
117 dep_add("libs/env/environ/*", find_environ);
118 dep_add("signal/raise/*", find_signal_raise);
119 dep_add("signal/names/*", find_signal_names);
120 dep_add("fstools/cp", find_fstools_cp);
121 dep_add("fstools/ln", find_fstools_ln);
122 dep_add("fstools/mv", find_fstools_mv);
123 dep_add("fstools/rm", find_fstools_rm);
124 dep_add("fstools/mkdir", find_fstools_mkdir);
125 dep_add("fstools/ar", find_fstools_ar);
126 dep_add("fstools/ranlib", find_fstools_ranlib);
127 dep_add("fstools/awk", find_fstools_awk);
128 dep_add("fstools/cat", find_fstools_cat);
129 dep_add("fstools/sed", find_fstools_sed);
130 dep_add("fstools/file_l", find_fstools_file_l);
131 dep_add("fstools/file", find_fstools_file);
132 dep_add("fstools/chmodx", find_fstools_chmodx);
133 dep_add("sys/name", find_uname);
134 dep_add("sys/uname", find_uname);
135 dep_add("sys/triplet", find_triplet);
136 dep_add("sys/sysid", find_sysid);
137 dep_add("sys/shell", find_shell);
138 dep_add("sys/shell_needs_quote", find_shell);
139 dep_add("sys/tmp", find_tmp);
140 dep_add("sys/shell_eats_backslash", find_tmp);
141 dep_add("sys/ext_exe", find_uname);
142 dep_add("sys/ext_dynlib", find_uname);
143 dep_add("sys/ext_dynlib_native", find_uname);
144 dep_add("sys/ext_stalib", find_uname);
145 dep_add("sys/class", find_uname);
146 dep_add("sys/path_sep", find_uname);
147 dep_add("sys/ptrwidth", find_sys_ptrwidth);
148 dep_add("sys/byte_order", find_sys_byte_order);
149 dep_add("sys/types/size_t/*", find_types_size_t);
150 dep_add("sys/types/off_t/*", find_types_off_t);
151 dep_add("sys/types/off64_t/*", find_types_off64_t);
152 dep_add("sys/types/gid_t/*", find_types_gid_t);
153 dep_add("sys/types/uid_t/*", find_types_uid_t);
154 dep_add("sys/types/pid_t/*", find_types_pid_t);
155 dep_add("sys/types/mode_t/*", find_types_mode_t);
156 dep_add("sys/types/nlink_t/*", find_types_nlink_t);
157 dep_add("sys/types/ptrdiff_t/*", find_types_ptrdiff_t);
158 dep_add("sys/types/dev_t/*", find_types_dev_t);
159 dep_add("sys/types/ino_t/*", find_types_ino_t);
160 dep_add("sys/types/void_ptr/*", find_types_void_ptr);
161 dep_add("str/strcasecmp/*", find_strcasecmp);
162 dep_add("str/strncasecmp/*", find_strncasecmp);
163
164 dep_add("/internal/filelist/cmd", find_filelist);
165 dep_add("/internal/filelist/method", find_filelist);
166 }
0 void deps_default_init(void);
0 /* cc */
1 int find_cc(const char *name, int logdepth, int fatal);
2 int find_cc_argstd(const char *name, int logdepth, int fatal);
3 int find_cc_argmachine(const char *name, int logdepth, int fatal);
4 int find_cc_fpie(const char *name, int logdepth, int fatal);
5 int find_cc_fnopie(const char *name, int logdepth, int fatal);
6 int find_cc_fnopic(const char *name, int logdepth, int fatal);
7 int find_inline(const char *name, int logdepth, int fatal);
8 int find_varargmacro(const char *name, int logdepth, int fatal);
9 int find_funcmacro(const char *name, int logdepth, int fatal);
10 int find_constructor(const char *name, int logdepth, int fatal);
11 int find_destructor(const char *name, int logdepth, int fatal);
12 int find_fattr_unused(const char *name, int logdepth, int fatal);
13 int find_declspec_dllimport(const char *name, int logdepth, int fatal);
14 int find_declspec_dllexport(const char *name, int logdepth, int fatal);
15 int find_rdynamic(const char *name, int logdepth, int fatal);
16 int find_soname(const char *name, int logdepth, int fatal);
17 int find_wlrpath(const char *name, int logdepth, int fatal);
18 int find_cc_wloutimplib(const char *name, int logdepth, int fatal);
19 int find_cc_wloutputdef(const char *name, int logdepth, int fatal);
20 int find_fpic(const char *name, int logdepth, int fatal);
21 int find_ldflags_dynlib(const char *name, int logdepth, int fatal);
22 int find_ldflags_dll(const char *name, int logdepth, int fatal);
23 int find_ldflags_so(const char *name, int logdepth, int fatal);
24 int find_alloca(const char *name, int logdepth, int fatal);
25 int find__exit(const char *name, int logdepth, int fatal);
26
27 /* libs */
28 int find_lib_ldl(const char *name, int logdepth, int fatal);
29 int find_lib_LoadLibrary(const char *name, int logdepth, int fatal);
30 int find_lib_errno(const char *name, int logdepth, int fatal);
31
32 /* thread */
33 int find_lib_lpthread(const char *name, int logdepth, int fatal);
34 int find_thread_semget(const char *name, int logdepth, int fatal);
35 int find_thread_pthread_create(const char *name, int logdepth, int fatal);
36 int find_thread_CreateSemaphore(const char *name, int logdepth, int fatal);
37 int find_thread_CreateThread(const char *name, int logdepth, int fatal);
38
39 /* fscalls */
40 int find_fs_realpath(const char *name, int logdepth, int fatal);
41 int find_fs__fullpath(const char *name, int logdepth, int fatal);
42 int find_fs_readdir(const char *name, int logdepth, int fatal);
43 int find_fs_findnextfile(const char *name, int logdepth, int fatal);
44 int find_fs_access(const char *name, int logdepth, int fatal);
45 int find_fs_access_macros(const char *name, int logdepth, int fatal);
46 int find_fs_stat_macros(const char *name, int logdepth, int fatal);
47 int find_fs_stat_fields(const char *name, int logdepth, int fatal);
48 int find_fs_lstat(const char *name, int logdepth, int fatal);
49 int find_fs_statlstat(const char *name, int logdepth, int fatal);
50 int find_fs_getcwd(const char *name, int logdepth, int fatal);
51 int find_fs__getcwd(const char *name, int logdepth, int fatal);
52 int find_fs_getwd(const char *name, int logdepth, int fatal);
53 int find_fs_mkdir(const char *name, int logdepth, int fatal);
54 int find_fs__mkdir(const char *name, int logdepth, int fatal);
55 int find_fs_mkdtemp(const char *name, int logdepth, int fatal);
56 int find_fs_mmap(const char *name, int logdepth, int fatal);
57 int find_fsmount_next_dev(const char *name, int logdepth, int fatal);
58 int find_fsmount_fsstat_fields(const char *name, int logdepth, int fatal);
59 int find_fsmount_statfs_fields(const char *name, int logdepth, int fatal);
60 int find_fsmount_statvfs_fields(const char *name, int logdepth, int fatal);
61 int find_fs_ustat(const char *name, int logdepth, int fatal);
62 int find_fs_statfs(const char *name, int logdepth, int fatal);
63 int find_fs_statvfs(const char *name, int logdepth, int fatal);
64 int find_fs_flock(const char *name, int logdepth, int fatal);
65
66 /* printf */
67 int find_printf_x(const char *name, int logdepth, int fatal);
68 int find_printf_ptrcast(const char *name, int logdepth, int fatal);
69 int find_snprintf(const char *name, int logdepth, int fatal);
70 int find_dprintf(const char *name, int logdepth, int fatal);
71 int find_vdprintf(const char *name, int logdepth, int fatal);
72 int find_vsnprintf(const char *name, int logdepth, int fatal);
73
74 /* proc */
75 int find_proc__spawnvp(const char *name, int logdepth, int fatal);
76 int find_proc_fork(const char *name, int logdepth, int fatal);
77 int find_proc_wait(const char *name, int logdepth, int fatal);
78
79 /* fstools */
80 int find_fstools_cp(const char *name, int logdepth, int fatal);
81 int find_fstools_ln(const char *name, int logdepth, int fatal);
82 int find_fstools_mv(const char *name, int logdepth, int fatal);
83 int find_fstools_rm(const char *name, int logdepth, int fatal);
84 int find_fstools_mkdir(const char *name, int logdepth, int fatal);
85 int find_fstools_ar(const char *name, int logdepth, int fatal);
86 int find_fstools_ranlib(const char *name, int logdepth, int fatal);
87 int find_fstools_awk(const char *name, int logdepth, int fatal);
88 int find_fstools_cat(const char *name, int logdepth, int fatal);
89 int find_fstools_sed(const char *name, int logdepth, int fatal);
90 int find_fstools_file(const char *name, int logdepth, int fatal);
91 int find_fstools_file_l(const char *name, int logdepth, int fatal);
92 int find_fstools_chmodx(const char *name, int logdepth, int fatal);
93
94 /* uname */
95 int find_uname(const char *name, int logdepth, int fatal);
96 int find_triplet(const char *name, int logdepth, int fatal);
97 int find_sysid(const char *name, int logdepth, int fatal);
98
99 /* find_target */
100 int find_target(const char *name, int logdepth, int fatal);
101
102 /* filelist */
103 int find_filelist(const char *name, int logdepth, int fatal);
104
105 /* find_str.c */
106 int find_strcasecmp(const char *name, int logdepth, int fatal);
107 int find_strncasecmp(const char *name, int logdepth, int fatal);
108
109 /* find_sys.c */
110 int find_sys_ptrwidth(const char *name, int logdepth, int fatal);
111 int find_sys_byte_order(const char *name, int logdepth, int fatal);
112 int find_tmp(const char *name, int logdepth, int fatal);
113 int find_shell(const char *name, int logdepth, int fatal);
114
115 /* find_io.c */
116 int find_io_pipe(const char *name, int logdepth, int fatal);
117 int find_io_dup2(const char *name, int logdepth, int fatal);
118 int find_io_fileno(const char *name, int logdepth, int fatal);
119 int find_io_lseek(const char *name, int logdepth, int fatal);
120 int find_io_popen(const char *name, int logdepth, int fatal);
121
122 /* find_time.c */
123 int find_time_usleep(const char *name, int logdepth, int fatal);
124 int find_time_Sleep(const char *name, int logdepth, int fatal);
125 int find_time_gettimeofday(const char *name, int logdepth, int fatal);
126 int find_time_ftime(const char *name, int logdepth, int fatal);
127 int find_time_timegm(const char *name, int logdepth, int fatal);
128 int find_time_mkgmtime(const char *name, int logdepth, int fatal);
129 int find_time_gmtime_s(const char *name, int logdepth, int fatal);
130 int find_time_gmtime_r(const char *name, int logdepth, int fatal);
131
132 /* find_types.c */
133 int find_types_stdint(const char *name, int logdepth, int fatal);
134 int find_types_sizes(const char *name, int logdepth, int fatal);
135 int find_types_size_t(const char *name, int logdepth, int fatal);
136 int find_types_off_t(const char *name, int logdepth, int fatal);
137 int find_types_off64_t(const char *name, int logdepth, int fatal);
138 int find_types_gid_t(const char *name, int logdepth, int fatal);
139 int find_types_uid_t(const char *name, int logdepth, int fatal);
140 int find_types_pid_t(const char *name, int logdepth, int fatal);
141 int find_types_dev_t(const char *name, int logdepth, int fatal);
142 int find_types_dev_t(const char *name, int logdepth, int fatal);
143 int find_types_mode_t(const char *name, int logdepth, int fatal);
144 int find_types_nlink_t(const char *name, int logdepth, int fatal);
145 int find_types_ptrdiff_t(const char *name, int logdepth, int fatal);
146 int find_types_dev_t(const char *name, int logdepth, int fatal);
147 int find_types_ino_t(const char *name, int logdepth, int fatal);
148 int find_types_void_ptr(const char *name, int logdepth, int fatal);
149
150 /* find_signal.c */
151 int find_signal_names(const char *name, int logdepth, int fatal);
152 int find_signal_raise(const char *name, int logdepth, int fatal);
153
154 /* environ.c */
155 int find_main_arg3(const char *name, int logdepth, int fatal);
156 int find_putenv(const char *name, int logdepth, int fatal);
157 int find_setenv(const char *name, int logdepth, int fatal);
158 int find_environ(const char *name, int logdepth, int fatal);
0 /*
1 scconfig - detection of cc and compiler features
2 Copyright (C) 2009..2012 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include "libs.h"
27 #include "log.h"
28 #include "db.h"
29 #include "dep.h"
30
31
32
33 static int try_flags(int logdepth, const char *cc, const char *test_c, const char *cflags, const char *ldflags, const char *expected)
34 {
35 char *out;
36
37 logprintf(logdepth, "trying cc:try_flags with cc='%s' cflags='%s' ldflags='%s'\n", (cc == NULL ? get("cc/cc") : cc), cflags == NULL ? "" : cflags, ldflags == NULL ? "" : ldflags);
38
39 if (compile_run(logdepth+1, test_c, cc, cflags, ldflags, &out) == 0) {
40 if (((out == NULL) && (iscross)) || (strncmp(out, expected, strlen(expected)) == 0)) {
41 free(out);
42 return 1;
43 }
44 free(out);
45 }
46 return 0;
47 }
48
49 static int try_flags_inv(int logdepth, const char *cc, const char *test_c, const char *cflags, const char *ldflags, const char *expected_bad)
50 {
51 char *out;
52
53 logprintf(logdepth, "trying cc:try_flags with cc='%s' cflags='%s' ldflags='%s'\n", (cc == NULL ? get("cc/cc") : cc), cflags == NULL ? "" : cflags, ldflags == NULL ? "" : ldflags);
54
55 if (compile_run(logdepth+1, test_c, cc, cflags, ldflags, &out) == 0) {
56 if (((out == NULL) && (iscross)) || (strncmp(out, expected_bad, strlen(expected_bad)) != 0)) {
57 free(out);
58 return 1;
59 }
60 free(out);
61 }
62 return 0;
63 }
64
65 static int try(int logdepth, const char *cc, const char *test_c, const char *expected)
66 {
67 return try_flags(logdepth, cc, test_c, NULL, NULL, expected);
68 }
69
70
71 static int trycc(int logdepth, const char *cc, const char *test_c)
72 {
73 int ret;
74
75 if (cc == NULL)
76 return 0;
77
78 ret = try(logdepth, cc, test_c, "OK");
79 if (ret)
80 put("cc/cc", cc);
81 return ret;
82 }
83
84 int find_cc(const char *name, int logdepth, int fatal)
85 {
86 char *test_c = "#include <stdio.h>\nint main() { printf(\"OK\\n\");\nreturn 0;}\n";
87 char *out = NULL, *targetcc;
88 const char *cc, *cflags, *ldflags, *target, *sys;
89 int len;
90
91 require("sys/name", logdepth, fatal);
92
93 sys = istarget(db_cwd) ? "target" : "host";
94 report("Checking for cc (%s)... ", sys);
95 logprintf(logdepth, "find_cc: trying to find cc (%s)...\n", sys);
96 logdepth++;
97
98 /* cflags */
99 cflags = get("/arg/cc/cflags");
100 if (cflags != NULL) {
101 logprintf(logdepth+1, "using user supplied cflags '%s'\n", cflags);
102 put("cc/cflags", cflags);
103 }
104
105 /* ldflags */
106 ldflags = get("/arg/cc/ldflags");
107 if (ldflags != NULL) {
108 logprintf(logdepth+1, "using user supplied ldflags '%s'\n", ldflags);
109 put("cc/ldflags", ldflags);
110 }
111
112 cc = get("/arg/cc/cc");
113 if (cc == NULL) {
114 target = get("sys/target");
115 if (target != NULL) {
116 logprintf(logdepth+1, "find_cc: crosscompiling for '%s', looking for target cc\n", target);
117 len = strlen(target);
118 targetcc = malloc(len + 8);
119 memcpy(targetcc, target, len);
120 strcpy(targetcc + len, "-gcc");
121 if (!trycc(logdepth+1, targetcc, test_c)) {
122 strcpy(targetcc + len, "-cc");
123 if (!trycc(logdepth+1, targetcc, test_c)) {
124 report("FAILED: failed to find crosscompiler for target '%s'\n", target);
125 logprintf(logdepth, "find_cc: FAILED to find a crosscompiler for target '%s'\n", target);
126 return 1;
127 }
128 }
129 put("cc/cc", targetcc);
130 }
131 else {
132 cc = getenv("CC");
133 logprintf(logdepth, "find_cc: Detecting cc (host)\n");
134 /* Find a working cc (no arguments) */
135 if (!(((cc != NULL) && (trycc(logdepth+1, cc, test_c))) || trycc(logdepth+1, "gcc", test_c) || trycc(logdepth+1, "cc", test_c))) {
136 report("FAILED to find a compiler\n");
137 logprintf(logdepth, "find_cc: FAILED to find a compiler\n");
138 return 1;
139 }
140 }
141 }
142 else {
143 put("cc/cc", cc);
144 logprintf(logdepth+1, "using user supplied '%s' (will test later)\n", cc);
145 }
146
147 /* cflags (again) */
148 if (cflags == NULL) {
149 logprintf(logdepth, "find_cc: Detecting -pipe\n");
150
151 if (compile_run(logdepth+1, test_c, NULL, "-pipe", "", &out) == 0) {
152 if (target_emu_fail(out) || (strncmp(out, "OK", 2) == 0)) {
153 append("cc/cflags", " -pipe");
154 }
155 free(out);
156 }
157 }
158 if (get("cc/cflags") == NULL)
159 put("cc/cflags", "");
160
161 /* ldflags (again) */
162 if (get("cc/ldflags") == NULL)
163 put("cc/ldflags", "");
164
165 /* Final test of all arguments together */
166 logprintf(logdepth, "find_cc: final test on cc and all flags \n");
167 if (compile_run(logdepth+1, test_c, NULL, NULL, NULL, &out) != 0) {
168 report("FAILED to get the compiler and all flags to work together\n");
169 logprintf(logdepth, "find_cc: the compiler and all the flags don't work well together, aborting\n");
170 if (out != NULL)
171 free(out);
172 return 1;
173 }
174
175 report("OK ('%s', '%s', '%s')\n", get("cc/cc"), get("cc/cflags"), get("cc/ldflags"));
176 logprintf(logdepth, "find_cc: conclusion: cc='%s' cflags='%s' ldflags='%s'\n", get("cc/cc"), get("cc/cflags"), get("cc/ldflags"));
177 if (out != NULL)
178 free(out);
179 return 0;
180 }
181
182 int find_cc_argstd(const char *det_name, int logdepth, int fatal)
183 {
184 char *test_c = "#include <stdio.h>\nint main() { printf(\"OK\\n\");\nreturn 0;}\n";
185 char *out = NULL;
186 char **flg, *flags[] = {"-ansi", "-pedantic", "-Wall", "-std=c89", "-std=c99", "-Werror", "-Wextra", "-W", "-pg", "-no-pie", "-static-pie", NULL};
187 const char *det_target = det_list_target(det_name);
188
189 require("cc/cc", logdepth, fatal);
190
191 logprintf(logdepth, "find_cc: Detecting CC args %s\n", det_target);
192 report("Checking for cc args for std %s... ", det_target);
193
194 for(flg = flags; *flg != NULL; flg++) {
195 char name[128], *end;
196 const char *found = "";
197 sprintf(name, "cc/argstd/%s", (*flg)+1);
198 end = strchr(name, '=');
199 if (end != NULL)
200 *end = '_';
201 if (!asked_for(name, det_name))
202 continue;
203 if (compile_run(logdepth+1, test_c, NULL, *flg, "", &out) == 0) {
204 if (target_emu_fail(out) || (strncmp(out, "OK", 2) == 0)) {
205 found = *flg;
206 report(" ");
207 report(found);
208 }
209 free(out);
210 }
211 put(name, found);
212 }
213
214 if (is_dep_wild(det_name))
215 put("cc/argstd/presents", strue); /* to avoid re-detection*/
216
217 report("\n");
218 return 0;
219 }
220
221 int find_cc_argmachine(const char *name, int logdepth, int fatal)
222 {
223 #define ARGM(flag) "-m" #flag , "-mno-" #flag
224 const char *test_c = "#include <stdio.h>\nint main() { printf(\"OK\\n\");\nreturn 0;}\n";
225 char *out = NULL;
226 const char **flg, *flags[] = { ARGM(mmx), ARGM(sse), ARGM(sse2), ARGM(sse3), ARGM(ssse3), ARGM(sse4), ARGM(sse4.1), ARGM(sse4.2), ARGM(avx), ARGM(avx2), NULL};
227
228 require("cc/cc", logdepth, fatal);
229
230 logprintf(logdepth, "find_cc: Detecting CC machine args\n");
231 report("Checking for cc args for machine... ");
232
233 for(flg = flags; *flg != NULL; flg++) {
234 char name[128], *end;
235 const char *found = "";
236 {
237 const char* ptr = (*flg) + 1;
238 strcpy(name, "cc/argmachine/");
239 end = name + strlen(name);
240 while(*ptr) {
241 if('.'!=*ptr && '-'!=*ptr) *end++ = *ptr;
242 ++ptr;
243 }
244 *end = '\0';
245 }
246 end = strchr(name, '=');
247 if (end != NULL)
248 *end = '_';
249 if (compile_run(logdepth+1, test_c, NULL, *flg, "", &out) == 0) {
250 if (target_emu_fail(out) || (strncmp(out, "OK", 2) == 0)) {
251 found = *flg;
252 report(" ");
253 report(found);
254 }
255 free(out);
256 }
257 put(name, found);
258 }
259
260 report("\n");
261 return 0;
262 #undef ARGM
263 }
264
265 int find_inline(const char *name, int logdepth, int fatal)
266 {
267 const char *test_c =
268 NL "#include <stdio.h>"
269 NL "static inline void test_inl()"
270 NL "{"
271 NL " puts(\"OK\");"
272 NL "}"
273 NL "int main() {"
274 NL " test_inl();"
275 NL " return 0;"
276 NL "}"
277 NL ;
278 require("cc/cc", logdepth, fatal);
279
280 report("Checking for inline... ");
281 logprintf(logdepth, "find_inline: trying to find inline...\n");
282 logdepth++;
283 if (try(logdepth, NULL, test_c, "OK")) {
284 put("cc/inline", strue);
285 report("Found.\n");
286 return 0;
287 }
288 put("cc/inline", sfalse);
289 report("Not found.\n");
290 return 1;
291 }
292
293 int find_varargmacro(const char *name, int logdepth, int fatal)
294 {
295 const char *test_c =
296 NL "#include <stdio.h>"
297 NL "#define pr(fmt, x...) {printf(\"PR \"); printf(fmt, x); }"
298 NL "int main() {"
299 NL " pr(\"%d %d %s\", 42, 8192, \"test\");"
300 NL " puts(\"\");"
301 NL " return 0;"
302 NL "}"
303 NL ;
304 require("cc/cc", logdepth, fatal);
305
306 report("Checking for vararg macro... ");
307 logprintf(logdepth, "find_varargmacro: trying to find vararg macro...\n");
308 logdepth++;
309 if (try(logdepth, NULL, test_c, "PR 42 8192 test")) {
310 put("cc/varargmacro", strue);
311 report("Found.\n");
312 return 0;
313 }
314 put("cc/varargmacro", sfalse);
315 report("Not found.\n");
316 return 1;
317 }
318
319 int find_funcmacro(const char *name, int logdepth, int fatal)
320 {
321 const char *test_c =
322 NL "#include <stdio.h>"
323 NL "int main() {"
324 NL " printf(\"%s\\n\", __func__);"
325 NL " return 0;"
326 NL "}"
327 NL ;
328 require("cc/cc", logdepth, fatal);
329
330 report("Checking for __func__ macro... ");
331 logprintf(logdepth, "find_funcmacro: trying to find __func__ macro...\n");
332 logdepth++;
333 if (try(logdepth, NULL, test_c, "main")) {
334 put("cc/funcmacro", strue);
335 report("Found.\n");
336 return 0;
337 }
338 put("cc/funcmacro", sfalse);
339 report("Not found.\n");
340 return 1;
341 }
342
343 int find_constructor(const char *name, int logdepth, int fatal)
344 {
345 const char *test_c =
346 NL "#include <stdio.h>"
347 NL "void startup() __attribute__ ((constructor));"
348 NL "void startup()"
349 NL "{"
350 NL " puts(\"OK\");"
351 NL "}"
352 NL "int main() {"
353 NL " return 0;"
354 NL "}"
355 NL ;
356
357 require("cc/cc", logdepth, fatal);
358
359 report("Checking for constructor... ");
360 logprintf(logdepth, "find_constructor: trying to find constructor...\n");
361 logdepth++;
362 if (try(logdepth, NULL, test_c, "OK")) {
363 put("cc/constructor", strue);
364 report("Found.\n");
365 return 0;
366 }
367 put("cc/constructor", sfalse);
368 report("Not found.\n");
369 return 1;
370 }
371
372 int find_destructor(const char *name, int logdepth, int fatal)
373 {
374 const char *test_c =
375 NL "#include <stdio.h>"
376 NL "void startup() __attribute__ ((destructor));"
377 NL "void startup()"
378 NL "{"
379 NL " puts(\"OK\");"
380 NL "}"
381 NL "int main() {"
382 NL " return 0;"
383 NL "}"
384 NL ;
385
386 require("cc/cc", logdepth, fatal);
387
388 report("Checking for destructor... ");
389 logprintf(logdepth, "find_destructor: trying to find destructor...\n");
390 logdepth++;
391 if (try(logdepth, NULL, test_c, "OK")) {
392 put("cc/destructor", strue);
393 report("Found.\n");
394 return 0;
395 }
396 put("cc/destructor", sfalse);
397 report("Not found.\n");
398 return 1;
399 }
400
401 static int test_fattr(const char *name, int logdepth, int fatal, const char *fattr)
402 {
403 char path[64];
404 char test_c[256];
405 const char *test_c_tmp =
406 NL "#include <stdio.h>"
407 NL "static void test1() __attribute__ ((%s));"
408 NL "static void test1()"
409 NL "{"
410 NL " puts(\"OK\");"
411 NL "}"
412 NL "int main() {"
413 NL " puts(\"OK\");"
414 NL " return 0;"
415 NL "}"
416 NL ;
417
418 require("cc/cc", logdepth, fatal);
419
420 sprintf(test_c, test_c_tmp, fattr);
421 sprintf(path, "cc/func_attr/%s/presents", fattr);
422
423 report("Checking for function attribute %s... ", fattr);
424 logprintf(logdepth, "test_fattr: trying to find %s...\n", fattr);
425 logdepth++;
426 if (try(logdepth, NULL, test_c, "OK")) {
427 put(path, strue);
428 report("Found.\n");
429 return 0;
430 }
431 put(path, sfalse);
432 report("Not found.\n");
433 return 1;
434 }
435
436 int find_fattr_unused(const char *name, int logdepth, int fatal)
437 {
438 return test_fattr(name, logdepth, fatal, "unused");
439 }
440
441 static int test_declspec(const char *name, int logdepth, int fatal, const char *dspec)
442 {
443 char path[64];
444 char test_c[256];
445 const char *test_c_tmp =
446 NL "#include <stdio.h>"
447 NL "void __declspec (%s) test1();"
448 NL "void test1()"
449 NL "{"
450 NL " puts(\"OK\");"
451 NL "}"
452 NL "int main() {"
453 NL " test1();"
454 NL " return 0;"
455 NL "}"
456 NL ;
457
458 require("cc/cc", logdepth, fatal);
459
460 sprintf(test_c, test_c_tmp, dspec);
461 sprintf(path, "cc/declspec/%s/presents", dspec);
462
463 report("Checking for declspec %s... ", dspec);
464 logprintf(logdepth, "test_declspec: trying to find %s...\n", dspec);
465 logdepth++;
466 if (try(logdepth, NULL, test_c, "OK")) {
467 put(path, strue);
468 report("Found.\n");
469 return 0;
470 }
471 put(path, sfalse);
472 report("Not found.\n");
473 return 1;
474 }
475
476 int find_declspec_dllimport(const char *name, int logdepth, int fatal)
477 {
478 return test_declspec(name, logdepth, fatal, "dllimport");
479 }
480
481 int find_declspec_dllexport(const char *name, int logdepth, int fatal)
482 {
483 return test_declspec(name, logdepth, fatal, "dllexport");
484 }
485
486 static int test_dll_auxfile(const char *name, int logdepth, int fatal, const char *path, const char *ldflag, const char *filename)
487 {
488 char *ldflags;
489 char test_c[256];
490 const char *test_c_template =
491 NL "#include <stdio.h>"
492 NL "void %s test1();"
493 NL "void test1()"
494 NL "{"
495 NL " puts(\"OK\");"
496 NL "}"
497 NL "int main() {"
498 NL " test1();"
499 NL " return 0;"
500 NL "}"
501 NL ;
502 const char *dspec;
503
504 require("cc/cc", logdepth, fatal);
505 require("cc/declspec/dllexport/*", logdepth, 0);
506
507 if (istrue("cc/declspec/dllexport/presents"))
508 dspec = " __declspec(dllexport) ";
509 else
510 dspec = "";
511
512 sprintf(test_c, test_c_template, dspec);
513
514 report("Checking for DLL flag %s... ", ldflag);
515 logprintf(logdepth, "test_dll_auxfile: trying to find %s...\n", ldflag);
516 logdepth++;
517 ldflags = str_concat("", ldflag, ",", filename, " ", get("cc/ldflags"), NULL);
518 if (try_flags(logdepth, NULL, test_c, NULL, ldflags, "OK")) {
519 unlink(filename);
520 put(path, ldflag);
521 free(ldflags);
522 report("Found.\n");
523 return 0;
524 }
525 unlink(filename);
526 free(ldflags);
527 report("Not found.\n");
528 return 1;
529 }
530
531 int find_cc_wloutimplib(const char *name, int logdepth, int fatal)
532 {
533 return test_dll_auxfile(name, logdepth, fatal, "cc/wloutimplib", "-Wl,--out-implib", "libscconfig_0.a");
534 }
535
536 int find_cc_wloutputdef(const char *name, int logdepth, int fatal)
537 {
538 return test_dll_auxfile(name, logdepth, fatal, "cc/wloutputdef", "-Wl,--output-def", "libscconfig_0.def");
539 }
540
541 /* Hello world program to test compiler flags */
542 static const char *test_hello_world =
543 NL "#include <stdio.h>"
544 NL "int main() {"
545 NL " puts(\"OK\");"
546 NL " return 0;"
547 NL "}"
548 NL ;
549
550 static int try_hello(int logdepth, const char *cflags, const char *ldflags, const char *name, const char *value)
551 {
552 if (try_flags(logdepth, NULL, test_hello_world, cflags, ldflags, "OK")) {
553 put(name, value);
554 report("OK (%s)\n", value);
555 return 1;
556 }
557 return 0;
558 }
559
560 int find_rdynamic(const char *name, int logdepth, int fatal)
561 {
562 const char *node = "cc/rdynamic";
563
564 require("cc/cc", logdepth, fatal);
565
566 report("Checking for rdynamic... ");
567 logprintf(logdepth, "find_rdynamic: trying to find rdynamic...\n");
568 logdepth++;
569
570 if (try_hello(logdepth, NULL, "-rdynamic", node, "-rdynamic")) return 0;
571 if (try_hello(logdepth, NULL, "-Wl,-export-dynamic", node, "-Wl,-export-dynamic")) return 0;
572 if (try_hello(logdepth, NULL, NULL, node, "")) return 0;
573
574 report("Not found.\n");
575 return 1;
576 }
577
578 int find_cc_fpie(const char *name, int logdepth, int fatal)
579 {
580 const char *test_c = test_hello_world;
581
582 require("cc/cc", logdepth, fatal);
583 /* TODO: what about -fpic? */
584
585 report("Checking for -fpie... ");
586 logprintf(logdepth, "find_cc_fpie: trying to find -fpie...\n");
587 logdepth++;
588
589 /* NOTE: some gcc configuration might not pass the -pie flag to the linker, so */
590 /* try to detect whether we can force it to the linker */
591 if (try_icl(logdepth, "cc/fpie", test_c, NULL, "-fpie", "-pie -Wl,-pie")) return 0;
592 if (try_icl(logdepth, "cc/fpie", test_c, NULL, "-fPIE", "-pie -Wl,-pie")) return 0;
593 if (try_icl(logdepth, "cc/fpie", test_c, NULL, "-fpie", "-pie")) return 0;
594 if (try_icl(logdepth, "cc/fpie", test_c, NULL, "-fPIE", "-pie")) return 0;
595 if (try_icl(logdepth, "cc/fpie", test_c, NULL, NULL, NULL)) return 0;
596 return try_fail(logdepth, "cc/fpie");
597 }
598
599 int find_cc_fnopie(const char *name, int logdepth, int fatal)
600 {
601 const char *test_c = test_hello_world;
602
603 require("cc/cc", logdepth, fatal);
604
605 report("Checking for -fno-pie... ");
606 logprintf(logdepth, "find_cc_fnopie: trying to find -fno-pie...\n");
607 logdepth++;
608
609 if (try_icl(logdepth, "cc/fnopie", test_c, NULL, "-fno-pie", NULL)) return 0;
610 if (try_icl(logdepth, "cc/fnopie", test_c, NULL, "-fno-pie", "-static")) return 0;
611 if (try_icl(logdepth, "cc/fnopie", test_c, NULL, NULL, NULL)) return 0;
612 return try_fail(logdepth, "cc/fnopie");
613 }
614
615 int find_cc_fnopic(const char *name, int logdepth, int fatal)
616 {
617 const char *test_c = test_hello_world;
618
619 require("cc/cc", logdepth, fatal);
620
621 report("Checking for -fno-pic... ");
622 logprintf(logdepth, "find_cc_fnopic: trying to find -fno-pic...\n");
623 logdepth++;
624
625 if (try_icl(logdepth, "cc/fnopic", test_c, NULL, "-fno-pic", NULL)) return 0;
626 if (try_icl(logdepth, "cc/fnopic", test_c, NULL, "-fno-pic", "-static")) return 0;
627 if (try_icl(logdepth, "cc/fnopic", test_c, NULL, NULL, NULL)) return 0;
628 return try_fail(logdepth, "cc/fnopic");
629 }
630
631 int find_soname(const char *name, int logdepth, int fatal)
632 {
633
634 require("cc/cc", logdepth, fatal);
635
636 report("Checking for soname... ");
637 logprintf(logdepth, "find_soname: trying to find soname...\n");
638 logdepth++;
639
640 if (try_hello(logdepth, NULL, "-Wl,-soname,libscconfig.0", "cc/soname", "-Wl,-soname,")) return 0;
641 if (try_hello(logdepth, NULL, NULL, "cc/soname", "")) return 0;
642
643 report("Not found.\n");
644 return 1;
645 }
646
647
648 int find_wlrpath(const char *name, int logdepth, int fatal)
649 {
650
651 require("cc/cc", logdepth, fatal);
652
653 report("Checking for rpath... ");
654 logprintf(logdepth, "find_wlrpath: trying to find rpath...\n");
655 logdepth++;
656
657 if (try_hello(logdepth, NULL, "-Wl,-rpath=.", "cc/wlrpath", "-Wl,-rpath=")) return 0;
658
659 report("Not found.\n");
660 return 1;
661 }
662
663 int find_fpic(const char *name, int logdepth, int fatal)
664 {
665
666 require("cc/cc", logdepth, fatal);
667
668 report("Checking for -fpic... ");
669 logprintf(logdepth, "find_fpic: trying to find -fpic...\n");
670 logdepth++;
671
672 if (try_hello(logdepth, NULL, "-fPIC", "cc/fpic", "-fPIC")) return 0;
673 if (try_hello(logdepth, NULL, "-fpic", "cc/fpic", "-fpic")) return 0;
674 if (try_hello(logdepth, NULL, NULL, "cc/fpic", "")) return 0;
675
676 report("Not found.\n");
677 return 1;
678 }
679
680 /* Hello world lib... */
681 static const char *test_lib =
682 NL "#include <stdio.h>"
683 NL "int hello() {"
684 NL " puts(\"OK\");"
685 NL " return 0;"
686 NL "}"
687 NL ;
688
689 /* ...and the corresponding host application */
690 static const char *test_host =
691 NL "#include <stdlib.h>"
692 NL "#include <stdio.h>"
693 NL "#include %s"
694 NL "int main() {"
695 NL " void *handle = NULL;"
696 NL " void (*func)() = NULL;"
697 NL " char *error;"
698 NL
699 NL " handle = dlopen(\"%s\", RTLD_NOW);"
700 NL " if (handle == NULL) {"
701 NL " printf(\"dlopen fails: \", dlerror());"
702 NL " return 1;"
703 NL " }"
704 NL " func = dlsym(handle, \"hello\");"
705 NL " if (func == NULL) {"
706 NL " printf(\"dlsym fails: \", dlerror());"
707 NL " return 1;"
708 NL " }"
709 NL " func();"
710 NL " return 0;"
711 NL "}"
712 NL ;
713
714 static int try_dynlib(int logdepth, const char *cflags, char *concated_ldflags, const char *name, const char *value, const char *host_app_cflags, const char *host_app_ldflags)
715 {
716 char test_host_app[1024];
717 const char *fpic;
718 const char *ld_include;
719 const char *dlc;
720 char *libname, *libname_dyn;
721 char *cflags_c;
722 char *oname = ".o";
723 int ret = 0;
724
725
726 dlc = get("libs/dl-compat");
727 if ((dlc != NULL) && (strcmp(dlc, strue) == 0))
728 ld_include = "<dl-compat.h>";
729 else
730 ld_include = "<dlfcn.h>";
731
732 fpic = get("cc/fpic");
733 if (fpic == NULL) fpic = "";
734
735 if (cflags == NULL)
736 cflags="";
737
738 cflags_c = malloc(strlen(cflags) + 8 + strlen(fpic));
739 sprintf(cflags_c, "%s -c %s", cflags, fpic);
740
741
742 libname_dyn = libname = (char *)get("sys/ext_dynlib");
743 if ((compile_code(logdepth, test_lib, &oname, NULL, cflags_c, NULL) != 0) ||
744 (compile_file(logdepth, oname, &libname_dyn, NULL, NULL, concated_ldflags) != 0)) {
745 report("FAILED (compiling dynlib)\n");
746 }
747 else {
748 sprintf(test_host_app, test_host, ld_include, libname_dyn);
749 if (try_flags(logdepth, NULL, test_host_app, host_app_cflags, host_app_ldflags, "OK")) {
750 put(name, value);
751 report("OK (%s)\n", value);
752 ret = 1;
753 }
754 }
755 unlink(libname_dyn);
756 unlink(oname);
757 if (libname != libname_dyn)
758 free(libname_dyn);
759 free(oname);
760 free(concated_ldflags);
761 free(cflags_c);
762 return ret;
763 }
764
765
766 int find_ldflags_dynlib(const char *name, int logdepth, int fatal)
767 {
768
769 require("cc/cc", logdepth, fatal);
770 require("cc/rdynamic", logdepth, fatal);
771 require("cc/fpic", logdepth, fatal);
772 require("libs/ldl", logdepth, fatal);
773
774 report("Checking for dynamic library ldflags... ");
775 logprintf(logdepth, "find_ldflags_dynlib: trying to find dynamic library ldflags...\n");
776 logdepth++;
777
778 if (try_dynlib(logdepth, NULL, concat_nodes("-dynamic -shared", "cc/rdynamic", "libs/ldl", NULL), "cc/ldflags_dynlib", "-dynamic -shared", NULL, get("libs/ldl"))) return 0;
779 if (try_dynlib(logdepth, NULL, concat_nodes("-shared", "cc/rdynamic", "libs/ldl", NULL), "cc/ldflags_dynlib", "-shared", NULL, get("libs/ldl"))) return 0;
780 report("Not found.\n");
781 return 1;
782 }
783
784 static int try_dll_or_so(int logdepth, int is_dll, const char *lib_ldflags, const char *name, const char *value,
785 const char *dspec_dllexport, const char *dspec_dllimport,
786 const char *app_cflags, const char *app_ldflags)
787 {
788 static const char *test_lib_template =
789 NL "#include <stdio.h>"
790 NL "%s void hello();"
791 NL "void hello() {"
792 NL " puts(\"OK\");"
793 NL "}"
794 NL ;
795 static const char *test_app_template =
796 NL "%s void hello();"
797 NL "int main() {"
798 NL " hello();"
799 NL " return 0;"
800 NL "}"
801 NL ;
802 char test_lib[1024];
803 char test_app[1024];
804 const char *fpic;
805 char *cflags_c;
806 char *oname, *oname_ext;
807 char *libname, *libname_ext;
808 char *appname = NULL, *appname_ext = NULL;
809 char *lib_filename = NULL, *lib_dirname = NULL;
810 char *lib_ldflags_new = NULL;
811 char *app_ldflags_new = NULL;
812 size_t len, ii;
813 int ret = 0;
814
815 ++logdepth;
816
817 require("cc/cc", logdepth, 0);
818 require("cc/cflags", logdepth, 0);
819 require("cc/ldflags", logdepth, 0);
820 require("cc/fpic", logdepth, 0);
821 require("sys/ext_exe", logdepth, 0);
822 require("sys/ext_dynlib_native", logdepth, 0);
823
824 fpic = get("cc/fpic");
825 if (fpic == NULL) fpic = "";
826
827 if (app_cflags == NULL)
828 app_cflags = "";
829
830 if (app_ldflags == NULL)
831 app_ldflags = "";
832
833 cflags_c = str_concat(" ", get("cc/cflags"), "-c", fpic, NULL);
834
835 oname = oname_ext = ".o";
836 libname = libname_ext = (char *)get("sys/ext_dynlib_native");
837 sprintf(test_lib, test_lib_template, dspec_dllexport);
838 lib_ldflags_new = str_concat(" ", get("cc/ldflags"), lib_ldflags, NULL);
839 if ((compile_code(logdepth, test_lib, &oname, NULL, cflags_c, NULL) != 0) ||
840 (compile_file(logdepth, oname, &libname, NULL, NULL, lib_ldflags_new) != 0)) {
841 report("FAILED (compiling %s)\n", (is_dll?"DLL":"SO"));
842 }
843 else {
844 lib_filename = file_name(libname);
845 lib_dirname = dir_name(libname);
846
847 if (!is_dll) {
848 len = strlen(lib_filename) - strlen(libname_ext);
849 for (ii=3; ii<len; ++ii)
850 lib_filename[ii-3] = lib_filename[ii];
851 lib_filename[len-3] = 0;
852 }
853
854 app_ldflags_new = str_concat("", "-L", lib_dirname, " -l", lib_filename,
855 " ", app_ldflags, " ", get("cc/ldflags"), NULL);
856
857 appname = appname_ext = (char *)get("sys/ext_exe");
858 sprintf(test_app, test_app_template, dspec_dllimport);
859 if (compile_code(logdepth, test_app, &appname, NULL, app_cflags, app_ldflags_new) == 0) {
860 put(name, value);
861 report("OK (%s)\n", value);
862 ret = 1;
863 }
864 }
865 if (oname != oname_ext) {
866 unlink(oname);
867 free(oname);
868 }
869 if (libname != libname_ext) {
870 unlink(libname);
871 free(libname);
872 }
873 if (appname != appname_ext) {
874 unlink(appname);
875 free(appname);
876 }
877 free(cflags_c);
878 free(lib_filename);
879 free(lib_dirname);
880 free(lib_ldflags_new);
881 free(app_ldflags_new);
882 return ret;
883 }
884
885 int find_ldflags_dll(const char *name, int logdepth, int fatal)
886 {
887 char dll_ldflags[128];
888 const char *dspec_dllimport;
889 const char *dspec_dllexport;
890 static const char *dll_implib_name = "libscconfigdll_0.a";
891
892 require("cc/cc", logdepth, 1);
893 require("cc/declspec/dllimport/*", logdepth, 0);
894 require("cc/declspec/dllexport/*", logdepth, 0);
895 require("cc/wloutimplib", logdepth, 0);
896
897 report("Checking for DLL ldflags... ");
898 logprintf(logdepth, "find_ldflags_dll: trying to find DLL ldflags...\n");
899
900 if (istrue(get("cc/declspec/dllimport/presents")))
901 dspec_dllimport = " __declspec(dllimport) ";
902 else
903 dspec_dllimport = "";
904
905 if (istrue(get("cc/declspec/dllexport/presents")))
906 dspec_dllexport = " __declspec(dllexport) ";
907 else
908 dspec_dllexport = "";
909
910 if (try_dll_or_so(logdepth+1, 1, "-shared", "cc/ldflags_dll", "-shared",
911 dspec_dllexport, dspec_dllimport, NULL, NULL))
912 return 0;
913
914 if (get("cc/wloutimplib")) {
915 sprintf(dll_ldflags, "-shared %s,%s", get("cc/wloutimplib"), dll_implib_name);
916 if (try_dll_or_so(logdepth+1, 1, dll_ldflags, "cc/ldflags_dll", "-shared",
917 dspec_dllexport, dspec_dllimport, NULL, "-L. -lscconfigdll_0")) {
918 unlink(dll_implib_name);
919 return 0;
920 }
921 unlink(dll_implib_name);
922 }
923
924 report("Not found.\n");
925 return 1;
926 }
927
928 static int find_ldflags_so_impl(const char *name, int logdepth, int fatal)
929 {
930 const char *ldflags[] = { "-dynamic -shared", "-shared", NULL };
931 const char **ldf;
932
933 require("cc/cc", logdepth, 1);
934
935 report("Checking for SO ldflags... ");
936 logprintf(logdepth, "find_ldflags_so: trying to find SO ldflags...\n");
937
938 for (ldf=ldflags; *ldf != NULL; ++ldf)
939 if (try_dll_or_so(logdepth+1, 0, *ldf, "cc/ldflags_so", *ldf,
940 "", "", NULL, ""))
941 return 0;
942
943 report("Not found.\n");
944 return 1;
945 }
946
947 int find_ldflags_so(const char *name, int logdepth, int fatal)
948 {
949 int res;
950 char *old_tmp;
951 char *new_tmp;
952
953 require("/host/sys/tmp", logdepth, 1);
954 require("/host/sys/path_sep", logdepth, 1);
955
956 /* HACK: modify */
957
958 old_tmp = strclone(get("/host/sys/tmp"));
959 new_tmp = str_concat("", old_tmp, get("/host/sys/path_sep"), "lib", NULL);
960 put("/host/sys/tmp", new_tmp);
961 free(new_tmp);
962
963 res = find_ldflags_so_impl(name, logdepth, fatal);
964
965 put("/host/sys/tmp", old_tmp);
966 free(old_tmp);
967
968 return res;
969 }
970
971 /* Hello world program to test compiler flags */
972 static const char *test_alloca =
973 NL "#include <stdio.h>"
974 NL "int main() {"
975 NL " char *s;"
976 NL " s = alloca(128);"
977 NL " if (s != NULL)"
978 NL " puts(\"OK\");"
979 NL " return 0;"
980 NL "}"
981 NL ;
982
983 static int try_alloca(int logdepth, const char *cflags, const char *ldflags, const char *name, const char *value)
984 {
985 if (try_flags(logdepth, NULL, test_alloca, cflags, ldflags, "OK")) {
986 put(name, value);
987 report("OK (%s)\n", value);
988 return 1;
989 }
990 return 0;
991 }
992
993 int find_alloca(const char *name, int logdepth, int fatal)
994 {
995 require("cc/cc", logdepth, fatal);
996
997 report("Checking for alloca()... ");
998 logprintf(logdepth, "find_alloca: trying to find alloca()...\n");
999 logdepth++;
1000
1001 if (try_alloca(logdepth, NULL, NULL, "cc/alloca/presents", "true")) return 0;
1002
1003 put("cc/alloca/presents", "false");
1004 report("Not found.\n");
1005 return 1;
1006 }
1007
1008
1009 int find__exit(const char *name, int logdepth, int fatal)
1010 {
1011 const char *test_c =
1012 NL "#include <stdio.h>"
1013 NL "int main() {"
1014 NL " _exit(0);"
1015 NL " puts(\"BAD\");"
1016 NL " return 0;"
1017 NL "}"
1018 NL ;
1019
1020 require("cc/cc", logdepth, fatal);
1021
1022 report("Checking for _exit()... ");
1023 logprintf(logdepth, "find__exit: trying to find _exit()...\n");
1024 logdepth++;
1025
1026 if (try_flags_inv(logdepth, NULL, test_c, NULL, NULL, "BAD")) {
1027 put("cc/_exit/presents", strue);
1028 report("found\n");
1029 return 0;
1030 }
1031
1032 put("cc/_exit/presents", sfalse);
1033 report("Not found.\n");
1034 return 1;
1035 }
1036
0 /*
1 scconfig - detection of environmental variable access features
2 Copyright (C) 2014 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "db.h"
28 #include "dep.h"
29
30 int find_main_arg3(const char *name, int logdepth, int fatal)
31 {
32 char *out;
33 char *test_c =
34 NL "#include <stdlib.h>"
35 NL "#include <stdio.h>"
36 NL "int main(int argc, char *argv[], char *env[])"
37 NL "{"
38 NL " char **e;"
39 NL " int cnt;"
40 NL " for(e = env, cnt = 0; *e != NULL; e++, cnt++) ;"
41 NL " printf(\"%d\\n\", cnt);"
42 NL " return 0;"
43 NL "}"
44 NL;
45
46 require("cc/cc", logdepth, fatal);
47
48 report("Checking for main() with 3 arguments... ");
49 logprintf(logdepth, "find_main_3args: checking for main() with 3 arguments\n");
50 if (compile_run(logdepth+1, test_c, NULL, NULL, NULL, &out) == 0) {
51 if (atoi(out) > 1) {
52 put("libs/env/main_3arg", strue);
53 report("OK\n");
54 free(out);
55 return 0;
56 }
57 free(out);
58 report("not found (broken output).\n");
59 }
60 else {
61 report("not found (no output).\n");
62 }
63 put("libs/env/main_3arg", sfalse);
64 return 1;
65 }
66
67 int find_environ(const char *name, int logdepth, int fatal)
68 {
69 char *out;
70 char *test_c =
71 NL "#include <stdlib.h>"
72 NL "#include <stdio.h>"
73 NL "extern char **environ;"
74 NL "int main(int argc, char *argv[])"
75 NL "{"
76 NL " char **e;"
77 NL " int cnt;"
78 NL " for(e = environ, cnt = 0; *e != NULL; e++, cnt++) ;"
79 NL " printf(\"%d\\n\", cnt);"
80 NL " return 0;"
81 NL "}"
82 NL;
83
84 require("cc/cc", logdepth, fatal);
85
86 report("Checking for extern environ... ");
87 logprintf(logdepth, "find_environ: checking for extern environ\n");
88 if (compile_run(logdepth+1, test_c, NULL, NULL, NULL, &out) == 0) {
89 if (atoi(out) > 1) {
90 put("libs/env/environ", strue);
91 report("OK\n");
92 free(out);
93 return 0;
94 }
95 free(out);
96 report("not found (broken output).\n");
97 }
98 else {
99 report("not found (no output).\n");
100 }
101 put("libs/env/environ", sfalse);
102 return 1;
103 }
104
105 int find_putenv(const char *name, int logdepth, int fatal)
106 {
107 char *test_c =
108 NL "#include <stdlib.h>"
109 NL "#include <stdio.h>"
110 NL "int main(int argc, char *argv[])"
111 NL "{"
112 NL " putenv(\"SCCONFIG_TEST=bad\");"
113 NL " putenv(\"SCCONFIG_TEST=OK\");"
114 NL " printf(\"%s\\n\", getenv(\"SCCONFIG_TEST\"));"
115 NL " return 0;"
116 NL "}"
117 NL;
118
119 require("cc/cc", logdepth, fatal);
120
121 report("Checking for putenv()... ");
122 logprintf(logdepth, "find_putenv: trying to find putenv...\n");
123 logdepth++;
124
125 if (try_icl(logdepth, "libs/env/putenv", test_c, "", NULL, NULL))
126 return 0;
127 if (try_icl(logdepth, "libs/env/putenv", test_c, "#define _XOPEN_SOURCE", NULL, NULL))
128 return 0;
129 if (try_icl(logdepth, "libs/env/putenv", test_c, "#define _SVID_SOURCE", NULL, NULL))
130 return 0;
131 return try_fail(logdepth, "libs/env/putenv");
132 }
133
134
135 int find_setenv(const char *name, int logdepth, int fatal)
136 {
137 char *test_c =
138 NL "#include <stdlib.h>"
139 NL "#include <stdio.h>"
140 NL "int main(int argc, char *argv[])"
141 NL "{"
142 NL " setenv(\"SCCONFIG_TEST\", \"bad\", 1);"
143 NL " setenv(\"SCCONFIG_TEST\", \"OK\", 1);"
144 NL " printf(\"%s\\n\", getenv(\"SCCONFIG_TEST\"));"
145 NL " return 0;"
146 NL "}"
147 NL;
148
149 require("cc/cc", logdepth, fatal);
150
151 report("Checking for setenv()... ");
152 logprintf(logdepth, "find_setenv: trying to find setenv...\n");
153 logdepth++;
154
155 if (try_icl(logdepth, "libs/env/setenv", test_c, "", NULL, NULL))
156 return 0;
157 if (try_icl(logdepth, "libs/env/setenv", test_c, "#define _BSD_SOURCE", NULL, NULL))
158 return 0;
159 if (try_icl(logdepth, "libs/env/setenv", test_c, "#define _POSIX_C_SOURCE 200112L", NULL, NULL))
160 return 0;
161 if (try_icl(logdepth, "libs/env/setenv", test_c, "#define _XOPEN_SOURCE 600", NULL, NULL))
162 return 0;
163 return try_fail(logdepth, "libs/env/setenv");
164 }
165
0 /*
1 scconfig - detection of standard library features: file system specific calls
2 Copyright (C) 2010 Tibor Palinkas
3 Copyright (C) 2018 Aron Barath
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Project page: http://repo.hu/projects/scconfig
20 Contact via email: scconfig [at] igor2.repo.hu
21 */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include "libs.h"
28 #include "log.h"
29 #include "db.h"
30 #include "dep.h"
31
32 int find_fs_realpath(const char *name, int logdepth, int fatal)
33 {
34 char *test_c =
35 NL "#include <limits.h>"
36 NL "#include <stdlib.h>"
37 NL "#include <stdio.h>"
38 NL "#ifdef PATH_MAX"
39 NL "char out_buf[PATH_MAX];"
40 NL "#else"
41 NL "char out_buf[32768];"
42 NL "#endif"
43 NL "int main() {"
44 NL " if (realpath(\".\", out_buf) == out_buf)"
45 NL " puts(\"OK\");"
46 NL " return 0;"
47 NL "}"
48 NL;
49
50 require("cc/cc", logdepth, fatal);
51
52 report("Checking for realpath()... ");
53 logprintf(logdepth, "find_fs_realpath: trying to find realpath...\n");
54 logdepth++;
55
56 if (try_icl(logdepth, "libs/fs/realpath", test_c, NULL, NULL, NULL)) return 0;
57 if (try_icl(logdepth, "libs/fs/realpath", test_c, "#define _DEFAULT_SOURCE", NULL, NULL)) return 0;
58 if (try_icl(logdepth, "libs/fs/realpath", test_c, "#define _BSD_SOURCE", NULL, NULL)) return 0;
59 return try_fail(logdepth, "libs/fs/realpath");
60 }
61
62
63 int find_fs__fullpath(const char *name, int logdepth, int fatal)
64 {
65 char *test_c =
66 NL "#include <stdio.h>"
67 NL "#include <conio.h>"
68 NL "#include <stdlib.h>"
69 NL "#include <direct.h>"
70 NL "int main() {"
71 NL " char full[_MAX_PATH];"
72 NL " if (_fullpath(full, \".\", _MAX_PATH) != NULL)"
73 NL " puts(\"OK\");"
74 NL " return 0;"
75 NL "}"
76 NL;
77
78 require("cc/cc", logdepth, fatal);
79
80 report("Checking for _fullpath()... ");
81 logprintf(logdepth, "find_fs__fullpath: trying to find _fullpath...\n");
82 logdepth++;
83
84 if (try_icl(logdepth, "libs/fs/_fullpath", test_c, NULL, NULL, NULL)) return 0;
85 return try_fail(logdepth, "libs/fs/_fullpath");
86 }
87
88
89 int find_fs_readdir(const char *name, int logdepth, int fatal)
90 {
91 char *test_c =
92 NL "#include <stdlib.h>"
93 NL "#include <stdio.h>"
94 NL "int main() {"
95 NL " DIR *dirp;"
96 NL " struct dirent *dp;"
97 NL " int found = 0;"
98 NL " if ((dirp = opendir(\".\")) == 0)"
99 NL " return -1;"
100 NL " while ((dp = readdir(dirp)) != 0)"
101 NL " if (strcmp(dp->d_name, \"configure\") == 0)"
102 NL " found++;"
103 NL " closedir(dirp);"
104 NL " if (found == 1)"
105 NL " puts(\"OK\");"
106 NL " return 0;"
107 NL "}";
108 char *includes[] = {
109 "#include <dirent.h>",
110 "#include <sys/dir.h>", /* 4.2BSD */
111 NULL
112 };
113 char **i;
114
115 require("cc/cc", logdepth, fatal);
116
117 report("Checking for readdir()... ");
118 logprintf(logdepth, "find_fs_readdir: trying to find readdir...\n");
119 logdepth++;
120
121 for (i = includes; *i != NULL; i++)
122 if (try_icl(logdepth, "libs/fs/readdir", test_c, *i, NULL, NULL))
123 return 0;
124 return try_fail(logdepth, "libs/fs/readdir");
125 }
126
127
128 int find_fs_findnextfile(const char *name, int logdepth, int fatal)
129 {
130 char *test_c =
131 NL "#include <stdlib.h>"
132 NL "#include <stdio.h>"
133 NL "#include <windows.h>"
134 NL "int main(int argc, char *argv[]) {"
135 NL " WIN32_FIND_DATA fd;"
136 NL " HANDLE h;"
137 NL " int found=0;"
138 NL " h = FindFirstFile(argv[0], &fd);"
139 NL " if (h == INVALID_HANDLE_VALUE)"
140 NL " return -1;"
141 NL " while (FindNextFile(h, &fd) != 0);"
142 NL " found++;"
143 NL " FindClose(h);"
144 NL " if (found > 0)"
145 NL " puts(\"OK\");"
146 NL " return 0;"
147 NL "}";
148
149 require("cc/cc", logdepth, fatal);
150
151 report("Checking for FindNextFile()... ");
152 logprintf(logdepth, "find_fs_findnextfile: trying to find FindNextFile...\n");
153 logdepth++;
154
155 if (try_icl(logdepth, "libs/fs/findnextfile", test_c, NULL, NULL, NULL)) return 0;
156 return try_fail(logdepth, "libs/fs/findnextfile");
157 }
158
159 int find_fs_access(const char *name, int logdepth, int fatal)
160 {
161 char *test_c =
162 NL "int my_test() { return access(\".\", 0); }"
163 NL "#include <stdio.h>"
164 NL "int main() {"
165 NL " if (my_test() == 0)"
166 NL " puts(\"OK\");"
167 NL " return 0;"
168 NL "}"
169 NL;
170 const char* includes[] = { "#include <unistd.h>", "#include <stdlib.h>\n#include <direct.h>", "#include <stdlib.h>", NULL };
171 const char** inc;
172
173 require("cc/cc", logdepth, fatal);
174
175 report("Checking for access()... ");
176 logprintf(logdepth, "find_fs_access: trying to find access...\n");
177 logdepth++;
178
179 for (inc=includes; *inc; ++inc)
180 if (try_icl(logdepth, "libs/fs/access", test_c, *inc, NULL, NULL)) return 0;
181
182 return try_fail(logdepth, "libs/fs/access");
183 }
184
185 int find_fs_access_macros(const char *rname, int logdepth, int fatal)
186 {
187 char *test_c_templ =
188 NL "%s"
189 NL "void my_test() { int a = %s; }"
190 NL "#include <stdio.h>"
191 NL "int main() {"
192 NL " my_test();"
193 NL " puts(\"OK\");"
194 NL " return 0;"
195 NL "}"
196 NL;
197 char test_c[256];
198
199 char *names[][3] = {
200 {"F_OK", "F_OK", NULL},
201 {"R_OK", "R_OK", NULL},
202 {"W_OK", "W_OK", NULL},
203 {"X_OK", "X_OK", NULL},
204 {NULL, NULL, NULL}
205 };
206 char **n;
207 const char* access_includes;
208 int name, pr;
209 char nodename[128];
210
211 require("cc/cc", logdepth, fatal);
212 if (require("libs/fs/access/*", logdepth, fatal)!=0 ||
213 !istrue(get("libs/fs/access/presents"))) {
214 put("libs/fs/access/macros/presents", sfalse);
215 return 1;
216 }
217 access_includes = get("libs/fs/access/includes");
218
219 report("Checking for access macros:\n");
220 logprintf(logdepth, "find_fs_access_macros: trying to find access macros...\n");
221 logdepth++;
222
223 pr = 0;
224 for(name = 0; *names[name] != NULL; name++) {
225 report(" %s...\t", names[name][0]);
226 for(n = &names[name][0]; *n != NULL; n++) {
227 sprintf(test_c, test_c_templ, access_includes, *n);
228 if (try_icl(logdepth, NULL, test_c, NULL, NULL, NULL)) {
229 sprintf(nodename, "libs/fs/access/macros/%s", names[name][0]);
230 put(nodename, *n);
231 report("found as %s\n", *n);
232 pr++;
233 goto found;
234 }
235 }
236 report("not found\n");
237 found:;
238 }
239
240 put("libs/fs/access/macros/presents", ((pr > 0) ? (strue) : (sfalse)));
241 return (pr == 0);
242 }
243
244 int find_fs_stat_macros(const char *rname, int logdepth, int fatal)
245 {
246 char *test_c_templ =
247 NL "#include <sys/stat.h>"
248 NL "#include <sys/types.h>"
249 NL "void my_test() { int a = %s(0); }"
250 NL "#include <stdio.h>"
251 NL "int main() {"
252 NL " my_test();"
253 NL " puts(\"OK\");"
254 NL " return 0;"
255 NL "}"
256 NL;
257 char test_c[256];
258
259 char *names[][3] = {
260 {"S_ISREG", "S_IFREG", NULL},
261 {"S_ISDIR", "S_IFDIR", NULL},
262 {"S_ISCHR", "S_IFCHR", NULL},
263 {"S_ISBLK", "S_IFBLK", NULL},
264 {"S_ISFIFO", "S_IFFIFO", NULL},
265 {"S_ISLNK", "S_IFLNK", NULL},
266 {"S_ISCHR", "S_IFCHR", NULL},
267 {"S_ISSOCK", "S_IFSOCK", NULL},
268 {NULL, NULL, NULL}
269 };
270 char **n;
271 int name, pr;
272 char nodename[128];
273
274 require("cc/cc", logdepth, fatal);
275
276 report("Checking for stat macros:\n");
277 logprintf(logdepth, "find_fs_stat_macros: trying to find stat macros...\n");
278 logdepth++;
279
280 pr = 0;
281 for(name = 0; *names[name] != NULL; name++) {
282 report(" %s...\t", names[name][0]);
283 for(n = &names[name][0]; *n != NULL; n++) {
284 sprintf(test_c, test_c_templ, *n);
285 if (try_icl(logdepth, NULL, test_c, NULL, NULL, NULL)) {
286 sprintf(nodename, "libs/fs/stat/macros/%s", names[name][0]);
287 put(nodename, *n);
288 report("found as %s\n", *n);
289 pr++;
290 goto found;
291 }
292 }
293 report("not found\n");
294 found:;
295 }
296
297 put("libs/fs/stat/macros/presents", ((pr > 0) ? (strue) : (sfalse)));
298 return (pr == 0);
299 }
300
301 int find_fs_stat_fields(const char *rname, int logdepth, int fatal)
302 {
303 char *test_c_templ =
304 NL "#include <sys/stat.h>"
305 NL "#include <sys/types.h>"
306 NL "#include <stdio.h>"
307 NL "int main() {"
308 NL " struct stat st;"
309 NL " (void)st.%s;"
310 NL " puts(\"OK\");"
311 NL " return 0;"
312 NL "}"
313 NL;
314 char test_c[256];
315
316 char *names[] = {"st_blksize", "st_blocks", "st_rdev", "st_mtim", "st_mtime", "st_birthtim", "st_birthtime", NULL };
317 int name, pr;
318 char nodename[128];
319
320 require("cc/cc", logdepth, fatal);
321
322 report("Checking for stat macros:\n");
323 logprintf(logdepth, "find_fs_stat_fields: trying to find stat macros...\n");
324 logdepth++;
325
326 pr = 0;
327 for(name = 0; names[name] != NULL; name++) {
328 report(" %s...\t", names[name]);
329 sprintf(test_c, test_c_templ, names[name]);
330 sprintf(nodename, "libs/fs/stat/fields/%s/presents", names[name]);
331 if (try_icl(logdepth, NULL, test_c, NULL, NULL, NULL)) {
332 put(nodename, strue);
333 report("found\n");
334 pr++;
335 }
336 else {
337 report("not found\n");
338 put(nodename, sfalse);
339 }
340 }
341 return (pr == 0);
342 }
343
344 static int find_fs_any_lstat(const char *name, int logdepth, int fatal, char *fn)
345 {
346 /* make sure <stdio.h> does not affect our lstat() detection */
347 const char *test_c_in =
348 NL "void my_puts(const char *s);"
349 NL "int main() {"
350 NL " struct stat buf;"
351 NL " if (%s(\".\", &buf) == 0)"
352 NL " my_puts(\"OK\");"
353 NL " return 0;"
354 NL "}"
355 NL "#include <stdio.h>"
356 NL "void my_puts(const char *s)"
357 NL "{"
358 NL " puts(s);"
359 NL "}"
360 NL;
361 char test_c[384], node[64];
362 const char *incs[] = {"#include <sys/stat.h>", "#include <unistd.h>", "#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>", NULL};
363 const char **inc;
364
365 require("cc/cc", logdepth, fatal);
366
367 sprintf(node, "libs/fs/%s", fn);
368 sprintf(test_c, test_c_in, fn);
369
370 report("Checking for %s... ", fn);
371 logprintf(logdepth, "find_fs_%s: trying to find lstat()...\n", fn);
372 logdepth++;
373
374 for (inc = incs; *inc; ++inc) {
375 if (try_icl(logdepth, node, test_c, *inc, NULL, NULL))
376 return 0;
377 }
378
379 return try_fail(logdepth, node);
380 }
381
382 int find_fs_lstat(const char *name, int logdepth, int fatal)
383 {
384 return find_fs_any_lstat(name, logdepth, fatal, "lstat");
385 }
386
387 int find_fs_statlstat(const char *name, int logdepth, int fatal)
388 {
389 return find_fs_any_lstat(name, logdepth, fatal, "statlstat");
390 }
391
392
393 int find_fs_getcwd(const char *name, int logdepth, int fatal)
394 {
395 char *test_c =
396 NL "#include <unistd.h>"
397 NL "int main() {"
398 NL " char b[1024];"
399 NL " if (getcwd(b, sizeof(b)) != NULL)"
400 NL " puts(\"OK\");"
401 NL " return 0;"
402 NL "}"
403 NL;
404
405 require("cc/cc", logdepth, fatal);
406
407 report("Checking for getcwd... ");
408 logprintf(logdepth, "find_fs_getcwd: trying to find getcwd()...\n");
409 logdepth++;
410
411 if (try_icl(logdepth, "libs/fs/getcwd", test_c, NULL, NULL, NULL)) return 0;
412 return try_fail(logdepth, "libs/fs/getcwd");
413 }
414
415 int find_fs__getcwd(const char *name, int logdepth, int fatal)
416 {
417 char *test_c =
418 NL "#include <stdlib.h>"
419 NL "int main() {"
420 NL " char b[1024];"
421 NL " if (_getcwd(b, sizeof(b)) != NULL)"
422 NL " puts(\"OK\");"
423 NL " return 0;"
424 NL "}"
425 NL;
426
427 require("cc/cc", logdepth, fatal);
428
429 report("Checking for _getcwd... ");
430 logprintf(logdepth, "find_fs__getcwd: trying to find _getcwd()...\n");
431 logdepth++;
432
433 if (try_icl(logdepth, "libs/fs/_getcwd", test_c, "#include <direct.h>", NULL, NULL)) return 0;
434 return try_fail(logdepth, "libs/fs/_getcwd");
435 }
436
437
438 int find_fs_getwd(const char *name, int logdepth, int fatal)
439 {
440 char *test_c =
441 NL "#include <unistd.h>"
442 NL "int main() {"
443 NL " char b[8192];"
444 NL " if (getwd(b) != NULL)"
445 NL " puts(\"OK\");"
446 NL " return 0;"
447 NL "}"
448 NL;
449
450 require("cc/cc", logdepth, fatal);
451
452 report("Checking for getwd... ");
453 logprintf(logdepth, "find_fs_getwd: trying to find getwd()...\n");
454 logdepth++;
455
456 if (try_icl(logdepth, "libs/fs/getwd", test_c, NULL, NULL, NULL)) return 0;
457 return try_fail(logdepth, "libs/fs/getwd");
458 }
459
460 int find_fs_mkdir(const char *name, int logdepth, int fatal)
461 {
462 char *dir;
463 char test_c[1024];
464 char *test_c_in =
465 NL "#include <stdio.h>"
466 NL "int main() {"
467 NL no_implicit(int, "mkdir", "mkdir")
468 NL " if (mkdir(\"%s\"%s) == 0)"
469 NL " puts(\"OK\");"
470 NL " return 0;"
471 NL "}"
472 NL;
473
474 require("cc/cc", logdepth, fatal);
475
476 dir = tempfile_new("");
477 unlink(dir);
478
479 report("Checking for mkdir... ");
480 logprintf(logdepth, "find_fs_mkdir: trying to find mkdir()...\n");
481 logdepth++;
482
483 /* POSIX, 2 arguments, standard includes */
484 sprintf(test_c, test_c_in, dir, ", 0755");
485 if (try_icl(logdepth, "libs/fs/mkdir", test_c, "#include <sys/types.h>\n#include <sys/stat.h>\n", NULL, NULL)) {
486 if (!is_dir(dir))
487 goto oops1;
488 put("libs/fs/mkdir/num_args", "2");
489 rmdir(dir);
490 return 0;
491 }
492
493 /* POSIX, 2 arguments, no includes */
494 oops1:;
495 sprintf(test_c, test_c_in, dir, ", 0755");
496 if (try_icl(logdepth, "libs/fs/mkdir", test_c, NULL, NULL, NULL)) {
497 if (!is_dir(dir))
498 goto oops2;
499 put("libs/fs/mkdir/num_args", "2");
500 rmdir(dir);
501 return 0;
502 }
503
504 /* win32, 1 argument, with <direct.h> */
505 oops2:;
506 sprintf(test_c, test_c_in, dir, "");
507 if (try_icl(logdepth, "libs/fs/mkdir", test_c, "#include <direct.h>\n", NULL, NULL)) {
508 if (!is_dir(dir))
509 goto oops3;
510 put("libs/fs/mkdir/num_args", "1");
511 rmdir(dir);
512 return 0;
513 }
514
515 oops3:;
516 put("libs/fs/mkdir/includes", "");
517 put("libs/fs/mkdir/ldflags", "");
518 put("libs/fs/mkdir/cdflags", "");
519
520 rmdir(dir);
521 return try_fail(logdepth, "libs/fs/mkdir");
522 }
523
524 int find_fs__mkdir(const char *name, int logdepth, int fatal)
525 {
526 char *dir;
527 char test_c[1024];
528 char *test_c_in =
529 NL "#include <stdio.h>"
530 NL "int main() {"
531 NL " if (_mkdir(\"%s\"%s) == 0)"
532 NL " puts(\"OK\");"
533 NL " return 0;"
534 NL "}"
535 NL;
536
537 require("cc/cc", logdepth, fatal);
538
539 dir = tempfile_new("");
540 unlink(dir);
541
542 report("Checking for _mkdir... ");
543 logprintf(logdepth, "find_fs__mkdir: trying to find _mkdir()...\n");
544 logdepth++;
545
546 /* win32, 2 arguments, standard includes */
547 sprintf(test_c, test_c_in, dir, ", 0755");
548 if (try_icl(logdepth, "libs/fs/_mkdir", test_c, "#include <direct.h>\n", NULL, NULL)) {
549 if (!is_dir(dir))
550 goto oops1;
551 put("libs/fs/_mkdir/num_args", "2");
552 rmdir(dir);
553 return 0;
554 }
555
556 oops1:;
557 /* win32, 1 argument, standard includes */
558 sprintf(test_c, test_c_in, dir, "");
559 if (try_icl(logdepth, "libs/fs/_mkdir", test_c, "#include <direct.h>\n", NULL, NULL)) {
560 if (!is_dir(dir))
561 goto oops2;
562 put("libs/fs/_mkdir/num_args", "1");
563 rmdir(dir);
564 return 0;
565 }
566
567 oops2:;
568 put("libs/fs/_mkdir/includes", "");
569 put("libs/fs/_mkdir/ldflags", "");
570 put("libs/fs/_mkdir/cdflags", "");
571
572 rmdir(dir);
573 return try_fail(logdepth, "libs/fs/_mkdir");
574 }
575
576 int find_fs_mkdtemp(const char *name, int logdepth, int fatal)
577 {
578 char *test_c =
579 NL "#include <stdio.h>"
580 NL "#include <unistd.h>"
581 NL "#include <string.h>"
582 NL "int main() {"
583 NL " char fn[32], *o;"
584 NL " strcpy(fn, \"scc.XXXXXX\");"
585 NL " o = mkdtemp(fn);"
586 NL " if ((o != NULL) && (strstr(o, \"scc.\") != NULL)) {"
587 NL " remove(o);"
588 NL " puts(\"OK\");"
589 NL " }"
590 NL " return 0;"
591 NL "}"
592 NL;
593
594 require("cc/cc", logdepth, fatal);
595
596 report("Checking for mkdtemp... ");
597 logprintf(logdepth, "find_fs_mkdtemp: trying to find mkdtemp()...\n");
598 logdepth++;
599
600 if (try_icl(logdepth, "libs/fs/mkdtemp", test_c, "#include <stdlib.h>\n", NULL, NULL)) return 0;
601 if (try_icl(logdepth, "libs/fs/mkdtemp", test_c, "#define _BSD_SOURCE\n#include <stdlib.h>\n", NULL, NULL)) return 0;
602 return try_fail(logdepth, "libs/fs/mkdtemp");
603 }
604
605 int find_fs_mmap(const char *name, int logdepth, int fatal)
606 {
607 char test_c[1024];
608 char *tmp;
609 FILE *f;
610 char *test_c_in =
611 NL "#include <stdio.h>"
612 NL "#include <unistd.h>"
613 NL "#include <string.h>"
614 NL "#include <sys/types.h>"
615 NL "#include <sys/stat.h>"
616 NL "#include <fcntl.h>"
617 NL "int main() {"
618 NL " int fd, size = 11;"
619 NL " void *p;"
620 NL " fd = open(\"%s\", O_RDONLY);"
621 NL " p = mmap(0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);"
622 NL " if (p == NULL) {"
623 NL " puts(\"mmap fail\");"
624 NL " return 0;"
625 NL " }"
626 NL " if (strcmp(p, \"hello world\") != 0) {"
627 NL " puts(\"strcmp fail\");"
628 NL " return 0;"
629 NL " }"
630 NL " if (munmap(p, size) != 0) {"
631 NL " puts(\"munmap fail\");"
632 NL " return 0;"
633 NL " }"
634 NL " puts(\"OK\");"
635 NL " return 0;"
636 NL "}"
637 NL;
638
639 require("cc/cc", logdepth, fatal);
640
641 tmp = tempfile_new("");
642 f = fopen(tmp, "w");
643 fprintf(f, "hello world");
644 fclose(f);
645 sprintf(test_c, test_c_in, tmp);
646
647 report("Checking for mmap... ");
648 logprintf(logdepth, "find_fs_mmap: trying to find mmap()...\n");
649 logdepth++;
650
651 if (try_icl(logdepth, "libs/fs/mmap", test_c, "#include <sys/mman.h>\n", NULL, NULL)) {
652 unlink(tmp);
653 free(tmp);
654 return 0;
655 }
656
657 unlink(tmp);
658 free(tmp);
659 return try_fail(logdepth, "libs/fs/mmap");
660 }
661
662 /* Haiku/BeOS next_dev */
663 int find_fsmount_next_dev(const char *name, int logdepth, int fatal)
664 {
665 char *test_c =
666 NL "#include <stdio.h>"
667 NL "int main()"
668 NL "{"
669 NL " int32 pos = 0;"
670 NL " dev_t res = next_dev(&pos);"
671 NL " if (res >= 0)"
672 NL " puts(\"OK\");"
673 NL " return 0;"
674 NL "}"
675 NL;
676
677 require("cc/cc", logdepth, fatal);
678
679 report("Checking for next_dev... ");
680 logprintf(logdepth, "find_fsmount_next_dev: trying to find next_dev()...\n");
681 logdepth++;
682
683 if (try_icl(logdepth, "libs/fsmount/next_dev", test_c, "#include <fs_info.h>\n", NULL, NULL)) return 0;
684 return try_fail(logdepth, "libs/fsmount/next_dev");
685 }
686
687 int find_fsmount_fsstat_fields(const char *name, int logdepth, int fatal)
688 {
689 const char *fields[] = {"f_fstypename", NULL};
690 return try_icl_sfields(logdepth, "libs/fsmount/struct_fsstat", "struct fsstat", fields, "#include <sys/fsstat.h>", NULL, NULL, 0);
691 }
692
693 int find_fsmount_statfs_fields(const char *name, int logdepth, int fatal)
694 {
695 const char *fields[] = {"f_fstypename", "f_type", NULL};
696 return try_icl_sfields(logdepth, "libs/fsmount/struct_statfs", "struct statfs", fields, "#include <sys/statfs.h>", NULL, NULL, 0);
697 }
698
699 int find_fsmount_statvfs_fields(const char *name, int logdepth, int fatal)
700 {
701 const char *fields[] = {"f_fstypename", "f_type", "f_basetype", NULL};
702 return try_icl_sfields(logdepth, "libs/fsmount/struct_statvfs", "struct statvfs", fields, "#include <sys/statvfs.h>", NULL, NULL, 0);
703 }
704
705 int find_fs_ustat(const char *name, int logdepth, int fatal)
706 {
707 const char *key = "libs/fs/ustat";
708 const char *test_c =
709 NL "#include <stdio.h>"
710 NL "#include <sys/stat.h>"
711 NL "int main()"
712 NL "{"
713 NL " struct stat stat_buf;"
714 NL " struct ustat ustat_buf;"
715 NL " if (stat(\".\", &stat_buf) == 0 &&"
716 NL " ustat(stat_buf.st_dev, &ustat_buf) == 0)"
717 NL " puts(\"OK\");"
718 NL " return 0;"
719 NL "}"
720 NL;
721
722 require("cc/cc", logdepth, fatal);
723
724 report("Checking for ustat... ");
725 logprintf(logdepth, "find_fs_ustat: trying to find ustat()...\n");
726 logdepth++;
727
728 if (try_icl(logdepth, key, test_c, "#include <ustat.h>", NULL, NULL)) return 0;
729 if (try_icl(logdepth, key, test_c, "#include <unistd.h>", NULL, NULL)) return 0;
730 if (try_icl(logdepth, key, test_c, "#include <sys/types.h>\n#include <unistd.h>", NULL, NULL)) return 0;
731 if (try_icl(logdepth, key, test_c, "#include <sys/types.h>\n#include <unistd.h>\n#include <ustat.h>", NULL, NULL)) return 0;
732 return try_fail(logdepth, key);
733 }
734
735 int find_fs_statfs(const char *name, int logdepth, int fatal)
736 {
737 const char *key = "libs/fs/statfs";
738 const char *test_c =
739 NL "#include <stdio.h>"
740 NL "int main()"
741 NL "{"
742 NL " struct statfs statfs_buf;"
743 NL " if (statfs(\".\", &statfs_buf) == 0)"
744 NL " puts(\"OK\");"
745 NL " return 0;"
746 NL "}"
747 NL;
748
749 require("cc/cc", logdepth, fatal);
750
751 report("Checking for statfs... ");
752 logprintf(logdepth, "find_fs_statfs: trying to find statfs()...\n");
753 logdepth++;
754
755 if (try_icl(logdepth, key, test_c, "#include <sys/statfs.h>", NULL, NULL)) return 0;
756 if (try_icl(logdepth, key, test_c, "#include <sys/vfs.h>", NULL, NULL)) return 0;
757 return try_fail(logdepth, key);
758 }
759
760 int find_fs_statvfs(const char *name, int logdepth, int fatal)
761 {
762 const char *key = "libs/fs/statvfs";
763 const char *test_c =
764 NL "#include <stdio.h>"
765 NL "int main()"
766 NL "{"
767 NL " struct statvfs statvfs_buf;"
768 NL " if (statvfs(\".\", &statvfs_buf) == 0)"
769 NL " puts(\"OK\");"
770 NL " return 0;"
771 NL "}"
772 NL;
773
774 require("cc/cc", logdepth, fatal);
775
776 report("Checking for statvfs... ");
777 logprintf(logdepth, "find_fs_statvfs: trying to find statvfs()...\n");
778 logdepth++;
779
780 if (try_icl(logdepth, key, test_c, "#include <sys/statvfs.h>", NULL, NULL)) return 0;
781 return try_fail(logdepth, key);
782 }
783
784 int find_fs_flock(const char *name, int logdepth, int fatal)
785 {
786 const char *key = "libs/fs/flock";
787 const char *test_c =
788 NL "#include <stdio.h>"
789 NL "int main()"
790 NL "{"
791 NL " if (flock(1, LOCK_UN) == 0)"
792 NL " puts(\"OK\");"
793 NL " return 0;"
794 NL "}"
795 NL;
796
797 require("cc/cc", logdepth, fatal);
798
799 report("Checking for flock... ");
800 logprintf(logdepth, "find_fs_flock: trying to find flock()...\n");
801 logdepth++;
802
803 if (try_icl(logdepth, key, test_c, "#include <sys/file.h>", NULL, NULL)) return 0;
804 return try_fail(logdepth, key);
805 }
0 /*
1 scconfig - detection of file system tools
2 Copyright (C) 2009..2012 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include "libs.h"
27 #include "log.h"
28 #include "db.h"
29 #include "dep.h"
30 #include "dep.h"
31
32 static int test_cp_ln(int logdepth, const char *command, int link)
33 {
34 char *src, *dst, *src_esc, *dst_esc;
35 char *cmd, *result;
36 char *test_string = "works.";
37 int ret;
38
39 logprintf(logdepth, "trying '%s'\n", command);
40
41 src = tempfile_dump(test_string, "");
42 dst = tempfile_new("");
43 if (link)
44 unlink(dst);
45
46 src_esc = shell_escape_dup(src);
47 dst_esc = shell_escape_dup(dst);
48 cmd = malloc(strlen(command) + strlen(src_esc) + strlen(dst_esc) + 32);
49 sprintf(cmd, "%s %s %s", command, src_esc, dst_esc);
50 run_shell(logdepth, cmd, NULL);
51 free(cmd);
52 free(src_esc);
53 free(dst_esc);
54
55 result = load_file(dst);
56 ret = !strcmp(result, test_string);
57 logprintf(logdepth+1, "result: '%s' == '%s' (%d)\n", result, test_string, ret);
58 free(result);
59
60 unlink(src);
61 free(src);
62
63 result = load_file(dst);
64 if (link) {
65 if (strcmp(result, test_string) == 0) {
66 report("Warning: link is copy (or hard link). ");
67 logprintf(logdepth+1, "Warning: link is copy (or hard link).\n");
68 }
69 }
70 else {
71 if (strcmp(result, test_string) != 0) {
72 report("Warning: copy is symlink. ");
73 logprintf(logdepth+1, "Warning: copy is symlink.\n");
74 }
75 }
76 free(result);
77
78 if (ret) {
79 if (link)
80 put("fstools/ln", command);
81 else
82 put("fstools/cp", command);
83
84 report("OK (%s)\n", command);
85 }
86
87 unlink(dst);
88 free(dst);
89 return ret;
90 }
91
92 static int test_mv(int logdepth, const char *command)
93 {
94 char *src, *dst, *src_esc, *dst_esc;
95 char *cmd, *result;
96 char *test_string = "works.";
97 int ret;
98
99 logprintf(logdepth, "trying '%s'\n", command);
100
101 src = tempfile_dump(test_string, "");
102 dst = tempfile_new("");
103 unlink(dst);
104
105 src_esc = shell_escape_dup(src);
106 dst_esc = shell_escape_dup(dst);
107 cmd = malloc(strlen(command) + strlen(src_esc) + strlen(dst_esc) + 32);
108 sprintf(cmd, "%s %s %s", command, src_esc, dst_esc);
109 run_shell(logdepth, cmd, NULL);
110 free(cmd);
111 free(src_esc);
112 free(dst_esc);
113
114 result = load_file(dst);
115 ret = !strcmp(result, test_string);
116 logprintf(logdepth+1, "result: '%s' == '%s' (%d)\n", result, test_string, ret);
117 free(result);
118
119 if (file_size(src) > 0) {
120 report("Warning: mv is copy. ");
121 logprintf(logdepth+1, "Warning: mv is copy.\n");
122 }
123
124 if (ret) {
125 put("fstools/mv", command);
126 report("OK (%s)\n", command);
127 }
128
129 unlink(dst);
130 unlink(src);
131 free(dst);
132 free(src);
133 return ret;
134 }
135
136 static int test_mkdir(int logdepth, const char *command)
137 {
138 char *dir, *file;
139 char *dir_esc;
140 char *cmd, *result;
141 char *test_string = "works.";
142 int ret = 0, had_p;
143 FILE *f;
144
145 logprintf(logdepth, "trying '%s'\n", command);
146 dir = tempfile_new("");
147 dir_esc = shell_escape_dup(dir);
148 unlink(dir);
149
150 had_p = is_dir("-p");
151
152 cmd = malloc(strlen(command) + strlen(dir_esc) + 32);
153 sprintf(cmd, "%s %s", command, dir_esc);
154 run_shell(logdepth, cmd, NULL);
155 free(cmd);
156
157 file = malloc(strlen(dir) + 32);
158 sprintf(file, "%s/test", dir);
159 f = fopen(file, "w");
160 if (f != NULL) {
161 fputs(test_string, f);
162 fclose(f);
163 result = load_file(file);
164 if (strcmp(result, test_string) == 0)
165 ret = 1;
166 free(result);
167 }
168
169 unlink(file);
170 unlink(dir);
171
172 cmd = malloc(strlen(dir) + 32);
173 sprintf(cmd, "rmdir %s", dir_esc);
174 run_shell(logdepth, cmd, NULL);
175 free(cmd);
176
177 free(file);
178 free(dir);
179 free(dir_esc);
180
181 /* This is a bit ugly, but on win32 or other systems where mkdir works
182 but -p doesn't have an effect, a directory called -p may be left over... */
183 if ((!had_p) && (is_dir("-p"))) {
184 unlink("-p");
185 return 0;
186 }
187
188 if (ret != 0) {
189 put("fstools/mkdir", command);
190 report("OK (%s)\n", command);
191 }
192
193 return ret;
194 }
195
196 static int test_rm(int logdepth, const char *command)
197 {
198 char *src, *src_esc, *cmd, *test_string = "works.";
199 int ret;
200
201 logprintf(logdepth, "trying '%s'\n", command);
202
203 src = tempfile_dump(test_string, "");
204
205 if (file_size(src) < 0) {
206 report("error: can't create temp file\n");
207 free(src);
208 return 0;
209 }
210
211
212 src_esc = shell_escape_dup(src);
213 cmd = malloc(strlen(command) + strlen(src_esc) + 32);
214 sprintf(cmd, "%s %s", command, src_esc);
215 run_shell(logdepth, cmd, NULL);
216 free(cmd);
217 free(src_esc);
218
219 ret = file_size(src) < 0;
220
221 if (ret) {
222 put("fstools/rm", command);
223 report("OK (%s)\n", command);
224 }
225 else
226 unlink(src);
227
228 free(src);
229 return ret;
230 }
231
232 static int test_ar(int logdepth, const char *command)
233 {
234 char *src, *dst, *src_esc, *dst_esc;
235 char *cmd, *result, *expected;
236 char *test_string = "works.";
237 const char *path_sep;
238 int ret = 0;
239
240 logprintf(logdepth, "trying '%s'\n", command);
241 path_sep = get("sys/path_sep");
242
243 src = tempfile_dump(test_string, "");
244 dst = tempfile_new("");
245 unlink(dst);
246
247 src_esc = shell_escape_dup(src);
248 dst_esc = shell_escape_dup(dst);
249 cmd = malloc(strlen(command) + strlen(src_esc) + strlen(dst_esc) + 32);
250 sprintf(cmd, "%s ru %s %s", command, dst_esc, src_esc);
251 run_shell(logdepth, cmd, NULL);
252 sprintf(cmd, "%s t %s", command, dst_esc);
253 run_shell(logdepth, cmd, &result);
254 free(cmd);
255 free(dst_esc);
256 free(src_esc);
257
258 if (result != NULL) {
259 expected = str_rchr(src, *path_sep);
260 if (expected == NULL)
261 expected = src;
262 else
263 expected++;
264
265 ret = strncmp(expected, result, strlen(expected)) == 0;
266 if (ret) {
267 put("fstools/ar", command);
268 report("OK (%s)\n", command);
269 }
270 free(result);
271 }
272
273 unlink(src);
274 unlink(dst);
275 free(src);
276 free(dst);
277 return ret;
278 }
279
280 static int test_ranlib(int logdepth, const char *command, const char *obj)
281 {
282 char *cmd, *archive, *archive_esc, *obj_esc;
283 const char *ar;
284 int ret;
285 ar = get("fstools/ar");
286 logprintf(logdepth, "trying '%s'\n", command);
287
288 archive = tempfile_new(".a");
289 archive_esc = shell_escape_dup(archive);
290 obj_esc = shell_escape_dup(obj);
291 cmd = malloc(strlen(command) + strlen(obj_esc) + strlen(archive_esc) + 64);
292
293 sprintf(cmd, "%s r %s %s", ar, archive_esc, obj_esc);
294 unlink(archive);
295 ret = run_shell(logdepth, cmd, NULL) == 0;
296 if (!ret)
297 goto fin;
298
299 sprintf(cmd, "%s %s", command, archive_esc);
300 ret = run_shell(logdepth, cmd, NULL) == 0;
301
302 if (ret) {
303 put("fstools/ranlib", command);
304 report("OK (%s)\n", command);
305 }
306
307 fin:;
308 unlink(archive);
309 free(archive);
310 free(cmd);
311 free(archive_esc);
312 free(obj_esc);
313 return ret;
314 }
315
316 static int test_awk(int logdepth, const char *command)
317 {
318 char cmd[1024];
319 char *out;
320 int ret = 0;
321 char *script, *script_esc;
322
323 /* For some reason windows awk doesn't like the code with NLs */
324 char *test_awk =
325 "BEGIN {"
326 " gsub(\"b\", \"B\", t);"
327 " print t;"
328 "}";
329
330 logprintf(logdepth, "trying '%s'\n", command);
331 script = tempfile_dump(test_awk, ".awk");
332 script_esc = shell_escape_dup(script);
333 sprintf(cmd, "%s -v \"t=blobb\" -f %s", command, script_esc);
334 free(script_esc);
335 run_shell(logdepth, cmd, &out);
336 unlink(script);
337 free(script);
338
339 if ((out != NULL) && (strncmp(out, "BloBB", 5) == 0)) {
340 put("fstools/awk", command);
341 report("OK (%s)\n", command);
342 ret = 1;
343 }
344
345 free(out);
346 return ret;
347 }
348
349 static int test_cat(int logdepth, const char *command)
350 {
351 char cmd[1024];
352 char *out;
353 int ret = 0;
354 char *fn, *fn_esc;
355 const char *test_str = "hello world";
356
357 logprintf(logdepth, "trying '%s'\n", command);
358 fn = tempfile_dump(test_str, ".txt");
359 fn_esc = shell_escape_dup(fn);
360 sprintf(cmd, "%s %s", command, fn_esc);
361 run_shell(logdepth, cmd, &out);
362 unlink(fn);
363 free(fn);
364 free(fn_esc);
365
366 if ((out != NULL) && (strncmp(out, test_str, strlen(test_str)) == 0)) {
367 put("fstools/cat", command);
368 report("OK (%s)\n", command);
369 ret = 1;
370 }
371
372 free(out);
373 return ret;
374 }
375
376 static int test_sed(int logdepth, const char *command)
377 {
378 char cmd[1024];
379 char *out;
380 int ret = 0;
381 char *fn, *fn_esc;
382 const char *test_str_in = "hello world";
383 const char *test_str_out = "he11o wor1d";
384
385 logprintf(logdepth, "trying '%s'\n", command);
386 fn = tempfile_dump(test_str_in, ".txt");
387 fn_esc = shell_escape_dup(fn);
388 sprintf(cmd, "%s \"s/l/1/g\" < %s", command, fn_esc);
389 run_shell(logdepth, cmd, &out);
390 unlink(fn);
391 free(fn);
392 free(fn_esc);
393
394 if ((out != NULL) && (strncmp(out, test_str_out, strlen(test_str_out)) == 0)) {
395 put("fstools/sed", command);
396 report("OK (%s)\n", command);
397 ret = 1;
398 }
399
400 free(out);
401 return ret;
402 }
403
404 static int test_chmodx(int logdepth, const char *command)
405 {
406 char *cmd, *tmp, *tmp_esc, *out, *s;
407 int ret;
408
409 logprintf(logdepth, "trying '%s'\n", command);
410 tmp = tempfile_dump("#!/bin/sh\necho OK\n", ".bat");
411
412 tmp_esc = shell_escape_dup(tmp);
413 cmd = malloc(strlen(command) + strlen(tmp_esc) + 16);
414 sprintf(cmd, "%s %s", command, tmp_esc);
415 ret = run_shell(logdepth, cmd, NULL) == 0;
416 free(cmd);
417 if (!ret) {
418 free(tmp_esc);
419 return ret;
420 }
421
422 ret = run(logdepth+1, tmp_esc, &out);
423 free(tmp_esc);
424
425 if (ret == 0) {
426 for(s = out; s != NULL; s = str_chr(s, '\n')) {
427 logprintf(logdepth+1, "chmod line to test: '%s'\n", s);
428 if ((s[0] == 'O') && (s[1] == 'K')) {
429 logprintf(logdepth+2, "(OK)\n");
430 ret = 1;
431 break;
432 }
433 s++;
434 }
435 }
436 else
437 ret = 0;
438
439 free(out);
440 if (ret) {
441 put("fstools/chmodx", command);
442 logprintf(logdepth, "chmodx command validated: '%s'\n", command);
443 report("OK (%s)\n", command);
444 }
445 unlink(tmp);
446 return ret;
447 }
448
449 static int test_file(int logdepth, const char *node, const char *command)
450 {
451 char cmd[1024];
452 char *out;
453 int ret = 0;
454 char *fn, *fn_esc;
455
456 logprintf(logdepth, "trying '%s'\n", command);
457 fn = tempfile_dump("plain text file\r\n", ".txt");
458 fn_esc = shell_escape_dup(fn);
459 sprintf(cmd, "%s %s", command, fn_esc);
460 run_shell(logdepth, cmd, &out);
461 unlink(fn);
462 free(fn);
463 free(fn_esc);
464
465 if ((out != NULL) && (strstr(out, "text") != NULL)) {
466 put(node, command);
467 report("OK (%s)\n", command);
468 ret = 1;
469 }
470
471 free(out);
472 return ret;
473 }
474
475 int find_fstools_cp(const char *name, int logdepth, int fatal)
476 {
477 const char *cp;
478
479 (void) fatal; /* to suppress compiler warnings about not using fatal */
480
481 report("Checking for cp... ");
482 logprintf(logdepth, "find_fstools_cp: trying to find cp...\n");
483 logdepth++;
484
485 cp = get("/arg/fstools/cp");
486 if (cp == NULL) {
487 if (test_cp_ln(logdepth, "cp -rp", 0)) return 0;
488 if (test_cp_ln(logdepth, "cp -r", 0)) return 0;
489 if (test_cp_ln(logdepth, "copy /r", 0)) return 0; /* wine */
490 }
491 else {
492 report(" user provided (%s)...", cp);
493 if (test_cp_ln(logdepth, cp, 0)) return 0;
494 }
495 return 1;
496 }
497
498 int find_fstools_ln(const char *name, int logdepth, int fatal)
499 {
500 const char *ln;
501
502 (void) fatal; /* to suppress compiler warnings about not using fatal */
503
504 report("Checking for ln... ");
505 logprintf(logdepth, "find_fstools_ln: trying to find ln...\n");
506 logdepth++;
507
508 ln = get("/arg/fstools/ln");
509 if (ln == NULL) {
510 if (test_cp_ln(logdepth, "ln -sf",1 )) return 0;
511 if (test_cp_ln(logdepth, "ln -s",1 )) return 0;
512 if (test_cp_ln(logdepth, "ln", 1)) return 0;
513 /* "mklink /H" -> win32 equivalent to "ln" */
514 /* "cp -s" -> same as "ln -s" */
515 /* "cp -l" -> same as "ln" */
516 if (test_cp_ln(logdepth, "cp", 1)) return 0;
517 }
518 else {
519 report(" user provided (%s)...", ln);
520 if (test_cp_ln(logdepth, ln, 1)) return 0;
521 }
522 return 1;
523 }
524
525 int find_fstools_mv(const char *name, int logdepth, int fatal)
526 {
527 const char *mv;
528
529 (void) fatal; /* to suppress compiler warnings about not using fatal */
530
531 report("Checking for mv... ");
532 logprintf(logdepth, "find_fstools_mv: trying to find mv...\n");
533 logdepth++;
534
535 mv = get("/arg/fstools/mv");
536 if (mv == NULL) {
537 if (test_mv(logdepth, "mv")) return 0;
538 if (test_mv(logdepth, "move")) return 0; /* win32 */
539 if (test_mv(logdepth, "cp")) return 0;
540 }
541 else {
542 report(" user provided (%s)...", mv);
543 if (test_mv(logdepth, mv)) return 0;
544 }
545 return 1;
546 }
547
548 int find_fstools_rm(const char *name, int logdepth, int fatal)
549 {
550 const char *rm;
551
552 (void) fatal; /* to suppress compiler warnings about not using fatal */
553
554 report("Checking for rm... ");
555 logprintf(logdepth, "find_fstools_rm: trying to find rm...\n");
556 logdepth++;
557
558 rm = get("/arg/fstools/rm");
559 if (rm == NULL) {
560 if (test_rm(logdepth, "rm -rf")) return 0;
561 if (test_rm(logdepth, "rm -f")) return 0;
562 if (test_rm(logdepth, "rm")) return 0;
563 if (test_rm(logdepth, "del")) return 0; /* for win32 */
564 }
565 else {
566 report(" user provided (%s)...", rm);
567 if (test_rm(logdepth, rm)) return 0;
568 }
569 return 1;
570 }
571
572 int find_fstools_mkdir(const char *name, int logdepth, int fatal)
573 {
574 const char *mkdir;
575
576 (void) fatal; /* to suppress compiler warnings about not using fatal */
577
578 report("Checking for mkdir... ");
579 logprintf(logdepth, "find_fstools_mkdir: trying to find mkdir...\n");
580 logdepth++;
581
582 mkdir = get("/arg/fstools/mkdir");
583 if (mkdir == NULL) {
584 if (test_mkdir(logdepth, "mkdir -p")) return 0;
585 if (test_mkdir(logdepth, "md")) return 0; /* for win32 */
586 }
587 else {
588 report(" user provided (%s)...", mkdir);
589 if (test_mkdir(logdepth, mkdir)) return 0;
590 }
591 return 1;
592 }
593
594 int find_fstools_ar(const char *name, int logdepth, int fatal)
595 {
596 const char *ar, *target;
597 char *targetar;
598 int len;
599
600 (void) fatal; /* to suppress compiler warnings about not using fatal */
601
602 require("sys/path_sep", logdepth, fatal);
603
604
605 report("Checking for ar... ");
606 logprintf(logdepth, "find_fstools_ar: trying to find ar...\n");
607 logdepth++;
608
609 ar = get("/arg/fstools/ar");
610 if (ar == NULL) {
611 target = get("/arg/sys/target");
612 if (target != NULL) {
613 logprintf(logdepth+1, "find_ar: crosscompiling for '%s', looking for target ar\n", target);
614 len = strlen(target);
615 targetar = malloc(len + 8);
616 memcpy(targetar, target, len);
617 strcpy(targetar + len, "-ar");
618 if (test_ar(logdepth, targetar)) {
619 free(targetar);
620 return 0;
621 }
622 free(targetar);
623 }
624 if (test_ar(logdepth, "ar")) return 0;
625 if (test_ar(logdepth, "/usr/bin/ar")) return 0;
626 }
627 else {
628 report(" user provided (%s)...", ar);
629 if (test_ar(logdepth, ar)) return 0;
630 }
631 return 1;
632 }
633
634 int find_fstools_ranlib(const char *name, int logdepth, int fatal)
635 {
636 const char *ranlib, *target;
637 char *targetranlib;
638 int len;
639 char *test_code = NL "int zero() { return 0; }" NL;
640 char *obj = ".o";
641
642 (void) fatal; /* to suppress compiler warnings about not using fatal */
643
644 require("fstools/ar", logdepth, fatal);
645 require("cc/cc", logdepth, fatal);
646
647 report("Checking for ranlib... ");
648 logprintf(logdepth, "find_fstools_ranlib: trying to find ranlib...\n");
649 logdepth++;
650
651 logprintf(logdepth, "compiling test object...\n");
652 if (compile_code(logdepth+1, test_code, &obj, NULL, "-c", NULL) != 0) {
653 logprintf(logdepth, "ERROR: Can't compile test object\n");
654 report("ERROR: Can't compile test object\n");
655 abort();
656 }
657
658 ranlib = get("/arg/fstools/ranlib");
659 if (ranlib == NULL) {
660 target = get("/arg/sys/target");
661 if (target != NULL) {
662 logprintf(logdepth+1, "find_ranlib: crosscompiling for '%s', looking for target ranlib\n", target);
663 len = strlen(target);
664 targetranlib = malloc(len + 16);
665 memcpy(targetranlib, target, len);
666 strcpy(targetranlib + len, "-ranlib");
667 if (test_ranlib(logdepth, targetranlib, obj)) {
668 free(targetranlib);
669 return 0;
670 }
671 free(targetranlib);
672 }
673 if (test_ranlib(logdepth, "ranlib", obj)) goto found;
674 if (test_ranlib(logdepth, "/usr/bin/ranlib", obj)) goto found;
675 if (test_ranlib(logdepth, "ar -s", obj)) goto found;
676 if (test_ranlib(logdepth, "/usr/bin/ar -s", obj)) goto found;
677
678 /* some systems (for example IRIX) can't run s without doing
679 something else; t is harmless */
680 if (test_ranlib(logdepth, "ar ts", obj)) goto found;
681 if (test_ranlib(logdepth, "/usr/bin/ar ts", obj)) goto found;
682
683 /* final fallback: some systems (for example minix3) simply
684 do not have ranlib or ar equivalent; it's easier to detect
685 a dummy command than to force conditions into Makefiles */
686 if (test_ranlib(logdepth, "true", obj)) goto found;
687 }
688 else {
689 report(" user provided (%s)...", ranlib);
690 if (test_ranlib(logdepth, ranlib, obj)) goto found;
691 }
692 unlink(obj);
693 free(obj);
694 return 1;
695 found:;
696 unlink(obj);
697 free(obj);
698 return 0;
699 }
700
701 int find_fstools_awk(const char *name, int logdepth, int fatal)
702 {
703 const char *awk;
704
705 (void) fatal; /* to suppress compiler warnings about not using fatal */
706
707 report("Checking for awk... ");
708 logprintf(logdepth, "find_fstools_awk: trying to find awk...\n");
709 logdepth++;
710
711 awk = get("/arg/fstools/awk");
712 if (awk == NULL) {
713 if (test_awk(logdepth, "awk")) return 0;
714 if (test_awk(logdepth, "gawk")) return 0;
715 if (test_awk(logdepth, "mawk")) return 0;
716 if (test_awk(logdepth, "nawk")) return 0;
717 }
718 else {
719 report(" user provided (%s)...", awk);
720 if (test_awk(logdepth, awk)) return 0;
721 }
722 return 1;
723 }
724
725 int find_fstools_chmodx(const char *name, int logdepth, int fatal)
726 {
727 const char *chmod;
728
729 (void) fatal; /* to suppress compiler warnings about not using fatal */
730
731 report("Checking for chmod to executable... ");
732 logprintf(logdepth, "find_fstools_awk: trying to find chmod to executable...\n");
733 logdepth++;
734
735 chmod = get("/arg/fstools/chmodx");
736 if (chmod == NULL) {
737 if (test_chmodx(logdepth, "chmod +x")) return 0;
738 if (test_chmodx(logdepth, "chmod 755")) return 0;
739 if (test_chmodx(logdepth, "")) return 0; /* on some systems we don't need to do anything */
740 }
741 else {
742 report(" user provided (%s)...", chmod);
743 if (test_chmodx(logdepth, chmod)) return 0;
744 }
745 return 1;
746 }
747
748 int find_fstools_cat(const char *name, int logdepth, int fatal)
749 {
750 const char *cat;
751
752 (void) fatal; /* to suppress compiler warnings about not using fatal */
753
754 report("Checking for cat... ");
755 logprintf(logdepth, "find_fstools_cat: trying to find cat...\n");
756 logdepth++;
757
758 cat = get("/arg/fstools/cat");
759 if (cat == NULL) {
760 if (test_cat(logdepth, "cat")) return 0;
761 if (test_cat(logdepth, "type")) return 0;
762 }
763 else {
764 report(" user provided (%s)...", cat);
765 if (test_cat(logdepth, cat)) return 0;
766 }
767 return 1;
768 }
769
770 int find_fstools_sed(const char *name, int logdepth, int fatal)
771 {
772 const char *sed;
773
774 (void) fatal; /* to suppress compiler warnings about not using fatal */
775
776 report("Checking for sed... ");
777 logprintf(logdepth, "find_fstools_sed: trying to find sed...\n");
778 logdepth++;
779
780 sed = get("/arg/fstools/sed");
781 if (sed == NULL) {
782 if (test_sed(logdepth, "sed")) return 0;
783 }
784 else {
785 report(" user provided (%s)...", sed);
786 if (test_sed(logdepth, sed)) return 0;
787 }
788 return 1;
789 }
790
791 int find_fstools_file_l(const char *name, int logdepth, int fatal)
792 {
793 const char *file;
794
795 (void) fatal; /* to suppress compiler warnings about not using fatal */
796
797 report("Checking for file... ");
798 logprintf(logdepth, "find_fstools_file_l: trying to find file -L...\n");
799 logdepth++;
800
801 file = get("/arg/fstools/file_l");
802 if (file == NULL) {
803 if (test_file(logdepth, "fstools/file_l", "file -L")) return 0;
804 if (test_file(logdepth, "fstools/file_l", "file")) return 0;
805 }
806 else {
807 report(" user provided (%s)...", file);
808 if (test_file(logdepth, "fstools/file_l", file)) return 0;
809 }
810 return 1;
811 }
812
813 int find_fstools_file(const char *name, int logdepth, int fatal)
814 {
815 const char *file;
816
817 (void) fatal; /* to suppress compiler warnings about not using fatal */
818
819 report("Checking for file... ");
820 logprintf(logdepth, "find_fstools_file: trying to find file...\n");
821 logdepth++;
822
823 file = get("/arg/fstools/file");
824 if (file == NULL) {
825 if (test_file(logdepth, "fstools/file", "file")) return 0;
826 }
827 else {
828 report(" user provided (%s)...", file);
829 if (test_file(logdepth, "fstools/file", file)) return 0;
830 }
831 return 1;
832 }
0 /*
1 scconfig - detect I/O features of the system
2 Copyright (C) 2010 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include "libs.h"
27 #include "log.h"
28 #include "db.h"
29 #include "dep.h"
30
31 int find_io_pipe(const char *name, int logdepth, int fatal)
32 {
33 char *test_c =
34 NL "#include <unistd.h>"
35 NL "int main() {"
36 NL " int fd[2];"
37 NL " if (pipe(fd) == 0)"
38 NL " puts(\"OK\");"
39 NL " return 0;"
40 NL "}"
41 NL;
42
43 require("cc/cc", logdepth, fatal);
44
45 report("Checking for pipe(2)... ");
46 logprintf(logdepth, "find_io_pipe: trying to find pipe(2)...\n");
47 logdepth++;
48
49
50 if (try_icl(logdepth, "libs/io/pipe", test_c, NULL, NULL, NULL)) return 0;
51 return try_fail(logdepth, "libs/io/pipe");
52 }
53
54 int find_io_dup2(const char *name, int logdepth, int fatal)
55 {
56 char *test_c =
57 NL "#include <unistd.h>"
58 NL "int main() {"
59 NL " int fd;"
60 NL " if (dup2(1, 4) == 4)"
61 NL " write(4, \"OK\\n\", 3); "
62 NL " return 0;"
63 NL "}"
64 NL;
65
66 require("cc/cc", logdepth, fatal);
67
68 report("Checking for dup2(2)... ");
69 logprintf(logdepth, "find_io_dup2: trying to find dup2(2)...\n");
70 logdepth++;
71
72 if (try_icl(logdepth, "libs/io/dup2", test_c, NULL, NULL, NULL)) return 0;
73 return try_fail(logdepth, "libs/io/dup2");
74 }
75
76
77 int find_io_fileno(const char *name, int logdepth, int fatal)
78 {
79 char test_c[256];
80 char *test_c_ =
81 NL "#include <stdio.h>"
82 NL "int main() {"
83 NL no_implicit(int, "%s", "%s")
84 NL " if (%s(stdout) >= 0)"
85 NL " puts(\"OK\"); "
86 NL " return 0;"
87 NL "}"
88 NL;
89
90 require("cc/cc", logdepth, fatal);
91
92 report("Checking for fileno(3)... ");
93 logprintf(logdepth, "find_io_fileno: trying to find fileno(3)...\n");
94 logdepth++;
95
96 /* UNIX */
97 sprintf(test_c, test_c_, "fileno", "fileno", "fileno");
98 if (try_icl(logdepth, "libs/io/fileno", test_c, "#include <unistd.h>\n", NULL, NULL)) {
99 put("libs/io/fileno/call", "fileno");
100 return 0;
101 }
102
103 sprintf(test_c, test_c_, "fileno", "fileno", "fileno");
104 if (try_icl(logdepth, "libs/io/fileno", test_c, "#define _XOPEN_SOURCE\n#include <unistd.h>\n", NULL, NULL)) {
105 put("libs/io/fileno/call", "fileno");
106 return 0;
107 }
108
109 /* windows */
110 sprintf(test_c, test_c_, "_fileno", "_fileno", "_fileno");
111 if (try_icl(logdepth, "libs/io/fileno", test_c, "#include <stdio.h>\n", NULL, NULL)) {
112 put("libs/io/fileno/call", "_fileno");
113 return 0;
114 }
115
116 return try_fail(logdepth, "libs/io/fileno");
117 }
118
119 int find_io_lseek(const char *name, int logdepth, int fatal)
120 {
121 #define NODE "libs/io/lseek"
122
123 char test_c[3256];
124 const char *test_c_template =
125 NL "#include <stdio.h>"
126 NL "#include <fcntl.h>"
127 NL "int main() {"
128 NL " const char *filename = \"%s\";"
129 NL no_implicit(int, "%s", "%s")
130 NL " int fd = open(filename, O_WRONLY);"
131 NL " if (write(fd, \"abc\", 3) == 3 && %s(fd, 1, SEEK_SET) == 1)"
132 NL " puts(\"OK\"); "
133 NL " return 0;"
134 NL "}"
135 NL;
136 char *tmpf;
137 const char *incs[] = {"#include <unistd.h>","#include <io.h>",NULL};
138 const char *fns[] = {"lseek", "_lseek", NULL};
139 const char **inc;
140 const char **fn;
141
142 require("cc/cc", logdepth, fatal);
143
144 report("Checking for lseek(2)... ");
145 logprintf(logdepth, "find_io_lseek: trying to find lseek(2)...\n");
146 logdepth++;
147
148 tmpf = tempfile_new(".psx");
149
150 for (inc = incs, fn = fns; *fn; ++inc, ++fn) {
151 sprintf(test_c, test_c_template, tmpf, *fn, *fn, *fn);
152 if (try_icl(logdepth, NODE, test_c, *inc, NULL, NULL)) {
153 put(NODE "/call", *fn);
154 return 0;
155 }
156 }
157
158 return try_fail(logdepth, NODE);
159 #undef NODE
160 }
161
162 int find_io_popen(const char *name, int logdepth, int fatal)
163 {
164 const char **i, *incs[] = {"#define _XOPEN_SOURCE", "#define _BSD_SOURCE", "#define _POSIX_C_SOURCE 2", NULL};
165 char *test_c =
166 NL "#include <stdlib.h>"
167 NL "#include <stdio.h>"
168 NL "int main() {"
169 NL " FILE *f = popen(\"echo OK\", \"r\");"
170 NL " char line[16];"
171 NL " if (f == NULL) return 0;"
172 NL " if (fgets(line, sizeof(line)-1, f) == NULL) return 0;"
173 NL " puts(line);"
174 NL " return 0;"
175 NL "}"
176 NL;
177
178 require("cc/cc", logdepth, fatal);
179
180 report("Checking for popen(3)... ");
181 logprintf(logdepth, "find_io_popen: trying to find popen(3)...\n");
182 logdepth++;
183
184 for(i = incs; *i != NULL; i++)
185 if (try_icl(logdepth, "libs/io/popen", test_c, *i, NULL, NULL)) return 0;
186 return try_fail(logdepth, "libs/io/popen");
187 }
188
0 /*
1 scconfig - detection of standard library features
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "db.h"
28 #include "dep.h"
29
30 static int trydlc(int logdepth, const char *test_c_dlc, const char *cflagsf, const char *ldflagsf, const char *dlc)
31 {
32 char *cflags, *ldflags;
33
34 cflags = malloc(strlen(dlc) + 64);
35 ldflags = malloc(strlen(dlc)*2 + 256);
36 sprintf(cflags, cflagsf, dlc);
37 sprintf(ldflags, ldflagsf, dlc, dlc);
38 if (try_icl(logdepth, NULL, test_c_dlc, NULL, cflags, ldflags)) {
39 *cflags = ' ';
40 append("cc/cflags", cflags);
41 put("libs/ldl", ldflags);
42 put("libs/dl-compat", strue);
43 report("OK (%s and %s)\n", cflags, ldflags);
44 free(cflags);
45 free(ldflags);
46 return 1;
47 }
48 free(cflags);
49 free(ldflags);
50 return 0;
51 }
52
53 int find_lib_ldl(const char *name, int logdepth, int fatal)
54 {
55 const char *ldl, *dlc;
56 char *s;
57
58 char *test_c =
59 NL "#include <stdio.h>"
60 NL "#include <dlfcn.h>"
61 NL "int main() {"
62 NL " void *handle;"
63 NL " handle = dlopen(\"/this file does not exist.\", RTLD_NOW);"
64 NL " if (handle == NULL) printf(\"OK\\n\");"
65 NL " return 0;"
66 NL "}"
67 NL;
68
69 char *test_c_dlc =
70 NL "#include <stdio.h>"
71 NL "#include <dl-compat.h>"
72 NL "int main() {"
73 NL " void *handle;"
74 NL " handle = dlopen(\"/this file does not exist.\", RTLD_NOW);"
75 NL " if (handle == NULL) printf(\"OK\\n\");"
76 NL " return 0;"
77 NL "}"
78 NL;
79
80 require("cc/cc", logdepth, fatal);
81
82 report("Checking for -ldl... ");
83 logprintf(logdepth, "find_lib_ldl: trying to find ldl...\n");
84 logdepth++;
85
86 ldl = get("/arg/libs/ldl");
87 if (ldl == NULL) {
88 dlc = get("/arg/libs/dl-compat");
89
90 if (dlc == NULL) {
91 /* If dlc is not explicitly requested by the user, try standard
92 dl (see whether we need -ldl for dlopen()) */
93 if (try_icl(logdepth, NULL, test_c, NULL, NULL, NULL)) {
94 put("libs/ldl", "");
95 put("libs/ldl/includes", "#include <dlfcn.h>\\n");
96 report("OK ()\n");
97 return 0;
98 }
99 if (try_icl(logdepth, NULL, test_c, NULL, NULL, "-ldl")) {
100 put("libs/ldl", "-ldl");
101 put("libs/ldl/includes", "#include <dlfcn.h>\\n");
102 report("OK (-ldl)\n");
103 return 0;
104 }
105 }
106 /* try dl-compat (dl compatibility lib) */
107 if (dlc != NULL) {
108 /* test at user supplied dlc prefix:
109 - first assume the linker will find it
110 - next assume gcc and pass rpath to the linker
111 - finally try static linking */
112 if (trydlc(logdepth, test_c_dlc, "-I%s/include", "-L%s/lib -ldl-compat\000%s", dlc)) {
113 put("libs/ldl/includes", "#include <dl-compat.h>\\n");
114 return 0;
115 }
116 if (trydlc(logdepth, test_c_dlc, "-I%s/include", "-L%s/lib -Wl,-rpath=%s/lib -ldl-compat", dlc)) {
117 put("libs/ldl/includes", "#include <dl-compat.h>\\n");
118 return 0;
119 }
120 if (trydlc(logdepth, test_c_dlc, "-I%s/include", "%s/lib/libdl-compat.a\000%s", dlc)) {
121 put("libs/ldl/includes", "#include <dl-compat.h>\\n");
122 return 0;
123 }
124 }
125 else if (try_icl(logdepth, NULL, test_c_dlc, NULL, NULL, "-ldl-compat")) {
126 /* check at normal system installation */
127 put("libs/ldl", "-ldl-compat");
128 put("libs/ldl/includes", "#include <dl-compat.h>\\n");
129 report("OK (-ldl-compat)\n");
130 return 0;
131 }
132 }
133 else {
134 report("User provided... ");
135 s = strclone(ldl);
136 if (try_icl(logdepth, NULL, test_c, NULL, NULL, s)) {
137 put("libs/ldl", ldl);
138 put("libs/ldl/includes", "#include <dlfcn.h>\\n");
139 report("OK (%s)\n", ldl);
140 free(s);
141 return 0;
142 }
143 free(s);
144 }
145 report("Not found\n");
146 return 1;
147 }
148
149 int find_lib_LoadLibrary(const char *name, int logdepth, int fatal)
150 {
151 /*char *s;*/
152
153 char *test_c =
154 NL "#include <stdio.h>"
155 NL "int main() {"
156 NL " void *handle;"
157 NL " handle = LoadLibrary(\"/this file does not exist.\");"
158 NL " if (handle == NULL) printf(\"OK\\n\");"
159 NL " return 0;"
160 NL "}"
161 NL;
162
163 require("cc/cc", logdepth, fatal);
164
165 report("Checking for LoadLibrary... ");
166 logprintf(logdepth, "find_lib_LoadLibrary: trying to find LoadLibrary...\n");
167 logdepth++;
168
169 if (try_icl(logdepth, "libs/LoadLibrary", test_c, "#include <windows.h>", NULL, NULL))
170 return 0;
171 return try_fail(logdepth, "libs/LoadLibrary");
172 }
173
174 int find_lib_errno(const char *name, int logdepth, int fatal)
175 {
176 char *test_c =
177 NL "#include <errno.h>"
178 NL "int main() {"
179 NL " errno = 0;"
180 NL " puts(\"OK\");"
181 NL " return 0;"
182 NL "}"
183 NL ;
184
185 require("cc/cc", logdepth, fatal);
186
187 report("Checking for errno.h... ");
188 logprintf(logdepth, "find_lib_errno: trying to find errno...\n");
189 logdepth++;
190
191 if (try_icl(logdepth, "libs/errno", test_c, NULL, NULL, NULL)) return 0;
192 return try_fail(logdepth, "libs/errno");
193 }
0 /*
1 scconfig - detection of printf-related features
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "db.h"
28 #include "dep.h"
29
30 static int tryx(int logdepth, const char *test_c, const char *trying, const char *expected)
31 {
32 char *out = NULL;
33 char buff[512];
34
35 logprintf(logdepth, "trying '%s'\n", trying);
36 sprintf(buff, test_c, trying, trying);
37 if (compile_run(logdepth+1, buff, NULL, NULL, NULL, &out) == 0) {
38 if (strncmp(out, expected, strlen(expected)) == 0) {
39 free(out);
40 return 1;
41 }
42 free(out);
43 }
44 return 0;
45 }
46
47 static int tryc(int logdepth, const char *test_c, const char *trying)
48 {
49 char *out = NULL;
50 char buff[512];
51 char *spc, *end;
52
53 logprintf(logdepth, "trying '%s'\n", trying);
54 sprintf(buff, test_c, trying);
55 if (compile_run(logdepth+1, buff, NULL, NULL, NULL, &out) == 0) {
56 spc = str_chr(out, ' ');
57 if (spc == NULL)
58 return 0;
59 *spc = '\0';
60 spc++;
61 end = str_chr(spc, ' ');
62 if (end == NULL)
63 return 0;
64 *end = '\0';
65 if (strcmp(out, spc) == 0) {
66 free(out);
67 put("libs/printf_ptrcast", trying);
68 report("OK (%s)\n", trying);
69 return 1;
70 }
71 free(out);
72 }
73 return 0;
74 }
75
76 int find_printf_x(const char *name, int logdepth, int fatal)
77 {
78 const char *pfx;
79 char *test_c =
80 NL "#include <stdlib.h>"
81 NL "#include <stdio.h>"
82 NL "int main() {"
83 NL " printf(\"'%s%%x'/'%s%%x'\\n\", (size_t)0x1234, NULL);"
84 NL " return 0;"
85 NL "}"
86 NL;
87 char *expected = "'0x1234'/'0x0'";
88
89 require("cc/cc", logdepth, fatal);
90
91 report("Checking for printf %%x prefix... ");
92 logprintf(logdepth, "find_printf_x: trying to find printf %%x prefix...\n");
93 logdepth++;
94
95 pfx = get("/arg/libs/printf_x");
96 if (pfx == NULL) {
97
98 if (tryx(logdepth, test_c, "", expected)) {
99 put("libs/printf_x", "");
100 report("OK ()\n");
101 return 0;
102 }
103 if (tryx(logdepth, test_c, "0x", expected)) {
104 put("libs/printf_x", "0x");
105 report("OK (0x)\n");
106 return 0;
107 }
108 }
109 else {
110 report("User provided... ");
111 if (tryx(logdepth, test_c, pfx, expected)) {
112 put("libs/printf_x", pfx);
113 report("OK (%s)\n", pfx);
114 return 0;
115 }
116 }
117 return 1;
118 }
119
120 int find_printf_ptrcast(const char *name, int logdepth, int fatal)
121 {
122 const char *cast;
123 char *test_c =
124 NL "#include <stdlib.h>"
125 NL "#include <stdio.h>"
126 NL "int main() {"
127 NL " printf(\"%%d %%d \\n\", sizeof(void *), sizeof(%s));"
128 NL " return 0;"
129 NL "}"
130 NL;
131
132 require("cc/cc", logdepth, fatal);
133
134 report("Checking for printf %%x pointer cast... ");
135 logprintf(logdepth, "find_printf_ptrcast: trying to find printf %%x pointer cast...\n");
136 logdepth++;
137
138 cast = get("/arg/libs/printf_ptrcast");
139 if (cast == NULL) {
140 if (tryc(logdepth, test_c, "unsigned int")) return 0;
141 if (tryc(logdepth, test_c, "unsigned long")) return 0;
142 if (tryc(logdepth, test_c, "unsigned long long")) return 0;
143 }
144 else {
145 report("User provided... ");
146 if (tryc(logdepth, test_c, cast)) return 0;
147 }
148 return 1;
149 }
150
151 int find_snprintf(const char *name, int logdepth, int fatal)
152 {
153 char *out;
154 char *test_c =
155 NL "#include <stdlib.h>"
156 NL "#include <stdio.h>"
157 NL "int main() {"
158 NL " char buff[9];"
159 NL " char *s = buff+2;"
160 NL
161 NL " /* build a fence */"
162 NL " buff[0] = 0;"
163 NL " buff[1] = 65;"
164 NL " buff[7] = 66;"
165 NL " buff[8] = 0;"
166 NL
167 NL " snprintf(s, 4, \"%d\", 123456);"
168 NL " if ((buff[0] == 0) && (buff[1] == 65) && (buff[7] == 65) && (buff[8] == 0))"
169 NL " printf(\"%s\\n\", s);"
170 NL " return 0;"
171 NL "}"
172 NL;
173
174 require("cc/cc", logdepth, fatal);
175
176 report("Checking for snprintf... ");
177 logprintf(logdepth, "find_snprintf_works: trying to find snprintf...\n");
178 logdepth++;
179 logprintf(logdepth, "trying snprintf...\n");
180
181 if (compile_run(logdepth+1, test_c, NULL, NULL, NULL, &out) == 0) {
182 if (cross_blind) {
183 put("libs/snprintf", strue);
184 report("OK (can't check if safe)\n");
185 free(out);
186 return 0;
187 }
188 if (strcmp(out, "123")) {
189 put("libs/snprintf", strue);
190 put("libs/snprintf_safe", strue);
191 report("OK (safe)\n");
192 free(out);
193 return 0;
194 }
195 if (strcmp(out, "1234")) {
196 put("libs/snprintf", strue);
197 put("libs/snprintf_safe", sfalse);
198 report("OK (UNSAFE)\n");
199 free(out);
200 return 0;
201 }
202 free(out);
203 report("not found (broken output).\n");
204 }
205 else {
206 report("not found (no output).\n");
207 }
208 put("libs/snprintf", sfalse);
209 return 1;
210 }
211
212 int find_dprintf(const char *name, int logdepth, int fatal)
213 {
214 char *out;
215 char *test_c =
216 NL "#include <stdlib.h>"
217 NL "#include <stdio.h>"
218 NL "int main() {"
219 NL " dprintf(1, \"OK\\n\");"
220 NL " return 0;"
221 NL "}"
222 NL;
223
224 require("cc/cc", logdepth, fatal);
225
226 report("Checking for dprintf... ");
227 logprintf(logdepth, "find_dprintf: trying to find dprintf...\n");
228 logdepth++;
229 logprintf(logdepth, "trying dprintf...\n");
230
231 if ((compile_run(logdepth+1, test_c, NULL, NULL, NULL, &out) == 0) && (strcmp(out, "OK"))) {
232 put("libs/dprintf", strue);
233 report("found\n");
234 free(out);
235 return 0;
236 }
237 put("libs/dprintf", sfalse);
238 report("not found\n");
239 return 1;
240 }
241
242 int find_vdprintf(const char *name, int logdepth, int fatal)
243 {
244 char *out;
245 char *test_c =
246 NL "#include <stdlib.h>"
247 NL "#include <stdio.h>"
248 NL "#include <stdarg.h>"
249 NL "void local_dprintf(int fd, const char *fmt, ...)"
250 NL "{"
251 NL " va_list ap;"
252 NL " va_start(ap, fmt);"
253 NL " vdprintf(fd, fmt, ap);"
254 NL "}"
255 NL "int main() {"
256 NL " local_dprintf(1, \"OK\\n\");"
257 NL " return 0;"
258 NL "}"
259 NL;
260
261 require("cc/cc", logdepth, fatal);
262
263 report("Checking for vdprintf... ");
264 logprintf(logdepth, "find_vdprintf: trying to find vdprintf...\n");
265 logdepth++;
266 logprintf(logdepth, "trying vdprintf...\n");
267
268 if ((compile_run(logdepth+1, test_c, NULL, NULL, NULL, &out) == 0) && (strcmp(out, "OK"))) {
269 put("libs/vdprintf", strue);
270 report("found\n");
271 free(out);
272 return 0;
273 }
274 put("libs/vdprintf", sfalse);
275 report("not found\n");
276 return 1;
277 }
278
279 int find_vsnprintf(const char *name, int logdepth, int fatal)
280 {
281 char *out;
282 char *test_c =
283 NL "#include <stdlib.h>"
284 NL "#include <stdio.h>"
285 NL "#include <stdarg.h>"
286 NL "void local_vsnprintf(char *s, int len, const char *fmt, ...)"
287 NL "{"
288 NL " va_list ap;"
289 NL " va_start(ap, fmt);"
290 NL " vsnprintf(s, len, fmt, ap);"
291 NL "}"
292 NL "int main() {"
293 NL " char s[16];"
294 NL " *s = '\\0';"
295 NL " local_vsnprintf(s, 14, \"OK\\n\");"
296 NL " printf(\"%s\", s);"
297 NL " return 0;"
298 NL "}"
299 NL;
300
301 require("cc/cc", logdepth, fatal);
302
303 report("Checking for vsnprintf... ");
304 logprintf(logdepth, "find_vsnprintf: trying to find vsnprintf...\n");
305 logdepth++;
306 logprintf(logdepth, "trying vsnprintf...\n");
307
308 if ((compile_run(logdepth+1, test_c, NULL, NULL, NULL, &out) == 0) && (strcmp(out, "OK"))) {
309 put("libs/vsnprintf", strue);
310 report("found\n");
311 free(out);
312 return 0;
313 }
314 put("libs/vsnprintf", sfalse);
315 report("not found\n");
316 return 1;
317 }
0 /*
1 scconfig - detection of standard library features (processes)
2 Copyright (C) 2016 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "db.h"
28 #include "dep.h"
29
30 int find_proc__spawnvp(const char *name, int logdepth, int fatal)
31 {
32 char *test_c =
33 NL "#include <stdlib.h>"
34 NL "int main() {"
35 NL " const char *a[3] = {\"/c\", \"echo OK\", NULL};"
36 NL " _spawnvp(_P_WAIT, \"cmd\", a);"
37 NL " return 0;"
38 NL "}"
39 NL ;
40
41 require("cc/cc", logdepth, fatal);
42
43 report("Checking for _spawnvp... ");
44 logprintf(logdepth, "find_proc__spawnvp: trying to find _spawnvp...\n");
45 logdepth++;
46
47 if (try_icl(logdepth, "libs/proc/_spawnvp", test_c, "#include <process.h>", NULL, NULL)) return 0;
48
49 return try_fail(logdepth, "libs/proc/_spawnvp");
50 }
51
52
53
54 int find_proc_fork(const char *name, int logdepth, int fatal)
55 {
56 char *test_c =
57 NL "#include <stdlib.h>"
58 NL "#include <stdio.h>"
59 NL "int main() {"
60 NL " if (fork() == 0) { return 0; }"
61 NL " puts(\"OK\");"
62 NL " return 0;"
63 NL "}"
64 NL ;
65
66 /* NOTE: can't print OK from the child process because of a possible race
67 with the parent immediately exiting without wait(). */
68
69 require("cc/cc", logdepth, fatal);
70
71 report("Checking for fork... ");
72 logprintf(logdepth, "find_proc_fork: trying to find fork...\n");
73 logdepth++;
74
75 if (try_icl(logdepth, "libs/proc/fork", test_c, "#include <unistd.h>", NULL, NULL)) return 0;
76
77 return try_fail(logdepth, "libs/proc/fork");
78 }
79
80
81 int find_proc_wait(const char *name, int logdepth, int fatal)
82 {
83 char *inc;
84 const char *inc1;
85 char test_c[1024];
86 char *test_c_in =
87 NL "%s\n"
88 NL "#include <stdlib.h>"
89 NL "#include <stdio.h>"
90 NL "int main() {"
91 NL " int st = 0;"
92 NL " if (fork() == 0) {"
93 NL " printf(\"O\");"
94 NL " return 42;"
95 NL " }"
96 NL " wait(&st);"
97 NL " if (WIFEXITED(st) && (WEXITSTATUS(st) == 42))"
98 NL " printf(\"K\");"
99 NL " else"
100 NL " printf(\"%%d\", st);"
101 NL " printf(\"\\n\");"
102 NL " return 0;"
103 NL "}"
104 NL ;
105
106 require("cc/cc", logdepth, fatal);
107 if (require("libs/proc/fork", logdepth, fatal))
108 return try_fail(logdepth, "libs/proc/wait");
109
110 report("Checking for wait... ");
111 logprintf(logdepth, "find_proc_wait: trying to find wait...\n");
112 logdepth++;
113
114 inc1 = get("libs/proc/fork/includes");
115 if (inc1 != NULL) {
116 char *i, *o;
117 inc = strclone(inc1);
118 for(i = o = inc; *i != '\0'; i++,o++) {
119 if ((i[0] == '\\') && (i[1] == 'n')) {
120 *o = '\n';
121 i++;
122 }
123 else
124 *o = *i;
125 }
126 *o = '\0';
127 sprintf(test_c, test_c_in, inc);
128 free(inc);
129 }
130 else
131 sprintf(test_c, test_c_in, "");
132
133 if (try_icl(logdepth, "libs/proc/wait", test_c, "#include <sys/types.h>\n#include <sys/wait.h>", NULL, NULL)) return 0;
134
135 return try_fail(logdepth, "libs/proc/wait");
136 }
0 /*
1 scconfig - detection of standard library features
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "db.h"
28 #include "dep.h"
29
30 static int try_bad(int logdepth, const char *test_c, char *cflags, char *ldflags)
31 {
32 char *out = NULL;
33
34 logprintf(logdepth, "trying signal (neg) with ldflags '%s'\n", ldflags == NULL ? get("cc/ldflags") : ldflags);
35 if (compile_run(logdepth+1, test_c, NULL, cflags, ldflags, &out) == 0) {
36 if (target_emu_fail(out) || (strncmp(out, "BAD", 3) == 0)) {
37 free(out);
38 return 0;
39 }
40 free(out);
41 }
42 return 1;
43 }
44
45
46 int find_signal_raise(const char *name, int logdepth, int fatal)
47 {
48 char *test_c =
49 NL "#include <stdio.h>"
50 NL "#include <signal.h>"
51 NL "int main(int argc, char *argv[]) {"
52 NL " printf(\"OK\\n\");"
53 NL " if (argc == 16)"
54 NL " raise(1);"
55 NL " return 0;"
56 NL "}"
57 NL;
58
59 require("cc/cc", logdepth, fatal);
60
61 report("Checking for raise()... ");
62 logprintf(logdepth, "find_signal_raise: trying to find raise()...\n");
63 logdepth++;
64
65 if (try_icl(logdepth, "signal/raise", test_c, NULL, NULL, NULL))
66 return 0;
67 return try_fail(logdepth, "signal/raise");
68 }
69
70
71 int find_signal_names(const char *rname, int logdepth, int fatal)
72 {
73 char *test_c_exists =
74 NL "#include <stdio.h>"
75 NL "#include <signal.h>"
76 NL "int main(int argc, char *argv[]) {"
77 NL " printf(\"OK\\n\");"
78 NL " if (argc == 16)"
79 NL " raise(%s);"
80 NL " return 0;"
81 NL "}"
82 NL;
83 char *test_c_terms =
84 NL "#include <stdio.h>"
85 NL "#include <signal.h>"
86 NL "int main() {"
87 NL " raise(%s);"
88 NL " printf(\"BAD\\n\");"
89 NL " return 0;"
90 NL "}"
91 NL;
92 char test_c[256];
93 const char *names[] = {"SIGINT", "SIGABRT", "SIGKILL", "SIGTERM", "SIGQUIT", "SIGHUP", "SIGFPE", "SIGSEGV", "SIGPIPE", NULL};
94 const char **name;
95 char path[256], *pathend;
96 const char *prefix = "signal/names/";
97
98 require("cc/cc", logdepth, fatal);
99 require("signal/raise/*", logdepth, fatal);
100
101 strcpy(path, prefix);
102 pathend = path + strlen(prefix);
103
104 for(name = names; *name != NULL; name++) {
105 /* check whether it exists */
106 report("Checking whether %s exists... ", *name);
107 logprintf(logdepth, "find_signal_names: checking whether %s exists\n", *name);
108 logdepth++;
109 sprintf(test_c, test_c_exists, *name);
110 strcpy(pathend, *name);
111 if (!try_icl(logdepth, path, test_c, NULL, NULL, NULL)) {
112 logdepth--;
113 continue;
114 }
115
116 /* check whether it exists */
117 logdepth--;
118 report("Checking whether %s terminates... ", *name);
119 logprintf(logdepth, "find_signal_names: checking whether %s terminates\n", *name);
120 logdepth++;
121
122 sprintf(test_c, test_c_terms, *name);
123 sprintf(pathend, "%s/terminates", *name);
124 if (try_bad(logdepth, test_c, NULL, "")) {
125 put(path, strue);
126 report("terminates\n");
127 }
128 else {
129 report("does not terminate\n");
130 put(path, sfalse);
131 }
132 logdepth--;
133 }
134
135 /* to avoid redetection */
136 put("signal/names/presents", strue);
137
138 return 0;
139 }
140
0 /*
1 scconfig - detection of standard library features: strings
2 Copyright (C) 2017 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include "libs.h"
27 #include "log.h"
28 #include "db.h"
29 #include "dep.h"
30
31 int find_strcasecmp(const char *name, int logdepth, int fatal)
32 {
33 char *test_c =
34 NL "#include <string.h>"
35 NL "#include <stdio.h>"
36 NL "int main() {"
37 NL " if ((strcasecmp(\"foo\", \"FoO\") == 0) && (strcasecmp(\"foo\", \"bar\") != 0))"
38 NL " puts(\"OK\");"
39 NL " return 0;"
40 NL "}"
41 NL;
42
43 require("cc/cc", logdepth, fatal);
44
45 report("Checking for strcasecmp()... ");
46 logprintf(logdepth, "find_fs_strcasecmp: trying to find strcasecmp...\n");
47 logdepth++;
48
49 if (try_icl(logdepth, "str/strcasecmp", test_c, NULL, NULL, NULL)) return 0;
50 return try_fail(logdepth, "str/strcasecmp");
51 }
52
53
54 int find_strncasecmp(const char *name, int logdepth, int fatal)
55 {
56 char *test_c =
57 NL "#include <string.h>"
58 NL "#include <stdio.h>"
59 NL "int main() {"
60 NL " if ((strncasecmp(\"foo1\", \"FoO2\", 3) == 0) && (strncasecmp(\"foo1\", \"bar2\", 3) != 0))"
61 NL " puts(\"OK\");"
62 NL " return 0;"
63 NL "}"
64 NL;
65
66 require("cc/cc", logdepth, fatal);
67
68 report("Checking for strncasecmp()... ");
69 logprintf(logdepth, "find_fs_strncasecmp: trying to find strncasecmp...\n");
70 logdepth++;
71
72 if (try_icl(logdepth, "str/strncasecmp", test_c, NULL, NULL, NULL)) return 0;
73 return try_fail(logdepth, "str/strncasecmp");
74 }
75
0 /*
1 scconfig - detect features of the system or the host/target computer
2 Copyright (C) 2009..2012 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <unistd.h>
27 #include "libs.h"
28 #include "log.h"
29 #include "db.h"
30 #include "dep.h"
31
32 int find_sys_ptrwidth(const char *name, int logdepth, int fatal)
33 {
34 char *end, W[32];
35 char *out = NULL;
36 int w;
37
38 char *test_c =
39 NL "#include <stdio.h>"
40 NL "int main() {"
41 NL " void *ptr;"
42 NL " printf(\"%d\\n\", sizeof(ptr));"
43 NL " return 0;"
44 NL "}"
45 NL;
46
47 require("cc/cc", logdepth, fatal);
48
49 report("Checking for pointer width... ");
50 logprintf(logdepth, "find_sys_ptrwidth: trying to find pointer width...\n");
51 logdepth++;
52
53 if (compile_run(logdepth, test_c, NULL, NULL, NULL, &out) == 0) {
54 w = strtol(out, &end, 10);
55 if ((*end != '\0') && (*end != '\n') && (*end != '\r')) {
56 report("FAILED (test code failed)\n");
57 logprintf(logdepth+1, "FAILED: returned '%s' which is not a valid decimal number (at '%s')\n", out, end);
58 return 1;
59 }
60 sprintf(W, "%d", w * 8);
61 report("OK (%s bits)\n", W);
62 put("sys/ptrwidth", W);
63 logprintf(logdepth+1, "OK (%s bits)\n", W);
64 }
65 return 0;
66 }
67
68 int find_sys_byte_order(const char *name, int logdepth, int fatal)
69 {
70 const char *test_c =
71 NL "#include <stdio.h>"
72 NL "int main() {"
73 NL " long int i = 8;"
74 NL " char *s = (char *)&i;"
75 NL " printf(\"%d\\n\", s[0]);"
76 NL " return 0;"
77 NL "}"
78 NL;
79 const char* test_c_blind_template =
80 NL "#include <stdio.h>"
81 NL "#include <endian.h>"
82 NL "#ifndef __BYTE_ORDER"
83 NL "#error \"ERROR 1\""
84 NL "void void *;"
85 NL "#endif"
86 NL "#ifndef __%s_ENDIAN"
87 NL "#error \"ERROR 2\""
88 NL "char char *;"
89 NL "#endif"
90 NL "#if __BYTE_ORDER != __%s_ENDIAN"
91 NL "#error \"ERROR 3\""
92 NL "int int *;"
93 NL "#endif"
94 NL "int main() {"
95 NL " puts(\"OK\");"
96 NL " return 0;"
97 NL "}"
98 NL;
99 const char *key = "sys/byte_order";
100 const char *endians1[] = { "LITTLE", "BIG", NULL };
101 const char *endians2[] = { "LSB", "MSB", NULL };
102 int index;
103 char test_c_blind[1024];
104 char *end;
105 const char *W;
106 char *out = NULL;
107 int w;
108
109 require("cc/cc", logdepth, fatal);
110
111 report("Checking for byte order... ");
112 logprintf(logdepth, "find_sys_byte_order: trying to find byte order...\n");
113 logdepth++;
114
115 if ((!isblind(db_cwd)) && compile_run(logdepth, test_c, NULL, NULL, NULL, &out) == 0) {
116 w = strtol(out, &end, 10);
117 if (((*end != '\0') && (*end != '\n') && (*end != '\r')) || ((w != 0) && (w != 8))) {
118 report("FAILED (test code failed)\n");
119 logprintf(logdepth+1, "FAILED: returned '%s' which is not a valid decimal number (at '%s')\n", out, end);
120 return 1;
121 }
122 if (w == 0)
123 W = "MSB";
124 else
125 W = "LSB";
126
127 report("OK (%s first)\n", W);
128 put("sys/byte_order", W);
129 logprintf(logdepth+1, "OK (%s first)\n", W);
130 return 0;
131 }
132
133 for (index=0; endians1[index]!=NULL; ++index)
134 {
135 sprintf(test_c_blind, test_c_blind_template, endians1[index], endians1[index]);
136
137 if (compile_run(logdepth, test_c_blind, NULL, NULL, NULL, NULL) == 0)
138 {
139 W = endians2[index];
140 report("OK (%s first)\n", W);
141 put(key, W);
142 return 0;
143 }
144 }
145
146 report("FAILED (cannot determine byte order, you must supply it)\n");
147 return try_fail(logdepth, key);
148 }
149
150 static int test_shell_eats_backslash(int logdepth)
151 {
152 char *test = "echo c:\\n";
153 char *out;
154
155
156 logprintf(logdepth, "testing if shell eats \\...\n");
157 run_shell(logdepth+1, test, &out);
158 if (out == NULL) {
159 logprintf(logdepth+1, "oops, couldn't run shell?! (returned NULL)\n");
160 report("ERROR: shell fails.");
161 abort();
162 }
163 if (out[2] == '\\') {
164 logprintf(logdepth, "shell does NOT eat \\...\n");
165 put("sys/shell_eats_backslash", sfalse);
166 free(out);
167 return 0;
168 }
169
170 free(out);
171 logprintf(logdepth, "shell eats \\...\n");
172 put("sys/shell_eats_backslash", strue);
173 return 1;
174 }
175
176
177 static int try_get_cwd(int logdepth, const char *cmd)
178 {
179 char *cwd, *end;
180 run_shell(logdepth+1, cmd, &cwd);
181 if (cwd != NULL) {
182 end = strpbrk(cwd, "\r\n");
183 if (end != NULL)
184 *end = '\0';
185 if (*cwd != '\0') {
186 end = cwd + strlen(cwd) - 1;
187 while((*end == ' ') || (*end == '\t')) { *end = '\0'; end--; }
188 put("sys/tmp", cwd);
189 /* ugly hack for win32: paths there start as c:\ */
190 if ((cwd[1] == ':') && (cwd[2] == '\\'))
191 append("sys/tmp", "\\");
192 else
193 append("sys/tmp", "/");
194 logprintf(logdepth, "cwd is '%s'\n", get("sys/tmp"));
195 free(cwd);
196 return 1;
197 }
198 else
199 free(cwd);
200 }
201 return 0;
202 }
203
204 static int try_tmp(int logdepth)
205 {
206 char *fn;
207
208 logprintf(logdepth, "validating temp dir '%s'\n", get("sys/tmp"));
209 fn = tempfile_new_noabort("");
210 if (fn != NULL) {
211 unlink(fn);
212 free(fn);
213 logprintf(logdepth, "temp dir works!\n");
214 return 1;
215 }
216
217 logprintf(logdepth, "temp dir fails\n");
218 return 0;
219 }
220
221 /* test temp dir with all sort of workarounds */
222 static int try_tmp_all(int logdepth)
223 {
224 const char *tmp, *si;
225 char c;
226 char *t, *so, *old_tmp;
227 int eats, n;
228
229 tmp = get("sys/tmp");
230
231 /* path must end in path separator */
232 c = tmp[strlen(tmp)-1];
233 if ((c != '/') && (c != '\\')) {
234 append("sys/tmp", "/");
235 tmp = get("sys/tmp");
236 }
237
238 logprintf(logdepth, "trying detected temp dir '%s'\n", tmp);
239 if (try_tmp(logdepth+1)) return 1;
240
241 /* try msys-on-windows hack: if path starts with /d/something, try d:/ instead */
242 if ((tmp[0] == '/') && (isalpha(tmp[1])) && (tmp[2] == '/')) {
243 /* for the next test we shouldn't use our half-detected tmp path but go with . */
244 old_tmp = strclone(tmp);
245 put("sys/tmp", "");
246 eats = istrue(get("sys/shell_eats_backslash"));
247 tmp = old_tmp;
248 logprintf(logdepth, "tmp2='%s' eats=%d\n", tmp, eats);
249 t = malloc(strlen(tmp) * 2);
250 t[0] = tmp[1];
251 t[1] = ':';
252 for(si = tmp + 2, so = t + 2; *si != '\0'; si++, so++) {
253 if (*si == '/') {
254 *so = '\\';
255 if (eats) {
256 for(n = 0; n < 3; n++) {
257 so++;
258 *so = '\\';
259 }
260 }
261 }
262 else
263 *so = *si;
264 }
265 *so = '\0';
266 free(old_tmp);
267
268 logprintf(logdepth, "trying windows fix: '%s'\n", t);
269 put("sys/tmp", t);
270 free(t);
271 if (try_tmp(logdepth+1)) {
272 if (eats)
273 put("sys/path_sep", "\\\\\\\\");
274 else
275 put("sys/path_sep", "\\");
276 return 1;
277 }
278 tmp = get("sys/tmp");
279 }
280
281 /* fail. Set back tmp to empty so next command has a chance to run */
282 put("sys/tmp", "");
283 return 0;
284 }
285
286 int find_tmp(const char *name, int logdepth, int fatal)
287 {
288 const char *usertmp;
289
290 if (in_cross_target) {
291 report("Temp dir for cross compilation target is the same as for host...");
292 logprintf(logdepth, "Copying temp dir from host to target\n");
293 require("/host/sys/tmp", logdepth, fatal);
294 usertmp = get("/host/sys/tmp");
295 if (usertmp == NULL) {
296 report("Host temp dir not found.\n");
297 logprintf(logdepth, "Host temp dir not found.\n");
298 return 1;
299 }
300 put("sys/tmp", usertmp);
301 return 0;
302 }
303
304 /* we need shell for later tests; do this detection in . */
305 put("sys/tmp", "");
306 require("sys/shell", logdepth, fatal);
307
308 put("sys/path_sep", "/");
309
310 report("Detecting temp dir...");
311 logprintf(logdepth, "Finding temp dir (current working directory)...\n");
312
313 usertmp = get("/arg/sys/tmp");
314
315 /* . as tmp would fail for commands including a "cd" - this would cause
316 temporary files left in the target dir. We start out with empty
317 string (which is ., but on windows ./ would fail), and run
318 pwd (without cd) to find out the current directory (as getcwd() is not
319 portable). If pwd fails, we stay with ./ */
320 put("sys/tmp", "");
321
322 /* we need to know about shell backslash problem regardless of how
323 we end up with tmp - currently tmp is ., where the test could run
324 safely */
325 test_shell_eats_backslash(logdepth+1);
326
327 /* Special case: cross-compilation with emulator; we can not assume
328 the emulator uses the same paths as the host system, while we mix
329 accessing files from host and emu. If we stay in ., both emulator
330 and host system should be (more or less) happy. */
331 if (istarget(db_cwd) && iscross) {
332 if (usertmp == NULL) {
333 report("using temp dir . for cross-compilation\n");
334 logprintf(logdepth, "staying with . for cross-compilation\n");
335 }
336 else {
337 put("sys/tmp", usertmp);
338 report("using user supplied temp dir '%s' for cross-compilation\n", usertmp);
339 logprintf(logdepth, "using user supplied temp dir '%s' for cross-compilation\n", usertmp);
340 }
341 return 0;
342 }
343
344 if ((usertmp != NULL))
345 put("sys/tmp", usertmp);
346
347 if (
348 ((usertmp != NULL) && (try_tmp_all(logdepth+2))) || /* try user supplied temp dir */
349 ((try_get_cwd(logdepth+1, "pwd")) && (try_tmp_all(logdepth+2))) || /* try pwd for finding out cwd */
350 ((try_get_cwd(logdepth+1, "echo %cd%") && (try_tmp_all(logdepth+2))))) { /* try windows-specific way for finding out cwd */
351
352 report(" validated %s\n", get("sys/tmp"));
353 logprintf(logdepth, "Detected temp dir '%s'\n", get("sys/tmp"));
354 return 0;
355 }
356
357 put("sys/tmp", "");
358 report("using temp dir fallback .\n");
359 logprintf(logdepth, "all temp directories failed, using . as tmp\n");
360 return 0;
361 }
362
363 int test_shell(const char *shell, int logdepth, int quote)
364 {
365 char *test = "echo hello";
366 char *cmd;
367 char *out;
368 char *q;
369
370 if (quote)
371 q = "\"";
372 else
373 q = "";
374
375 logprintf(logdepth, "testing '%s' as shell\n", shell);
376 cmd = malloc(strlen(test) + strlen(shell) + 8);
377 sprintf(cmd, "%s %s%s%s", shell, q, test, q);
378
379 run(logdepth+1, cmd, &out);
380
381 free(cmd);
382
383 if ((out != NULL) && (strncmp(out, "hello", 5) == 0)) {
384 put("sys/shell", shell);
385 if (quote)
386 put("sys/shell_needs_quote", strue);
387 else
388 put("sys/shell_needs_quote", sfalse);
389 logprintf(logdepth, "accepted.\n");
390 free(out);
391 return 1;
392 }
393
394 logprintf(logdepth, "refused.\n");
395 free(out);
396 return 0;
397 }
398
399 static int find_shell_escape(const char *name, int logdepth, int fatal, const char *shell)
400 {
401 char cmdline[256];
402 char **t;
403 char *tests[] = {
404 "\\", "\\ {}&;|",
405 "^", "^ &",
406 NULL, NULL
407 };
408 (void) fatal; /* not used */
409 (void) shell; /* not used */
410
411 report("Looking for a shell escape character... ");
412 logprintf(logdepth, "finding shell escape character...\n");
413
414 for(t = tests; *t != NULL; t += 2) {
415 char *s, *end, *out, *start;
416 strcpy(cmdline, "echo ");
417 end = cmdline+5;
418 for(s = t[1]; *s != '\0'; s++) {
419 *end++ = *t[0];
420 *end++ = *s;
421 }
422 *end = '\0';
423 run(logdepth+1, cmdline, &out);
424 if (out != NULL) {
425 int res;
426 if (*out == '\"') /* wine likes to wrap the output in quotes for some reason */
427 start = out+1;
428 else
429 start = out;
430
431 res = strncmp(start, t[1], strlen(t[1]));
432 free(out);
433 if (res == 0) {
434 report("found: '%s'\n", t[0]);
435 logprintf(logdepth, "found shell escape char '%s'\n", t[0]);
436 put("sys/shell_escape_char", t[0]);
437 return 0;
438 }
439 }
440 }
441 report("NOT FOUND\n");
442 logprintf(logdepth, "shell escape character not found\n");
443
444 return 1;
445 }
446
447 int find_shell(const char *name, int logdepth, int fatal)
448 {
449 const char *shells[] = {
450 "/bin/sh -c",
451 "/bin/bash -c",
452 "bash -c",
453 "cmd.exe /c",
454 "sh -c",
455 "/bin/dash -c",
456 "dash -c",
457 "/bin/ksh -c",
458 "ksh -c",
459 NULL
460 };
461 const char **s;
462
463 if (cross_blind) {
464 const char *shell = get("/arg/sys/target-shell");
465 if (shell == NULL) {
466 report("Need to specify sys/target-shell in blind cross compiling mode, because the shell cannot be detected (note: scconfig will not attempt to run the target shell)\n");
467 exit(1);
468 }
469
470 put("sys/shell", shell);
471 report("Blind cross compiling: accepting '%s' as shell\n", shell);
472 logprintf(logdepth, "Blind cross compiling: accepting '%s' as shell\n", shell);
473 return 0;
474 }
475
476 report("Looking for a shell... ");
477 logprintf(logdepth, "finding a shell\n");
478
479 for(s = shells; *s != NULL; s++) {
480 if ((test_shell(*s, logdepth+1, 0)) || (test_shell(*s, logdepth+1, 1))) {
481 report("%s\n", *s);
482 logprintf(logdepth, "found a shell '%s', need quote: %s\n", *s, get("sys/shell_needs_quote"));
483 return find_shell_escape(name, logdepth, fatal, *s);
484 }
485 }
486
487 report("NOT FOUND\n");
488 logprintf(logdepth, "shell not found\n");
489 return 1;
490 }
0 /*
1 scconfig - glue layer for proper crosscompiling to target
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include "db.h"
24 #include "libs.h"
25
26 int find_target(const char *name, int logdepth, int fatal)
27 {
28 const char *target = get("/arg/sys/target");
29 const char *emu = get("/arg/sys/emu");
30
31 (void) logdepth; /* to suppress compiler warnings about not using logdepth */
32 (void) fatal; /* to suppress compiler warnings about not using fatal */
33
34 /* Does target differ from host? */
35 if (target == NULL) {
36 db_link("/host", "/target");
37 #ifdef RUNTIME
38 db_link("/host", "/runtime");
39 #endif
40 put("/target/sys/cross", sfalse);
41 put("/target/sys/cross_blind", sfalse);
42 return 0;
43 }
44 else
45 db_mkdir("/target");
46
47 put("/target/sys/target", target);
48 put("/target/sys/cross", strue);
49 if (emu != NULL)
50 put("/target/sys/emu", emu);
51
52 /* If so, check if emulator is provided */
53 cross_blind = ((emu == NULL) || (*emu == '\0'));
54 put("/target/sys/cross_blind", cross_blind ? strue : sfalse);
55
56 return 0;
57 }
0 /*
1 scconfig - detection of standard library features
2 Copyright (C) 2009,2017 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "db.h"
28 #include "dep.h"
29
30 int find_lib_lpthread(const char *name, int logdepth, int fatal)
31 {
32 const char *lpthread;
33 char *s;
34 int ret = 0;
35
36 char *test_c_recursive =
37 NL "#define _GNU_SOURCE 1 /* Needed for recursive thread-locking */"
38 NL "#include <pthread.h>"
39 NL "pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;"
40 NL "int main() {"
41 NL " pthread_attr_t a;"
42 NL " if (pthread_attr_init(&a) == 0)"
43 NL " puts(\"OK\");"
44 NL " return 0;"
45 NL "}"
46 NL ;
47
48 char *test_c_simple =
49 NL "#include <pthread.h>"
50 NL "int main() {"
51 NL " pthread_attr_t a;"
52 NL " if (pthread_attr_init(&a) == 0)"
53 NL " puts(\"OK\");"
54 NL " return 0;"
55 NL "}"
56 NL ;
57
58 require("cc/cc", logdepth, fatal);
59
60 report("Checking for -lpthread... ");
61 logprintf(logdepth, "find_lib_lpthread: trying to find lpthread...\n");
62 logdepth++;
63
64 lpthread = get("/arg/libs/lpthread");
65
66 if (lpthread != NULL) {
67 put("libs/lpthread", lpthread);
68 report("User provided... ");
69 s = strclone(lpthread);
70 }
71 else
72 s = strclone("-lpthread");
73
74 if (try_icl(logdepth, NULL, test_c_recursive, NULL, NULL, s)) {
75 put("libs/lpthread", s);
76 put("libs/lpthread-recursive", strue);
77 report("OK, recursive (%s)\n", s);
78 }
79 else if (try_icl(logdepth, NULL, test_c_simple, NULL, NULL, s)) {
80 put("libs/lpthread", s);
81 put("libs/lpthread-recursive", sfalse);
82 report("OK, NOT RECURSIVE (%s)\n", s);
83 }
84 else
85 ret = 1;
86
87 free(s);
88 return ret;
89 }
90
91 int find_thread_semget(const char *name, int logdepth, int fatal)
92 {
93 const char *test_c =
94 NL "#include <stdio.h>"
95 NL "int main()"
96 NL "{"
97 NL " int semid = semget(IPC_PRIVATE, 1, IPC_CREAT);"
98 NL " if (semid < 0) return 0;"
99 NL " if(semctl(semid, 0, IPC_RMID) < 0) return 0;"
100 NL " puts(\"OK\");"
101 NL " return 0;"
102 NL "}"
103 NL;
104 const char *node = "thread/semget";
105 char **inc, *incs[] = {"#include <sys/types.h>\n#include <sys/ipc.h>\n#include <sys/sem.h>", "#include <sys/types.h>\n#include <sys/ipc.h>", "#include <sys/types.h>\n#include <sys/sem.h>", NULL};
106
107 if (require("cc/cc", logdepth, fatal))
108 return try_fail(logdepth, node);
109
110 report("Checking for semget... ");
111 logprintf(logdepth, "find_semget:\n");
112 logdepth++;
113
114 for(inc = incs; *inc != NULL; inc++)
115 if (try_icl(logdepth, node, test_c, *inc, NULL, NULL) != 0)
116 return 0;
117
118 return try_fail(logdepth, node);
119 }
120
121 int find_thread_pthread_create(const char *name, int logdepth, int fatal)
122 {
123 const char *test_c =
124 NL "#include <stdio.h>"
125 NL "void* test_thread(void* param)"
126 NL "{"
127 NL " return NULL;"
128 NL "}"
129 NL "int main()"
130 NL "{"
131 NL " pthread_t pt;"
132 NL " if (pthread_create(&pt, NULL, test_thread, NULL) == 0)"
133 NL " puts(\"OK\");"
134 NL " return 0;"
135 NL "}"
136 NL;
137 const char *node = "thread/pthread_create";
138 char **inc, *incs[] = {"#include <pthread.h>", "#include <pthread.h>\n#include <signal.h>", NULL};
139 const char *lpthread;
140 char* s;
141
142 if (require("cc/cc", logdepth, fatal))
143 return try_fail(logdepth, node);
144
145 report("Checking for pthread_create... ");
146 logprintf(logdepth, "find_pthread_create:\n");
147 logdepth++;
148
149 lpthread = get("/arg/libs/lpthread");
150
151 if (lpthread != NULL) {
152 report("User provided... ");
153 s = strclone(lpthread);
154 }
155 else
156 s = strclone("-lpthread");
157
158 for(inc = incs; *inc != NULL; inc++)
159 if (try_icl(logdepth, node, test_c, *inc, NULL, s) != 0) {
160 free(s);
161 return 0;
162 }
163
164 free(s);
165 return try_fail(logdepth, node);
166 }
167
168 int find_thread_CreateSemaphore(const char *name, int logdepth, int fatal)
169 {
170 const char *test_c =
171 NL "#include <stdio.h>"
172 NL "int main()"
173 NL "{"
174 NL " if (CreateSemaphore(NULL, 1, 1, NULL))"
175 NL " puts(\"OK\");"
176 NL " return 0;"
177 NL "}"
178 NL;
179 const char *node = "thread/CreateSemaphore";
180
181 if (require("cc/cc", logdepth, fatal))
182 return try_fail(logdepth, node);
183
184 report("Checking for CreateSemaphore... ");
185 logprintf(logdepth, "find_thread_CreateSemaphore:\n");
186 logdepth++;
187
188 if (try_icl(logdepth, node, test_c, "#include <windows.h>", NULL, NULL) != 0)
189 return 0;
190
191 return try_fail(logdepth, node);
192 }
193
194 int find_thread_CreateThread(const char *name, int logdepth, int fatal)
195 {
196 const char *test_c =
197 NL "#include <stdio.h>"
198 NL "DWORD WINAPI test_thread(void* param)"
199 NL "{"
200 NL " return 0;"
201 NL "}"
202 NL "int main()"
203 NL "{"
204 NL " if (CreateThread(NULL, 0, test_thread, NULL, 0, NULL))"
205 NL " puts(\"OK\");"
206 NL " return 0;"
207 NL "}"
208 NL;
209 const char *node = "thread/CreateThread";
210
211 if (require("cc/cc", logdepth, fatal))
212 return try_fail(logdepth, node);
213
214 report("Checking for CreateThread... ");
215 logprintf(logdepth, "find_thread_CreateThread:\n");
216 logdepth++;
217
218 if (try_icl(logdepth, node, test_c, "#include <windows.h>", NULL, NULL) != 0)
219 return 0;
220
221 return try_fail(logdepth, node);
222 }
0 /*
1 scconfig - detection of standard library features: time/date/sleep related calls
2 Copyright (C) 2011..2012 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "db.h"
28 #include "dep.h"
29
30 int find_time_usleep(const char *name, int logdepth, int fatal)
31 {
32 char *test_c =
33 NL "#include <unistd.h>"
34 NL "int main() {"
35 NL " if (usleep(1) == 0)"
36 NL " puts(\"OK\");"
37 NL " return 0;"
38 NL "}"
39 NL;
40
41 require("cc/cc", logdepth, fatal);
42
43 report("Checking for usleep()... ");
44 logprintf(logdepth, "find_time_usleep: trying to find usleep...\n");
45 logdepth++;
46
47 if (try_icl(logdepth, "libs/time/usleep", test_c, NULL, NULL, NULL))
48 return 0;
49 return try_fail(logdepth, "libs/time/usleep");
50 }
51
52 int find_time_Sleep(const char *name, int logdepth, int fatal)
53 {
54 char *test_c =
55 NL "int main() {"
56 NL " Sleep(1);"
57 NL " puts(\"OK\");"
58 NL " return 0;"
59 NL "}"
60 NL;
61
62 require("cc/cc", logdepth, fatal);
63
64 report("Checking for Sleep()... ");
65 logprintf(logdepth, "find_time_Sleep: trying to find Sleep...\n");
66 logdepth++;
67
68 if (try_icl(logdepth, "libs/time/Sleep", test_c, "#include <windows.h>", NULL, NULL))
69 return 0;
70 return try_fail(logdepth, "libs/time/Sleep");
71 }
72
73 int find_time_gettimeofday(const char *name, int logdepth, int fatal)
74 {
75 char *test_c =
76 NL "#include <stdlib.h>"
77 NL "int main() {"
78 NL " struct timeval tv;"
79 NL " if (gettimeofday(&tv, NULL) == 0)"
80 NL " puts(\"OK\");"
81 NL " return 0;"
82 NL "}"
83 NL;
84
85 require("cc/cc", logdepth, fatal);
86
87 report("Checking for gettimeofday()... ");
88 logprintf(logdepth, "find_time_gettimeofday: trying to find gettimeofday...\n");
89 logdepth++;
90
91 if (try_icl(logdepth, "libs/time/gettimeofday", test_c, "#include <sys/time.h>", NULL, NULL))
92 return 0;
93 return try_fail(logdepth, "libs/time/gettimeofday");
94 }
95
96
97 int find_time_ftime(const char *name, int logdepth, int fatal)
98 {
99 char *test_c =
100 NL "int main() {"
101 NL " struct timeb tb;"
102 NL " if (ftime(&tb) == 0)"
103 NL " puts(\"OK\");"
104 NL " return 0;"
105 NL "}"
106 NL;
107
108 require("cc/cc", logdepth, fatal);
109
110 report("Checking for ftime()... ");
111 logprintf(logdepth, "find_time_ftime: trying to find ftime...\n");
112 logdepth++;
113
114 if (try_icl(logdepth, "libs/time/ftime", test_c, "#include <sys/timeb.h>", NULL, NULL))
115 return 0;
116 return try_fail(logdepth, "libs/time/ftime");
117 }
118
119 static const char timegm_test_c_template[] =
120 NL "void my_puts(const char *s);"
121 NL "int main() {"
122 NL " struct tm tm;"
123 NL " tm.tm_sec = 50;"
124 NL " tm.tm_min = 30;"
125 NL " tm.tm_hour = 6;"
126 NL " tm.tm_mday = 1;"
127 NL " tm.tm_mon = 11;"
128 NL " tm.tm_year = 2018 - 1900;"
129 NL " tm.tm_wday = 0;"
130 NL " tm.tm_yday = 0;"
131 NL " if (%s(&tm) != (time_t)(-1))"
132 NL " my_puts(\"OK\");"
133 NL " return 0;"
134 NL "}"
135 NL "#include <stdio.h>"
136 NL "void my_puts(const char *s)"
137 NL "{"
138 NL " puts(s);"
139 NL "}"
140 NL;
141
142 int find_time_timegm(const char *name, int logdepth, int fatal)
143 {
144 char test_c[1000];
145 sprintf(test_c, timegm_test_c_template, "timegm");
146
147 require("cc/cc", logdepth, fatal);
148
149 report("Checking for timegm()... ");
150 logprintf(logdepth, "find_time_timegm: trying to find timegm...\n");
151 logdepth++;
152
153 if (try_icl(logdepth, "libs/time/timegm", test_c, "#include <time.h>", NULL, NULL))
154 return 0;
155 return try_fail(logdepth, "libs/time/timegm");
156 }
157
158 int find_time_mkgmtime(const char *name, int logdepth, int fatal)
159 {
160 char test_c[1000];
161 const char *ldflags[] = {"","-lmsvcr120","-lmsvcr110","-lmsvcr100","-lmsvcr90","-lmsvcr80","-lmsvcr71","-lmsvcr70",NULL};
162 const char **ldf;
163
164 sprintf(test_c, timegm_test_c_template, "_mkgmtime");
165
166 require("cc/cc", logdepth, fatal);
167
168 report("Checking for _mkgmtime()... ");
169 logprintf(logdepth, "find_time_mkgmtime: trying to find _mkgmtime...\n");
170 logdepth++;
171
172 for (ldf = ldflags; *ldf; ++ldf)
173 if (try_icl(logdepth, "libs/time/_mkgmtime", test_c, "#include <time.h>", NULL, *ldf))
174 return 0;
175 return try_fail(logdepth, "libs/time/_mkgmtime");
176 }
177
178 int find_time_gmtime_r(const char *name, int logdepth, int fatal)
179 {
180 const char test_c[] =
181 NL "void my_puts(const char *s);"
182 NL "int main() {"
183 NL " time_t tim = 1543645850;"
184 NL " struct tm tm;"
185 NL " if (gmtime_r(&tim, &tm)" /* returns '&tm' */
186 NL " && 50==tm.tm_sec"
187 NL " && 30==tm.tm_min"
188 NL " && 6==tm.tm_hour"
189 NL " && 1==tm.tm_mday"
190 NL " && 11==tm.tm_mon"
191 NL " && (2018-1900)==tm.tm_year)"
192 NL " my_puts(\"OK\");"
193 NL " return 0;"
194 NL "}"
195 NL "#include <stdio.h>"
196 NL "void my_puts(const char *s)"
197 NL "{"
198 NL " puts(s);"
199 NL "}"
200 NL;
201
202 require("cc/cc", logdepth, fatal);
203
204 report("Checking for gmtime_r()... ");
205 logprintf(logdepth, "find_time_gmtime_r: trying to find gmtime_r...\n");
206 logdepth++;
207
208 if (try_icl(logdepth, "libs/time/gmtime_r", test_c, "#include <time.h>", NULL, NULL))
209 return 0;
210 return try_fail(logdepth, "libs/time/gmtime_r");
211 }
212
213 int find_time_gmtime_s(const char *name, int logdepth, int fatal)
214 {
215 const char test_c[] =
216 NL "void my_puts(const char *s);"
217 NL "int main() {"
218 NL " time_t tim = 1543645850;"
219 NL " struct tm tm;"
220 NL " if (0==gmtime_s(&tm, &tim)" /* returns errno */
221 NL " && 50==tm.tm_sec"
222 NL " && 30==tm.tm_min"
223 NL " && 6==tm.tm_hour"
224 NL " && 1==tm.tm_mday"
225 NL " && 11==tm.tm_mon"
226 NL " && (2018-1900)==tm.tm_year)"
227 NL " my_puts(\"OK\");"
228 NL " return 0;"
229 NL "}"
230 NL "#include <stdio.h>"
231 NL "void my_puts(const char *s)"
232 NL "{"
233 NL " puts(s);"
234 NL "}"
235 NL;
236
237 require("cc/cc", logdepth, fatal);
238
239 report("Checking for gmtime_s()... ");
240 logprintf(logdepth, "find_time_gmtime_s: trying to find gmtime_s...\n");
241 logdepth++;
242
243 if (try_icl(logdepth, "libs/time/gmtime_s", test_c, "#include <time.h>", NULL, NULL))
244 return 0;
245 return try_fail(logdepth, "libs/time/gmtime_s");
246 }
0 /*
1 scconfig - detection of types and type sizes
2 Copyright (C) 2012 Tibor Palinkas
3 Copyright (C) 2017-2018 Aron Barath
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Project page: http://repo.hu/projects/scconfig
20 Contact via email: scconfig [at] igor2.repo.hu
21 */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include "libs.h"
27 #include "log.h"
28 #include "db.h"
29 #include "dep.h"
30
31 /* assume there is no integer that is at least this wide, in bytes */
32 #define MAX_INT_WIDTH 9
33 /* ('long double' can be 16 bytes; see https://en.wikipedia.org/wiki/Long_double) */
34 #define MAX_FLT_WIDTH 17
35
36 static int try_size(int logdepth, char *cflags, char *ldflags, const char *type, int use_stdint, const char *path, const char **sizearr, unsigned char *inc_stdint, const int max_width)
37 {
38 char *out = NULL;
39 const char *test_c_template =
40 NL "#include <stdio.h>"
41 NL "int main() {"
42 NL " printf(\"OK %%d\\n\", sizeof(%s));"
43 NL " return 0;"
44 NL "}"
45 NL;
46 char test_c[512], *start;
47 const char *inc = "#include <stdint.h>\n";
48 int size;
49
50 if (use_stdint) {
51 strcpy(test_c, inc);
52 start = test_c + strlen(inc);
53 }
54 else
55 start = test_c;
56 sprintf(start, test_c_template, type);
57
58 report("Testing size of type %25s... ", type);
59
60 logprintf(logdepth, "trying size with ldflags '%s'\n", ldflags == NULL ? get("cc/ldflags") : ldflags);
61 if (compile_run(logdepth+1, test_c, NULL, cflags, ldflags, &out) == 0) {
62 if (target_emu_fail(out)) {
63 report(" FAIL (emulator)\n");
64 free(out);
65 return -1;
66 }
67
68 if (strncmp(out, "OK", 2) == 0) {
69 size = atoi(out+3);
70 if ((size > 0) && (size < max_width)) {
71 sprintf(test_c, "%d", size);
72 put(path, test_c);
73 sizearr[size] = type;
74 if (inc_stdint != NULL)
75 inc_stdint[size] = use_stdint;
76 report(" OK, size %d byte%s\n", size, (size > 1) ? "s" : "");
77 }
78 else {
79 report(" FAIL, size %d bytes\n", size);
80 size = -1;
81 }
82 free(out);
83 return size;
84 }
85 free(out);
86 }
87 report(" FAIL (compile)\n");
88 return -1;
89 }
90
91 int find_types_stdint(const char *name, int logdepth, int fatal)
92 {
93 char *test_c =
94 NL "#include <stdint.h>"
95 NL "int main() {"
96 NL " if (sizeof(uint8_t) == 1)"
97 NL " puts(\"OK\");"
98 NL " return 0;"
99 NL "}"
100 NL;
101
102 require("cc/cc", logdepth, fatal);
103
104 report("Checking for stdint.h... ");
105 logprintf(logdepth, "find_types_stdint: trying to find stdint.h...\n");
106 logdepth++;
107
108 if (try_icl(logdepth, "libs/types/stdint", test_c, NULL, NULL, NULL))
109 return 0;
110 return try_fail(logdepth, "libs/types/stdint");
111 }
112
113 int find_types_sizes(const char *name, int logdepth, int fatal)
114 {
115 const char *stdint;
116 const char *sizearr_u[MAX_INT_WIDTH];
117 const char *sizearr_s[MAX_INT_WIDTH];
118 const char *sizearr_f[MAX_FLT_WIDTH];
119 unsigned char inc_stdint_u[MAX_INT_WIDTH];
120 unsigned char inc_stdint_s[MAX_INT_WIDTH];
121 int n;
122 const char *includes = "";
123 const char *path_template = "sys/types/size/%d_%c_int";
124 const char *path_template_f = "sys/types/size/%d_float";
125 char path[64];
126
127 require("cc/cc", logdepth, fatal);
128 require("libs/types/stdint/presents", logdepth, 0);
129 stdint = get("libs/types/stdint/presents");
130
131 for(n = 0; n < MAX_INT_WIDTH; n++) {
132 sizearr_u[n] = NULL;
133 sizearr_s[n] = NULL;
134 inc_stdint_u[n] = 0;
135 inc_stdint_s[n] = 0;
136 }
137 for(n = 0; n < MAX_FLT_WIDTH; n++)
138 sizearr_f[n] = NULL;
139
140 try_size(logdepth+1, NULL, NULL, "unsigned long long int", 0, "sys/types/size/unsigned_long_long_int", sizearr_u, NULL, MAX_INT_WIDTH);
141 try_size(logdepth+1, NULL, NULL, "unsigned char", 0, "sys/types/size/unsigned_char", sizearr_u, NULL, MAX_INT_WIDTH);
142 try_size(logdepth+1, NULL, NULL, "unsigned short int", 0, "sys/types/size/unsigned_short_int", sizearr_u, NULL, MAX_INT_WIDTH);
143 try_size(logdepth+1, NULL, NULL, "unsigned int", 0, "sys/types/size/unsigned_int", sizearr_u, NULL, MAX_INT_WIDTH);
144 try_size(logdepth+1, NULL, NULL, "unsigned long int", 0, "sys/types/size/unsigned_long_int", sizearr_u, NULL, MAX_INT_WIDTH);
145
146 try_size(logdepth+1, NULL, NULL, "signed long long int", 0, "sys/types/size/signed_long_long_int", sizearr_s, NULL, MAX_INT_WIDTH);
147 try_size(logdepth+1, NULL, NULL, "signed char", 0, "sys/types/size/signed_char", sizearr_s, NULL, MAX_INT_WIDTH);
148 try_size(logdepth+1, NULL, NULL, "signed short int", 0, "sys/types/size/signed_short_int", sizearr_s, NULL, MAX_INT_WIDTH);
149 try_size(logdepth+1, NULL, NULL, "signed int", 0, "sys/types/size/signed_int", sizearr_s, NULL, MAX_INT_WIDTH);
150 try_size(logdepth+1, NULL, NULL, "signed long int", 0, "sys/types/size/signed_long_int", sizearr_s, NULL, MAX_INT_WIDTH);
151
152 if ((stdint != NULL) && (istrue(stdint))) {
153 try_size(logdepth+1, NULL, NULL, "uint8_t", 1, "sys/types/size/uint8_t", sizearr_u, inc_stdint_u, MAX_INT_WIDTH);
154 try_size(logdepth+1, NULL, NULL, "uint16_t", 1, "sys/types/size/uint16_t", sizearr_u, inc_stdint_u, MAX_INT_WIDTH);
155 try_size(logdepth+1, NULL, NULL, "uint32_t", 1, "sys/types/size/uint32_t", sizearr_u, inc_stdint_u, MAX_INT_WIDTH);
156 try_size(logdepth+1, NULL, NULL, "uint64_t", 1, "sys/types/size/uint64_t", sizearr_u, inc_stdint_u, MAX_INT_WIDTH);
157 try_size(logdepth+1, NULL, NULL, "int8_t", 1, "sys/types/size/int8_t", sizearr_s, inc_stdint_s, MAX_INT_WIDTH);
158 try_size(logdepth+1, NULL, NULL, "int16_t", 1, "sys/types/size/int16_t", sizearr_s, inc_stdint_s, MAX_INT_WIDTH);
159 try_size(logdepth+1, NULL, NULL, "int32_t", 1, "sys/types/size/int32_t", sizearr_s, inc_stdint_s, MAX_INT_WIDTH);
160 try_size(logdepth+1, NULL, NULL, "int64_t", 1, "sys/types/size/int64_t", sizearr_s, inc_stdint_s, MAX_INT_WIDTH);
161 }
162
163 try_size(logdepth+1, NULL, NULL, "float", 0, "sys/types/size/float", sizearr_f, NULL, MAX_FLT_WIDTH);
164 try_size(logdepth+1, NULL, NULL, "double", 0, "sys/types/size/double", sizearr_f, NULL, MAX_FLT_WIDTH);
165 try_size(logdepth+1, NULL, NULL, "long double", 0, "sys/types/size/long_double", sizearr_f, NULL, MAX_FLT_WIDTH);
166
167 for(n = 0; n < MAX_INT_WIDTH; n++) {
168 if (sizearr_u[n] != NULL) {
169 report("Found best fit %d bytes wide uint: %s\n", n, sizearr_u[n]);
170 sprintf(path, path_template, n, 'u');
171 put(path, sizearr_u[n]);
172 if (inc_stdint_u[n])
173 includes = "#include <stdint.h>";
174 }
175 if (sizearr_s[n] != NULL) {
176 report("Found best fit %d bytes wide sint: %s\n", n, sizearr_s[n]);
177 sprintf(path, path_template, n, 's');
178 put(path, sizearr_s[n]);
179 if (inc_stdint_s[n])
180 includes = "#include <stdint.h>";
181 }
182 }
183 for(n = 0; n < MAX_FLT_WIDTH; n++) {
184 if (sizearr_f[n] != NULL) {
185 report("Found best fit %d bytes wide float: %s\n", n, sizearr_f[n]);
186 sprintf(path, path_template_f, n);
187 put(path, sizearr_f[n]);
188 }
189 }
190
191 put("sys/types/size/presents", strue); /* to avoid redetection */
192 put("sys/types/size/includes", includes);
193
194 return 0;
195 }
196
197
198 int find_types_something_t(const char *name, int logdepth, int fatal, const char *prefix, const char *typ, const char *define, const char *try_include)
199 {
200 char *out = NULL;
201 int res;
202 char test_c[512];
203 char node[256], *nodeend;
204 const char **include, *includes[] = {"", "#include <stddef.h>", "#include <sys/types.h>", "#include <sys/types/types.h>", "#include <stdlib.h>", "#include <unistd.h>", "#include <stdio.h>", NULL};
205 const char ** const first_include = (try_include && *try_include) ? includes : (includes+1);
206
207 char *test_c_include =
208 NL "%s"
209 NL "int my_puts(const char *s);"
210 NL "%s"
211 NL "int main() {"
212 NL " %s s;"
213 NL " my_puts(\"OK\");"
214 NL " return 0;"
215 NL "}"
216 NL "#include <stdio.h>"
217 NL "int my_puts(const char *s)"
218 NL "{"
219 NL " return puts(s);"
220 NL "}"
221 NL;
222
223 char *test_c_size =
224 NL "%s"
225 NL "#include <stdio.h>"
226 NL "%s"
227 NL "int main() {"
228 NL " printf(\"%%d\", sizeof(%s));"
229 NL " return 0;"
230 NL "}"
231 NL;
232
233 char *test_c_broken =
234 NL "%s"
235 NL "int my_puts(const char *s);"
236 NL "%s"
237 NL "int main() {"
238 NL " %s s;"
239 NL " void *v;"
240 NL " if (sizeof(v) != sizeof(s)) my_puts(\"yes\");"
241 NL " else my_puts(\"no\");"
242 NL " return 0;"
243 NL "}"
244 NL "#include <stdio.h>"
245 NL "int my_puts(const char *s)"
246 NL "{"
247 NL " return puts(s);"
248 NL "}"
249 NL;
250
251 includes[0] = try_include;
252
253 require("cc/cc", logdepth, fatal);
254
255 report("Checking for type %s... ", typ);
256 logprintf(logdepth, "find_types_something_t: Checking for %s...\n", typ);
257 logdepth++;
258
259 sprintf(node, "%s/%s", prefix, typ);
260 nodeend = node + strlen(node);
261
262 /* replace '*' at the end of the node path with _ptr so it can be saved in the tree */
263 if (nodeend[-1] == '*') {
264 nodeend--;
265 while((nodeend > node) && (*nodeend == ' ')) nodeend--;
266 strcpy(nodeend-1, "_ptr");
267 nodeend+=4;
268 }
269
270 nodeend[0] = '/';
271 nodeend[1] = '\0';
272 nodeend++;
273
274 if (define == NULL)
275 define = "";
276
277 for(include = first_include; *include != NULL; include++) {
278 sprintf(test_c, test_c_include, define, *include, typ);
279 if ((compile_run(logdepth, test_c, NULL, NULL, NULL, &out) == 0) && (strncmp(out, "OK", 2) == 0)) {
280 report("Found; ");
281 logprintf(logdepth+1, "include %s works\n", *include);
282 sprintf(nodeend, "includes");
283 if (define) {
284 put(node, define);
285 append(node, "\\n");
286 append(node, *include);
287 } else
288 put(node, *include);
289 break;
290 }
291 logprintf(logdepth+1, "include %s fails\n", *include);
292 if (out != NULL)
293 free(out);
294 }
295 if (*include == NULL) {
296 report("Not found\n");
297 return 1;
298 }
299
300 sprintf(nodeend, "presents");
301 put(node, strue);
302
303 /* check if typ is broken (smaller than void *) */
304 sprintf(test_c, test_c_broken, define, *include, typ);
305 if (compile_run(logdepth, test_c, NULL, NULL, NULL, &out) == 0) {
306 if ((out != NULL) && (strncmp(out, "yes", 3) == 0)) {
307 report("(%s is narrower than void *)\n", typ);
308 sprintf(nodeend, "broken");
309 put(node, strue);
310 res = 0;
311 }
312 else if ((out != NULL) && (strncmp(out, "no", 2) == 0)) {
313 report("(%s is not narrower than void *)\n", typ);
314 sprintf(nodeend, "broken");
315 put(node, sfalse);
316 res = 0;
317 }
318 else {
319 report("ERROR: test failed (%s)\n", out);
320 res = 1;
321 }
322 }
323 if (out != NULL)
324 free(out);
325
326 if (res == 0) {
327 report("Checking for size of %s... ", typ);
328 sprintf(test_c, test_c_size, define, *include, typ);
329 if (compile_run(logdepth, test_c, NULL, NULL, NULL, &out) == 0) {
330 if (out != NULL) {
331 report("(sizeof %s is %s)\n", typ, out);
332 sprintf(nodeend, "size");
333 put(node, out);
334 }
335 }
336 if (out != NULL)
337 free(out);
338 }
339
340 return res;
341 }
342
343
344 int find_types_size_t(const char *name, int logdepth, int fatal)
345 {
346 return find_types_something_t(name, logdepth, fatal, "sys/types", "size_t", NULL, NULL);
347 }
348
349 int find_types_off_t(const char *name, int logdepth, int fatal)
350 {
351 return find_types_something_t(name, logdepth, fatal, "sys/types", "off_t", NULL, NULL);
352 }
353
354 int find_types_off64_t(const char *name, int logdepth, int fatal)
355 {
356 return find_types_something_t(name, logdepth, fatal, "sys/types", "off64_t", NULL, NULL) &&
357 find_types_something_t(name, logdepth, fatal, "sys/types", "off64_t", "#define _LARGEFILE64_SOURCE", NULL);
358 }
359
360 int find_types_gid_t(const char *name, int logdepth, int fatal)
361 {
362 return find_types_something_t(name, logdepth, fatal, "sys/types", "gid_t", NULL, NULL);
363 }
364
365 int find_types_uid_t(const char *name, int logdepth, int fatal)
366 {
367 return find_types_something_t(name, logdepth, fatal, "sys/types", "uid_t", NULL, NULL);
368 }
369
370 int find_types_pid_t(const char *name, int logdepth, int fatal)
371 {
372 return find_types_something_t(name, logdepth, fatal, "sys/types", "pid_t", NULL, NULL);
373 }
374
375 int find_types_mode_t(const char *name, int logdepth, int fatal)
376 {
377 return find_types_something_t(name, logdepth, fatal, "sys/types", "mode_t", NULL, NULL);
378 }
379
380 int find_types_nlink_t(const char *name, int logdepth, int fatal)
381 {
382 return find_types_something_t(name, logdepth, fatal, "sys/types", "nlink_t", NULL, NULL);
383 }
384
385 int find_types_ptrdiff_t(const char *name, int logdepth, int fatal)
386 {
387 return find_types_something_t(name, logdepth, fatal, "sys/types", "ptrdiff_t", NULL, NULL);
388 }
389
390 int find_types_dev_t(const char *name, int logdepth, int fatal)
391 {
392 return find_types_something_t(name, logdepth, fatal, "sys/types", "dev_t", NULL, NULL);
393 }
394
395 int find_types_ino_t(const char *name, int logdepth, int fatal)
396 {
397 return find_types_something_t(name, logdepth, fatal, "sys/types", "ino_t", NULL, NULL);
398 }
399
400 int find_types_void_ptr(const char *name, int logdepth, int fatal)
401 {
402 return find_types_something_t(name, logdepth, fatal, "sys/types", "void *", NULL, NULL);
403 }
0 /*
1 scconfig - evaluate uname and classify the system
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include "regex.h"
26 #include "log.h"
27 #include "db.h"
28 #include "libs.h"
29 #include "dep.h"
30
31 static void sys_unix(void)
32 {
33 put("sys/ext_exe", "");
34 put("sys/ext_dynlib", ".so");
35 put("sys/ext_stalib", ".a");
36 put("sys/ext_dynlib_native", ".so");
37 }
38
39 static void sys_netbsd(void)
40 {
41 sys_unix();
42 put("cc/ldflags", "-Wl,-R/usr/pkg/lib -L/usr/pkg/lib"); /* TODO: is this the best way? */
43 }
44
45 static void sys_win32dlc(void)
46 {
47 put("sys/ext_exe", ".exe");
48 put("sys/ext_dynlib", ".dlc");
49 put("sys/ext_stalib", ".a");
50 put("sys/ext_dynlib_native", ".dll");
51 }
52
53 typedef void (*callback_t)(void);
54
55 typedef struct {
56 char *uname_regex;
57 char *name;
58 char *class;
59
60 callback_t callback;
61 } uname_t;
62
63 typedef struct {
64 char *file_name;
65 char *name;
66 char *class;
67
68 callback_t callback;
69 } magic_file_t;
70
71 /* Guess system class by uname; class is informative, nothing important
72 should depend on it.
73 Order *does* matter */
74 uname_t unames[] = {
75 {"[Nn]et[Bb][Ss][Dd]", "NetBSD", "UNIX", sys_netbsd},
76 {"[Ll]inux", "Linux", "UNIX", sys_unix},
77 {"[Bb][Ss][Dd]", "BSD", "UNIX", sys_unix},
78 {"SunOS", "SunOS", "UNIX", sys_unix},
79 {"OSF1", "OSF", "UNIX", sys_unix}, /* TODO: note the difference in cflags for debugging ("-ms -g") */
80 {"IRIX", "IRIX", "UNIX", sys_unix},
81 {"SunOS", "SunOS", "UNIX", sys_unix},
82 {"[Mm]inix", "Minix", "UNIX", sys_unix},
83 {"[Aa][Rr][Oo][Ss]", "Aros", "UNIX", sys_unix},
84 {"^Darwin", "MacOSX", "UNIX", sys_unix},
85 {"[Th]hreos", "Threos", "UNIX", sys_unix},
86 {"[Cc]ygwin", "cygwin", "WIN32", sys_win32dlc},
87 {"[Mm][Ii][Nn][Gg][Ww]", "mingw", "WIN32", sys_win32dlc},
88 {"win32", "win32", "WIN32", sys_win32dlc}, /* vanilla windows */
89 {NULL, NULL, NULL, NULL}
90 };
91
92 /* Fallback: extract machine name from uname -a if uname -m fails */
93 static const char *machine_names[] = {
94 "i[0-9]86[^ ]*", "x86_[^ ]*", "amd[0-9]*", "armv[0-9][^ ]*", "ppc[0-9]+",
95 "sparc[0-9]*", "BePC", "ia64", "x86", "IP[0-9]*", "k1om", "sun4u",
96 "RM600", "R4000", "alpha",
97 NULL
98 };
99
100 /* Fallback: extract system name from uname -a if uname -s fails */
101 static const char *system_names[] = {
102 "[Ll]inux", "sn5[0-9]*", "CYGWIN_NT[^ ]*", "GNU[^ ]*", "DragonFly",
103 "[^ ]*BSD[^ ]*", "Haiku", "HP-UX", "AIX", "OS4000", "Interix",
104 "IRIX[0-9]*", "Darwin", "Minix", "MINGW[^ ]*", "ReliantUNIX[^ ]*",
105 "SunOS", "OSF1", "ULTRIX", "UWIN-W7", "IS/WB", "OS/390",
106 "SCO[^ ]*", "QNX",
107 NULL
108 };
109
110 /* Fallback: if uname -a fails, guess system by looking at "magic file names" */
111 magic_file_t magic_files[] = {
112 {"/dev/null", "UNIX", "UNIX", sys_unix},
113 {"c:\\config.sys", "win32", "WIN32", sys_win32dlc},
114 {"c:\\windows\\system.ini", "win32", "WIN32", sys_win32dlc},
115 {"c:\\windows\\win.ini", "win32", "WIN32", sys_win32dlc},
116 {"c:\\windows\\notepad.exe", "win32", "WIN32", sys_win32dlc},
117 {NULL, NULL, NULL, NULL}
118 } ;
119
120 static int match(const char *regex, const char *str)
121 {
122 re_comp(regex);
123 return re_exec(str);
124 }
125
126 /* match uname against each pattern on the list; on a match, put() the portion
127 of the string matched in node and return 1 */
128 int uname_guess(const char *node, const char *uname, const char *list[])
129 {
130 const char **l;
131 if (uname == NULL)
132 return 0;
133 for(l = list; *l != NULL; l++) {
134 if (match(*l, uname)) {
135 char *s;
136 int len = eopat[0] - bopat[0];
137 s = malloc(len+1);
138 memcpy(s, bopat[0], len);
139 s[len] = '\0';
140 put(node, s);
141 return 1;
142 }
143 }
144 return 0;
145 }
146
147 /* Don't worry about linear search or matching regexes all the time - this
148 function will be run at most two times */
149 static callback_t lookup_uname(char **uname, const char **name, const char **class)
150 {
151 uname_t *u;
152 for(u = unames; u->uname_regex != NULL; u++) {
153 if (
154 ((*uname != NULL) && (match(u->uname_regex, *uname))) /* uname match */
155 || ((*name != NULL) && ((strcmp(u->name, *name) == 0))) /* name match */
156 || ((*class != NULL) && ((strcmp(u->class, *class) == 0))) /* class match */
157 ) {
158 if (*name == NULL) *name = u->name;
159 if (*class == NULL) *class = u->class;
160 return u->callback;
161 }
162 }
163 return NULL;
164 }
165
166 static callback_t lookup_magic_file(int logdepth, const char **name, const char **class)
167 {
168 magic_file_t *u;
169 for(u = magic_files; u->file_name != NULL; u++) {
170 if (is_file(u->file_name)) {
171 logprintf(logdepth, "%s -> %s\n", u->file_name, u->class);
172
173 if (*name == NULL) *name = u->name;
174 if (*class == NULL) *class = u->class;
175 return u->callback;
176 }
177 }
178 return NULL;
179 }
180
181 int find_uname(const char *rname, int logdepth, int fatal)
182 {
183 const char *name, *class, *tname, *uname_orig;
184 char *s, *uname, *mname, *sname;
185 void (*callback)(void);
186
187 require("sys/tmp", logdepth, fatal);
188
189 if (istarget(db_cwd))
190 require("/target/sys/target", logdepth, fatal);
191
192 report("Checking for system type... ");
193 logprintf(logdepth, "[find_uname] checking for sys/name\n");
194 logdepth++;
195
196 tname = get("/arg/sys/target-name");
197 if (istarget(db_cwd) && (tname != NULL))
198 put("sys/name", tname);
199
200 tname = get("/arg/sys/target-uname");
201 if (istarget(db_cwd) && (tname != NULL))
202 put("sys/uname", tname);
203
204 name = get("sys/name");
205 uname_orig = get("sys/uname");
206
207 if (name == NULL) {
208 if (uname_orig == NULL) {
209 logprintf(logdepth, "not set, running\n");
210 run_shell(logdepth, "uname -a", (char **)&uname);
211 if (uname != NULL) {
212 for(s = uname; *s != '\0'; s++)
213 if ((*s == '\n') || (*s == '\r')) *s = ' ';
214 put("sys/uname", uname);
215 }
216 else
217 put("sys/uname", "");
218
219 if (run_shell(logdepth, "uname -m", (char **)&mname) == 0)
220 put("sys/machine_name", strip(mname));
221 else
222 put("sys/machine_name", NULL);
223
224 if (mname != NULL)
225 free(mname);
226
227 if (run_shell(logdepth, "uname -o", (char **)&sname) == 0)
228 put("sys/system_name", strip(sname));
229 else if (run_shell(logdepth, "uname -s", (char **)&sname) == 0)
230 put("sys/system_name", strip(sname));
231 else
232 put("sys/system_name", NULL);
233 if (sname != NULL)
234 free(sname);
235 }
236
237 /* we have uname by now, set sys/name */
238 name = NULL;
239 class = NULL;
240 callback = lookup_uname(&uname, &name, &class);
241 if (name == NULL) {
242 /* no uname or unknown system by uname - fallback: check for cross target */
243 const char *target = get("/arg/sys/target");
244 if ((target != NULL) && (strstr(target, "mingw") != NULL)) {
245 name = "WIN32";
246 report("(detected mingw cross compilation to WIN32)\n");
247 }
248 else {
249 report("Warning: unknown system\n");
250 name = "unknown";
251 }
252 }
253 put("sys/name", name);
254 }
255 else {
256 /* we had sys/name, that should be enough */
257 uname = NULL;
258 class = name;
259 callback = lookup_uname(&uname, &name, &class);
260 }
261
262 /* predefined and/or detected uname failed, try magic file method */
263 if (callback == NULL) {
264 logprintf(logdepth, "System class is unknown by uname, running heuristics...\n");
265 report("System class is unknown by uname, running heuristics... ");
266
267 callback = lookup_magic_file(logdepth + 1, &name, &class);
268 }
269
270
271 if (callback == NULL) {
272 /* System unknown. */
273 error("Unknown system '%s'\n", get("sys/uname"));
274 abort();
275 }
276
277 callback();
278 report("OK (name: %s; class: %s)\n", name, class);
279 put("sys/class", class);
280
281 /* fallbacks */
282 if (get("sys/machine_name") == NULL)
283 uname_guess("sys/machine_name", uname, machine_names);
284
285 if (get("sys/system_name") == NULL)
286 uname_guess("sys/system_name", uname, system_names);
287
288 /* on windows, overwrite the path sep with the right amount of \ (the tmp finder may have left / in it) */
289 if (strcmp(class, "WIN32") == 0) {
290 int eats = istrue(get("sys/shell_eats_backslash"));
291
292 if (eats)
293 put("sys/path_sep", "\\\\\\\\");
294 else
295 put("sys/path_sep", "\\");
296 }
297
298 return 0;
299 }
300
301 static int find_triplet_(const char *name, int logdepth, int fatal, const char *nodename, int include_vendor, char *sep, char *esc)
302 {
303 const char *machine, *vendor, *os;
304 char *triplet, *s;
305 char fake_sep[2];
306
307 fake_sep[0] = 1;
308 fake_sep[1] = 0;
309
310 require("sys/uname", logdepth, fatal);
311
312 machine = get("sys/machine_name");
313 if (machine == NULL)
314 machine = "unknown";
315
316 vendor = "unknown";
317
318 os = get("sys/system_name");
319 if (os == NULL)
320 os = "unknown";
321
322 if (include_vendor)
323 triplet = str_concat(fake_sep, machine, vendor, os, NULL);
324 else
325 triplet = str_concat(fake_sep, machine, os, NULL);
326
327 for(s = triplet; *s != '\0'; s++) {
328 if ((esc != NULL) && (*s == *sep))
329 *s = *esc;
330 if (isalnum(*s))
331 *s = tolower(*s);
332 else {
333 if (*s == *fake_sep)
334 *s = *sep;
335 else if (esc != NULL)
336 *s = *esc;
337 else
338 *s = '-';
339 }
340 }
341 put(nodename, triplet);
342 free(triplet);
343 return 0;
344 }
345
346 int find_triplet(const char *name, int logdepth, int fatal)
347 {
348 return find_triplet_(name, logdepth, fatal, "sys/triplet", 1, "-", NULL);
349 }
350
351 int find_sysid(const char *name, int logdepth, int fatal)
352 {
353 return find_triplet_(name, logdepth, fatal, "sys/sysid", 0, "-", "_");
354 }
0 /* Runs when a custom command line argument is found
1 returns true if no further argument processing should be done */
2 int hook_custom_arg(const char *key, const char *value);
3
4 /* If any of the int hooks return non-zero, that means failure and stops
5 the whole process */
6
7 /* Runs before anything else */
8 int hook_preinit(void);
9
10 /* Runs after initialization */
11 int hook_postinit(void);
12
13 /* Runs after all arguments are read and parsed */
14 int hook_postarg(void);
15
16 /* Runs when things should be detected for the host system (tools compiled for and/or run on compilation host) */
17 int hook_detect_host(void);
18
19 /* Runs when things should be detected for the target system (tools compiled on the compilation host but running on the target)*/
20 int hook_detect_target(void);
21
22 /* Runs when things should be detected for the runtime system (tools that will run only on the target, production runtime, not during compilation or installation) */
23 int hook_detect_runtime(void);
24
25 /* Runs after detection hooks, should generate the output (Makefiles, etc.) */
26 int hook_generate(void);
27
28 /* Runs before everything is uninitialized */
29 void hook_preuninit(void);
30
31 /* Runs at the very end, when everything is already uninitialized */
32 void hook_postuninit(void);
0 /*
1 scconfig - hash tables
2 Copyright (C) 2007, 2008, 2009 by Szabolcs Nagy
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <assert.h>
27 #include "libs.h"
28 #include "ht.h"
29
30 #define HT_MINSIZE 8
31 #define HT_MAXSIZE ((UINT_MAX >> 1U) + 1U)
32
33 #define JUMP(i, j) i += j++
34 #define JUMP_FIRST(i, j) j = 1, i += j++
35
36 /* portable str hash */
37 #define HASH_INIT 0xbabeface
38 static unsigned int keyhash(const char *key) {
39 unsigned int a = HASH_INIT;
40
41 while (*key)
42 a += (a << 5) + *key++;
43 return a;
44 }
45
46 /* fill threshold = 3/4 */
47 #define HT_LOG_THRES 2
48 static void checkfill(ht_t *ht)
49 {
50 if (ht->fill > ht->mask - (ht->mask >> HT_LOG_THRES) || ht->fill > ht->used << 2)
51 ht_resize(ht, ht->used << (ht->used > 1U << 15 ? 1 : 2));
52 }
53
54 static ht_t *ht_init(ht_t *ht, int isstr)
55 {
56 ht->mask = HT_MINSIZE - 1;
57 ht->fill = 0;
58 ht->used = 0;
59 ht->isstr = isstr;
60 ht->table = calloc(ht->mask + 1, sizeof(ht_entry_t));
61 ht->refcount = 1;
62 return ht;
63 }
64
65 static ht_t *ht_uninit(ht_t *ht)
66 {
67 ht_entry_t *entry;
68
69 for (entry = ht->table; entry != ht->table + ht->mask + 1; entry++)
70 if (ht_isused(entry)) {
71 if (ht->isstr)
72 free(entry->value);
73 free(entry->key);
74 }
75 free(ht->table);
76 return ht;
77 }
78
79 ht_t *ht_alloc(int isstr)
80 {
81 ht_t *ht;
82
83 ht = malloc(sizeof(ht_t));
84 return ht_init(ht, isstr);
85 }
86
87 void ht_free(ht_t *ht)
88 {
89 ht_uninit(ht);
90 free(ht);
91 }
92
93 ht_t *ht_clear(ht_t *ht)
94 {
95 ht_uninit(ht);
96 return ht_init(ht, ht->isstr);
97 }
98
99 /* one lookup function to rule them all */
100 static ht_entry_t *ht_lookup(ht_t *ht, const char *key, unsigned int hash)
101 {
102 unsigned int mask;
103 unsigned int i;
104 unsigned int j;
105 ht_entry_t *table;
106 ht_entry_t *entry;
107 ht_entry_t *free_entry;
108
109 mask = ht->mask;
110 i = hash;
111 table = ht->table;
112 assert(ht->table);
113 entry = table + (i & mask);
114 if (ht_isempty(entry) || !strcmp(entry->key, key))
115 return entry;
116 /* free_entry: first deleted entry for insert */
117 free_entry = ht_isdeleted(entry) ? entry : NULL;
118 assert(ht->fill <= ht->mask);
119 for (JUMP_FIRST(i, j); ; JUMP(i, j)) {
120 entry = table + (i & mask);
121 if (ht_isempty(entry))
122 return (free_entry == NULL) ? entry : free_entry;
123 if (entry->hash == hash && !strcmp(entry->key, key))
124 return entry;
125 if (ht_isdeleted(entry) && free_entry == NULL)
126 free_entry = entry;
127 }
128 }
129
130 /* for resize: no deleted entries in ht, entry->key is not in ht, no strdup */
131 static void cleaninsert(ht_t *ht, const ht_entry_t *entry)
132 {
133 unsigned int i;
134 unsigned int j;
135 ht_entry_t *newentry;
136
137 i = entry->hash;
138 newentry = ht->table + (i & ht->mask);
139 if (!ht_isempty(newentry))
140 for (JUMP_FIRST(i, j); !ht_isempty(newentry); JUMP(i, j))
141 newentry = ht->table + (i & ht->mask);
142 ++ht->fill;
143 ++ht->used;
144 memcpy(newentry, entry, sizeof(ht_entry_t));
145 }
146
147 ht_t *ht_resize(ht_t *ht, unsigned int hint)
148 {
149 unsigned int newsize;
150 unsigned int oldused;
151 ht_entry_t *oldtable, *newtable, *entry;
152
153 oldused = ht->used;
154 if (hint < oldused << 1)
155 hint = oldused << 1;
156 assert(hint <= HT_MAXSIZE && hint > oldused);
157 for (newsize = HT_MINSIZE; newsize < hint; newsize <<= 1);
158 newtable = calloc(newsize, sizeof(ht_entry_t));
159 oldtable = ht->table;
160 ht->mask = newsize - 1;
161 ht->fill = 0;
162 ht->used = 0;
163 ht->table = newtable;
164 for (entry = oldtable; oldused > 0; ++entry)
165 if (ht_isused(entry)) {
166 --oldused;
167 cleaninsert(ht, entry);
168 }
169 free(oldtable);
170 return ht;
171 }
172
173 void *ht_get(ht_t *ht, const char *key)
174 {
175 ht_entry_t *entry;
176
177 entry = ht_lookup(ht, key, keyhash(key));
178 return ht_isused(entry) ? entry->value : NULL;
179 }
180
181 void *ht_insert(ht_t *ht, const char *key, void *value)
182 {
183 unsigned int hash;
184 ht_entry_t *entry;
185
186 hash = keyhash(key);
187 entry = ht_lookup(ht, key, hash);
188 if (ht_isused(entry))
189 return entry->value;
190 if (ht_isempty(entry))
191 ++ht->fill;
192 ++ht->used;
193 entry->hash = hash;
194 entry->key = strclone(key);
195 entry->value = ht->isstr ? strclone(value) : value;
196 checkfill(ht);
197 return NULL;
198 }
199
200 const char *ht_set(ht_t *ht, const char *key, void *value)
201 {
202 unsigned int hash;
203 ht_entry_t *entry;
204 char *k;
205
206 hash = keyhash(key);
207 entry = ht_lookup(ht, key, hash);
208 if (ht_isused(entry)) {
209 if (ht->isstr) {
210 free(entry->value);
211 entry->value = strclone(value);
212 } else
213 entry->value = value;
214 return entry->key;
215 }
216 if (ht_isempty(entry))
217 ++ht->fill;
218 ++ht->used;
219 entry->hash = hash;
220 entry->key = k = strclone(key);
221 entry->value = ht->isstr ? strclone(value) : value;
222 checkfill(ht);
223 return k;
224 }
225
226 const char *ht_del(ht_t *ht, const char *key)
227 {
228 ht_entry_t *entry;
229
230 entry = ht_lookup(ht, key, keyhash(key));
231 if (!ht_isused(entry))
232 return NULL;
233 --ht->used;
234 free(entry->key);
235 if (ht->isstr)
236 free(entry->value);
237 entry->key = ht_deleted_key;
238 return ht_deleted_key;
239 }
240
241 ht_entry_t *ht_first(const ht_t *ht)
242 {
243 ht_entry_t *entry = 0;
244
245 if (ht->used)
246 for (entry = ht->table; !ht_isused(entry); ++entry);
247 return entry;
248 }
249
250 ht_entry_t *ht_next(const ht_t *ht, ht_entry_t *entry)
251 {
252 while (++entry != ht->table + ht->mask + 1)
253 if (ht_isused(entry))
254 return entry;
255 return 0;
256 }
0 #ifndef STR_HT_H
1 #define STR_HT_H
2
3 /* char * -> void * open addressing hashtable */
4 /* keys and values are strdupped (strcloned) */
5
6 #define ht_deleted_key ((char *)1)
7 #define ht_isused(e) ((e)->key && (e)->key != ht_deleted_key)
8 #define ht_isempty(e) (((e)->key == NULL) || (e)->key == ht_deleted_key)
9 #define ht_isdeleted(e) ((e)->key == ht_deleted_key)
10
11 typedef struct {
12 unsigned int hash;
13 char *key;
14 void *value;
15 } ht_entry_t;
16
17 typedef struct {
18 unsigned int mask;
19 unsigned int fill;
20 unsigned int used;
21 int isstr;
22 ht_entry_t *table;
23 int refcount;
24 } ht_t;
25
26 ht_t *ht_alloc(int isstr);
27 void ht_free(ht_t *ht);
28 ht_t *ht_clear(ht_t *ht);
29 ht_t *ht_resize(ht_t *ht, unsigned int hint);
30
31 /* value of ht[key], NULL if key is empty or deleted */
32 void *ht_get(ht_t *ht, const char *key);
33 /* ht[key] = value and return NULL or return ht[key] if key is already used */
34 void *ht_insert(ht_t *ht, const char *key, void *value);
35 /* ht[key] = value and return a pointer to the strdupped key */
36 const char *ht_set(ht_t *ht, const char *key, void *value);
37 /* delete key and return ht_deleted_key or NULL if key was not used */
38 const char *ht_del(ht_t *ht, const char *key);
39
40 /* iteration */
41 #define foreach(ht, e) \
42 for (e = (ht)->table; e != (ht)->table + (ht)->mask + 1; e++) \
43 if (ht_isused(e))
44
45 /* first used (useful for iteration) NULL if empty */
46 ht_entry_t *ht_first(const ht_t *ht);
47 /* next used (useful for iteration) NULL if there is no more used */
48 ht_entry_t *ht_next(const ht_t *ht, ht_entry_t *entry);
49
50 #endif
0 /*
1 scconfig - library functions for compiling and running test code
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <assert.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include "log.h"
29 #include "libs.h"
30 #include "db.h"
31 #include "dep.h"
32
33 /*
34 #define KEEP_TEST_SRCS
35 */
36
37 int cross_blind = 0;
38
39
40 static char *clone_flags(const char *input, const char *node)
41 {
42 char *output;
43 const char *s;
44 int len;
45
46 if (input != NULL) {
47 if (*input == '+') {
48 s = get(node);
49 if (s != NULL) {
50 len = strlen(s);
51 output = malloc(len + strlen(input) + 4);
52 memcpy(output, s, len);
53 output[len] = ' ';
54 strcpy(output + len + 1, input + 1);
55 }
56 else
57 output = strclone(input);
58 }
59 else
60 output = strclone(input);
61 }
62 else {
63 s = get(node);
64 if (s != NULL)
65 output = strclone(s);
66 else
67 output = strclone("");
68 }
69 return output;
70 }
71
72 int compile_file_raw(int logdepth, const char *fn_input, char **fn_output, const char *cc, const char *cflags, const char *ldflags)
73 {
74 char cmd[2048];
75 char *cc_esc, *fn_input_esc, *fn_output_esc, *temp_out_esc, *temp_out;
76 int ret;
77
78 temp_out = tempfile_new(".out");
79
80 if (*fn_output == NULL)
81 *fn_output = tempfile_new(get("sys/ext_exe"));
82 else
83 *fn_output = tempfile_new(*fn_output);
84 unlink(*fn_output);
85
86 cc_esc = shell_escape_dup(cc == NULL ? get("cc/cc") : cc);
87 fn_input_esc = shell_escape_dup(fn_input);
88 fn_output_esc = shell_escape_dup(*fn_output);
89 temp_out_esc = shell_escape_dup(temp_out);
90
91 sprintf(cmd, "%s \"%s %s %s %s -o %s 2>&1\" >%s", get("/host/sys/shell"), cc_esc, cflags, fn_input_esc, ldflags, fn_output_esc, temp_out_esc);
92
93 free(cc_esc);
94 free(fn_input_esc);
95 free(fn_output_esc);
96 free(temp_out_esc);
97
98 logprintf(logdepth, "compile: '%s'\n", cmd);
99 ret = system(cmd);
100 log_merge(logdepth + 1, temp_out);
101 #ifndef KEEP_TEST_SRCS
102 unlink(temp_out);
103 #endif
104 free(temp_out);
105 logprintf(logdepth, "compile result: %d\n", ret);
106
107 return ret;
108 }
109
110 int compile_file(int logdepth, const char *fn_input, char **fn_output, const char *cc, const char *cflags, const char *ldflags)
111 {
112 int ret;
113 char *ldflags_, *cflags_;
114
115 cflags_ = clone_flags(cflags, "cc/cflags");
116 ldflags_ = clone_flags(ldflags, "cc/ldflags");
117
118 ret = compile_file_raw(logdepth, fn_input, fn_output, cc, cflags_, ldflags_);
119
120 free(cflags_);
121 free(ldflags_);
122
123 return ret;
124 }
125
126 int compile_code(int logdepth, const char *testcode, char **fn_output, const char *cc, const char *cflags, const char *ldflags)
127 {
128 char *temp_in;
129 int ret;
130
131 require("sys/ext_exe", logdepth, 1);
132
133 assert(testcode != NULL);
134 assert(fn_output != NULL);
135
136 temp_in = tempfile_dump(testcode, ".c");
137 ret = compile_file(logdepth, temp_in, fn_output, cc, cflags, ldflags);
138 #ifndef KEEP_TEST_SRCS
139 unlink(temp_in);
140 #endif
141 free(temp_in);
142
143 return ret;
144 }
145
146 int compile_code_raw(int logdepth, const char *testcode, char **fn_output, const char *cc, const char *cflags, const char *ldflags)
147 {
148 char *temp_in;
149 int ret;
150
151 require("sys/ext_exe", logdepth, 1);
152
153 assert(testcode != NULL);
154 assert(fn_output != NULL);
155
156 temp_in = tempfile_dump(testcode, ".c");
157 ret = compile_file_raw(logdepth, temp_in, fn_output, cc, cflags, ldflags);
158 #ifndef KEEP_TEST_SRCS
159 unlink(temp_in);
160 #endif
161 free(temp_in);
162
163 return ret;
164 }
165
166 char *shell_escape_dup(const char *in)
167 {
168 char *o, *out;
169 const char *i;
170 const char *esc = get("sys/shell_escape_char");
171
172 /* in the early phase, before detecting the shell, this happens */
173 if (esc == NULL)
174 return strclone(in);
175
176 out = malloc(strlen(in)*2+1);
177 for(i = in, o = out; *i != '\0'; i++) {
178 if (*i == *esc) {
179 *o++ = *esc;
180 }
181 else if (!isalnum(*i)) {
182 switch(*i) {
183 case '/':
184 case '_':
185 case '-':
186 case '.':
187 break;
188 default:
189 *o++ = *esc;
190 }
191 }
192 *o++ = *i;
193 }
194 *o = '\0';
195 return out;
196 }
197
198 int run(int logdepth, const char *cmd_, char **stdout_saved)
199 {
200 char *cmd;
201 char *fn_out, *temp_out;
202 char *fn_out_esc, *temp_out_esc;
203 int ret;
204 const char *emu;
205
206 assert(cmd_ != NULL);
207
208 /* blind cross compiling mode means we always assume success */
209 if (cross_blind) {
210 if (stdout_saved != NULL)
211 *stdout_saved = NULL;
212 return 0;
213 }
214
215 emu = get("sys/emu");
216
217 /* emu == NULL means we need an emulator but we don't have one and
218 we should pretend everything went well (and of course can't provide
219 output.) */
220 if (emu == NULL) {
221 if (stdout_saved != NULL)
222 *stdout_saved = NULL;
223 return 0;
224 }
225
226 /* emu == false means we need an emulator and we don't want to pretend -> fatal */
227 if (strcmp(emu, sfalse) == 0) {
228 error("Trying to run unavailable emulator (db_cwd='%s')\n", db_cwd);
229 abort();
230 }
231
232 temp_out = tempfile_new(".out");
233 fn_out = tempfile_new("");
234
235 temp_out_esc = shell_escape_dup(temp_out);
236 fn_out_esc = shell_escape_dup(fn_out);
237 cmd = malloc(strlen(emu) + strlen(cmd_) + strlen(fn_out_esc) + strlen(temp_out_esc) + 32);
238 sprintf(cmd, "%s %s >%s 2>>%s", emu, cmd_, fn_out_esc, temp_out_esc);
239 free(temp_out_esc);
240 free(fn_out_esc);
241
242 logprintf(logdepth, "run: '%s'\n", cmd);
243 ret = system(cmd);
244 log_merge(logdepth + 1, temp_out);
245 unlink(temp_out);
246 free(temp_out);
247 logprintf(logdepth, "run result: %d\n", ret);
248 free(cmd);
249
250 if (stdout_saved != NULL) {
251 if (ret == 0) {
252 *stdout_saved = load_file(fn_out);
253 logprintf(logdepth, "stdout: '%s'\n", *stdout_saved);
254 }
255 else
256 *stdout_saved = NULL;
257 }
258
259 unlink(fn_out);
260 free(fn_out);
261 return ret;
262 }
263
264 int run_shell(int logdepth, const char *cmd_, char **stdout_saved)
265 {
266 int ret;
267 char *cmd, *cmd_esc;
268 const char *emu;
269 const char *shell;
270
271 emu = get("sys/emulator");
272 if (emu == NULL)
273 emu = "";
274
275 shell = get("sys/shell");
276 if (shell == NULL) {
277 error("No shell was specified (db_cwd='%s')\n", db_cwd);
278 abort();
279 }
280
281 cmd_esc = shell_escape_dup(cmd_);
282 cmd = malloc(strlen(emu) + strlen(shell) + strlen(cmd_esc) + 16);
283 if (istrue(get("sys/shell_needs_quote")))
284 sprintf(cmd, "%s %s \"%s\"", emu, shell, cmd_);
285 else
286 sprintf(cmd, "%s %s %s", emu, shell, cmd_);
287 free(cmd_esc);
288
289 ret = run(logdepth, cmd, stdout_saved);
290 free(cmd);
291 return ret;
292 }
293
294
295 int compile_run(int logdepth, const char *testcode, const char *cc, const char *cflags, const char *ldflags, char **stdout_saved)
296 {
297 int ret;
298 char *fn_output = NULL;
299
300 ret = compile_code(logdepth+1, testcode, &fn_output, cc, cflags, ldflags);
301
302 if (ret == 0) {
303 char *fn_output_esc = shell_escape_dup(fn_output);
304 ret = run(logdepth+1, fn_output_esc, stdout_saved);
305 free(fn_output_esc);
306 }
307
308 if (fn_output != NULL) {
309 unlink(fn_output);
310 free(fn_output);
311 }
312 return ret;
313 }
314
315 int run_script(int logdepth, const char *interpreter, const char *script, const char *suffix, char **out)
316 {
317 char *temp, *cmd;
318 int res;
319
320 temp = tempfile_dump(script, suffix);
321 cmd = malloc(strlen(temp) + strlen(interpreter) + 4);
322 sprintf(cmd, "%s %s", interpreter, temp);
323
324 res = run(logdepth, cmd, out);
325
326 unlink(temp);
327 free(temp);
328 free(cmd);
329 return res;
330 }
331
0 /*
1 scconfig - library to query files and directories
2 Copyright (C) 2009..2012 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include "db.h"
28 #include "libs.h"
29 #include "log.h"
30 #include "dep.h"
31
32 int file_size(const char *name)
33 {
34 struct stat buf;
35 if (stat(name, &buf) != 0)
36 return -1;
37 return buf.st_size;
38 }
39
40 char *tempdir_new(int logdepth, const char *suffix)
41 {
42 char s[1024];
43 char *cmd;
44 const char *tmp;
45 const char *mkdir, *emu;
46 unsigned int rn, n;
47
48 require("sys/tmp", logdepth+1, 1);
49 tmp = get("sys/tmp");
50
51 if (strlen(suffix) > sizeof(s) - strlen(tmp) - 32) {
52 fprintf(stderr, "Not enough room for creating temporary file name\n");
53 abort();
54 }
55
56 require("fstools/mkdir", logdepth+1, 1);
57 mkdir = get("fstools/mkdir");
58
59 emu = get("sys/emu");
60 if (emu == NULL)
61 emu = "";
62
63 for(n = 0; n < 128; n++) {
64 rn = rand() % 100000;
65 sprintf(s, "%sscc_%u%s", tmp, rn, suffix);
66 if (!exists(s)) {
67 char *s_esc = shell_escape_dup(s);
68 cmd = malloc(strlen(s_esc) + strlen(mkdir) + 16);
69 sprintf(cmd, "%s %s", mkdir, s_esc);
70 run_shell(logdepth+1, cmd, NULL);
71 free(s_esc);
72 free(cmd);
73 if (is_dir(s))
74 return strclone(s);
75 }
76 }
77 error("Couldn't find a suitable temp dir name\n");
78 abort();
79 }
80
81 char *tempfile_new_noabort(const char *suffix)
82 {
83 char s[1024];
84 const char *tmp;
85 unsigned int rn, n;
86 FILE *f;
87
88
89 require("/host/sys/tmp", 0, 1);
90 tmp = get("/host/sys/tmp");
91 if (strlen(suffix) > sizeof(s) - strlen(tmp) - 32) {
92 fprintf(stderr, "tempfile_new_noabort(): not enough room for creating temporary file name\n");
93 abort();
94 }
95
96 for(n = 0; n < 128; n++) {
97 rn = rand() % 100000;
98 sprintf(s, "%sscc_%u%s", tmp, rn, suffix);
99 if (!is_file(s)) { /* can not test for exists() because that would recurse is_dir */
100 f = fopen(s, "w");
101 if (f != NULL) {
102 fclose(f);
103 return strclone(s);
104 }
105 }
106 }
107 return NULL;
108 }
109
110 char *tempfile_new(const char *suffix)
111 {
112 char *tmp;
113
114 tmp = tempfile_new_noabort(suffix);
115 if (tmp == NULL) {
116 error("Couldn't find a suitable temp file name\n");
117 abort();
118 }
119 return tmp;
120 }
121
122 char *tempfile_dump(const char *testcode, const char *suffix)
123 {
124 char *fn;
125 FILE *f;
126
127 fn = tempfile_new(suffix);
128 f = fopen(fn, "w");
129 fprintf(f, "%s", testcode);
130 fclose(f);
131 return fn;
132 }
133
134 char *load_file(const char *name)
135 {
136 int size;
137 char *content;
138 FILE *f;
139
140 size = file_size(name);
141 if (size > 0) {
142 content = malloc(size+1);
143 *content = '\0';
144 f = fopen(name, "r");
145 if (f != NULL) {
146 int len = fread(content, 1, size, f);
147 if (len < 0)
148 len = 0;
149 content[len] = '\0';
150 fclose(f);
151 }
152 }
153 else {
154 content = malloc(1);
155 *content = '\0';
156 }
157 return content;
158 }
159
160 int is_dir(const char *path)
161 {
162 char *tmp, *path_esc;
163 int ret;
164
165 require("sys/shell", 0, 1);
166
167 path_esc = shell_escape_dup(path);
168 tmp = malloc(strlen(path_esc) + 16);
169 sprintf(tmp, "cd %s", path_esc);
170 ret = run_shell(0, tmp, NULL);
171 free(tmp);
172 free(path_esc);
173 return !ret;
174 }
175
176 int is_file(const char *path)
177 {
178 return file_size(path) >= 0;
179 }
180
181 int exists(const char *path)
182 {
183 return is_file(path) || is_dir(path);
184 }
185
186
187 int exists_in(const char *dir, const char *file)
188 {
189 char *path;
190 int ret;
191
192 path = malloc(strlen(dir) + strlen(file) + 5);
193 sprintf(path, "%s/%s", dir, file);
194 ret = is_file(path) || is_dir(path);
195 free(path);
196 return ret;
197 }
198
199 const char *file_name_ptr(const char *path)
200 {
201 const char *s;
202 s = str_rchr((char *)path, '/');
203 if (s == NULL)
204 s = str_rchr((char *)path, '\\');
205 return s;
206 }
207
208 char *file_name(const char *path)
209 {
210 const char *s;
211 s = file_name_ptr(path);
212 if (s == NULL)
213 return strclone(path);
214 s++;
215 return strclone(s);
216 }
217
218 char *dir_name(const char *path)
219 {
220 char *s, *r;
221 s = strclone(path);
222 r = (char *)file_name_ptr(s);
223 if (r == NULL) {
224 free(s);
225 return strclone("");
226 }
227 *r = '\0';
228 return s;
229 }
230
231 int touch_file(const char *path)
232 {
233 FILE *f;
234 f = fopen(path, "a");
235 if (f == NULL)
236 return -1;
237 fclose(f);
238 return 0;
239 }
0 /*
1 scconfig - library for listing files in a directory
2 Copyright (C) 2009..2012 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "db.h"
26 #include "libs.h"
27 #include "log.h"
28 #include "dep.h"
29
30 static void destroy_testdir(int logdepth, char *dir)
31 {
32 const char *rm;
33 char *cmd, *dir_esc;
34
35 rm = get("fstools/rm");
36 if (rm == NULL) {
37 logprintf(logdepth, "CAN NOT delete test directory '%s': no rm available\n", dir);
38 return;
39 }
40
41 if (dir == NULL)
42 return;
43
44 logprintf(logdepth, "deleting test directory '%s'\n", dir);
45
46 cmd = malloc(strlen(dir) + strlen(rm) + 4);
47 dir_esc = shell_escape_dup(dir);
48 sprintf(cmd, "%s %s", rm, dir_esc);
49 run_shell(0, cmd, NULL);
50 free(cmd);
51 free(dir);
52 free(dir_esc);
53 }
54
55 static char *create_testdir(int logdepth)
56 {
57 char *dir, *fn, *cmd;
58 const char *mkdir;
59 int n;
60 logprintf(logdepth, "creating test directory\n");
61
62 dir = tempdir_new(logdepth+1, "");
63 logprintf(logdepth, "sandbox is: '%s'\n", dir);
64
65 fn = malloc(strlen(dir) + 32);
66 for(n = 0; n < 2; n++) {
67 FILE *f;
68 sprintf(fn, "%s%sfile%d", dir, get("sys/path_sep"), n+1);
69 f = fopen(fn, "w");
70 if (f != NULL) {
71 fclose(f);
72 if (!is_file(fn)) {
73 logprintf(logdepth, "Can not create file %s\n", fn);
74 free(fn);
75 destroy_testdir(logdepth, dir);
76 return NULL;
77 }
78 }
79 }
80
81 mkdir = get("fstools/mkdir");
82
83 cmd = malloc(strlen(dir) + 64);
84 for(n = 0; n < 2; n++) {
85 char *fn_esc;
86 sprintf(fn, "%s%sdir%d", dir, get("sys/path_sep"), n+1);
87 fn_esc = shell_escape_dup(fn);
88 sprintf(cmd, "%s %s", mkdir, fn_esc);
89 free(fn_esc);
90 if (run_shell(logdepth+1, cmd, NULL) || (!is_dir(fn))) {
91 logprintf(logdepth, "Can not create directory %s\n", fn);
92 free(fn);
93 free(cmd);
94 destroy_testdir(logdepth, dir);
95 return NULL;
96 }
97 }
98 free(cmd);
99 free(fn);
100 return dir;
101 }
102
103 static int test(int logdepth, int argc, char *argv[])
104 {
105 int dir[2], file[2], n;
106 int *arr, idx;
107
108 for(n = 0; n < 2; n++) {
109 dir[n] = 0;
110 file[n] = 0;
111 }
112
113 /* count the list of files, increase arrays by hit */
114 for(n = 0; n < argc; n++) {
115 arr = NULL;
116 if (strncmp(argv[n], "dir", 3) == 0) { arr = dir; idx = atoi(argv[n]+3); }
117 if (strncmp(argv[n], "file", 4) == 0) { arr = file; idx = atoi(argv[n]+4); }
118 if (arr == NULL) {
119 logprintf(logdepth, "test fails: unknown existing file on the list: '%s'\n", argv[n]);
120 return 0;
121 }
122 idx--;
123 if ((idx < 0) || (idx > 1)) {
124 logprintf(logdepth, "test fails: file name changed: '%s'\n", argv[n]);
125 return 0;
126 }
127 arr[idx]++;
128 }
129
130 /* check if every item was found exactly once */
131 for(n = 0; n < 2; n++) {
132 if ((dir[n] != 1) || (file[n] != 1)) {
133 logprintf(logdepth, "test fails: %s%d not found \n", dir[n] ? "file" : "dir", n);
134 return 0;
135 }
136 }
137
138 return 1;
139 }
140
141 static void filelist_extract(char *out, const char *dir, const char *method, int *argc, char ***argv)
142 {
143 char *s, sep, *start, *end;
144 int len, allocated = 0, count = 0;
145 char **arr = NULL;
146 const char *psep;
147
148 psep = get("sys/path_sep");
149
150 len = strlen(dir);
151
152 /* uniform separator */
153 if (*method == 'w') {
154 /* if word splitting then convert newlines to spaces and convert tabs to spaces */
155 for(s = out; *s != '\0'; s++) {
156 if ((*s == '\n') || (*s == '\r') || (*s == '\t'))
157 *s = ' ';
158 }
159 sep = ' ';
160 }
161 else {
162 for(s = out; *s != '\0'; s++) {
163 if (*s == '\r')
164 *s = '\n';
165 }
166 sep = '\n';
167 }
168
169 start = out;
170 while((s = str_chr(start, sep)) != NULL) {
171 *s = '\0';
172 if (strncmp(dir, start, len) == 0)
173 start += len;
174 while(*start == *psep)
175 start++;
176
177 if (*start != '\0') {
178 end = str_chr(start, *psep);
179 if (end != NULL)
180 *end = '\0';
181
182 /* add only if not the same as previous and exists */
183 if ((!((count > 0) && (strcmp(arr[count - 1], start) == 0))) && (exists_in(dir, start))) {
184
185 if (count >= allocated) {
186 allocated = count + 32;
187 arr = realloc(arr, sizeof(char *) * allocated);
188 }
189 arr[count] = strclone(start);
190 count++;
191 }
192 }
193
194 start = s+1;
195 while(*start == sep) start++;
196 }
197 *argc = count;
198 *argv = arr;
199 }
200
201 void filelist_free(int *argc, char ***argv)
202 {
203 int n;
204
205 if (*argv == NULL)
206 return;
207
208 for(n = 0; n < *argc; n++)
209 free((*argv)[n]);
210 free(*argv);
211 *argc = 0;
212 }
213
214 static char *filelist_asmcmd(const char *dir, const char *list_cmd)
215 {
216 char *cmd;
217
218 cmd = malloc(strlen(dir) + strlen(list_cmd) + 32);
219 sprintf(cmd, list_cmd, dir);
220 return cmd;
221 }
222
223 static int try(int logdepth, const char *dir, const char *list_cmd, const char *method)
224 {
225 char *cmd, *out, *dir_esc;
226 int argc, res;
227 char **argv;
228
229 dir_esc = shell_escape_dup(dir);
230 cmd = filelist_asmcmd(dir_esc, list_cmd);
231 free(dir_esc);
232 logprintf(logdepth, "trying '%s'...\n", cmd);
233
234 run_shell(logdepth+1, cmd, &out);
235 if (out != NULL) {
236 filelist_extract(out, dir, method, &argc, &argv);
237 res = test(logdepth+1, argc, argv);
238 filelist_free(&argc, &argv);
239 free(out);
240 }
241
242 if (res) {
243 logprintf(logdepth+1, "Works.", cmd);
244 put("/internal/filelist/cmd", list_cmd);
245 put("/internal/filelist/method", method);
246 report("OK ('%s' with %s split)\n", list_cmd, method);
247 }
248
249 free(cmd);
250 return res;
251 }
252
253 int find_filelist(const char *name, int logdepth, int fatal)
254 {
255 char *dir;
256 char *old_cwd;
257 int ret;
258
259 old_cwd = strclone(db_cwd);
260 db_cd("/host");
261
262 require("fstools/mkdir", logdepth, fatal);
263 require("fstools/rm", logdepth, fatal);
264
265
266 report("Checking for filelist... ");
267 logprintf(logdepth, "find_filelist: trying to find file listing...\n");
268 logdepth++;
269
270
271 dir = create_testdir(logdepth);
272 if (dir == NULL) {
273 report("Failed to creat sandbox\n");
274 ret = 1;
275 goto end;
276 }
277
278 if (
279 try(logdepth, dir, "ls %s", "line") || /* should return one file name per line since the output is redirected */
280 try(logdepth, dir, "ls -1 %s", "line") || /* try to force one file name per line */
281 try(logdepth, dir, "ls --format=single-column %s", "line") || /* for gnu ls */
282 try(logdepth, dir, "find %s", "line") || /* if ls fails, we try find */
283 try(logdepth, dir, "ls %s", "word") || /* if that fails too, ls may still have a list in multiple columns */
284 try(logdepth, dir, "dir %s", "word") || /* or we are on windows where we need to use dir maybe */
285 try(logdepth, dir, "echo %s/*", "word")) { /* or on a system without ls, dir or anything alike, but shell globbing may still work */
286
287 destroy_testdir(logdepth, dir);
288 ret = 0;
289 goto end;
290 }
291
292 destroy_testdir(logdepth, dir);
293 ret = 1;
294 end:;
295 db_cd(old_cwd);
296 free(old_cwd);
297 return ret;
298 }
299
300
301 void filelist(int logdepth, const char *dir, int *argc, char ***argv)
302 {
303 const char *list_cmd, *method;
304 char *cmd, *out, *dir_esc;
305 char *old_cwd;
306
307 old_cwd = strclone(db_cwd);
308 db_cd("/host");
309
310 /* make sure these are set to invalid for easier return in case we fail anywhere later */
311 *argc = -1;
312 *argv = NULL;
313
314 if (!is_dir(dir))
315 goto end;
316
317 require("/internal/filelist/cmd", logdepth, 1);
318 require("/internal/filelist/method", logdepth, 1);
319
320 list_cmd = get("/internal/filelist/cmd");
321 method = get("/internal/filelist/method");
322
323 dir_esc = shell_escape_dup(dir);
324 cmd = filelist_asmcmd(dir_esc, list_cmd);
325 free(dir_esc);
326 run_shell(logdepth+1, cmd, &out);
327 if (out != NULL) {
328 filelist_extract(out, dir, method, argc, argv);
329 logprintf(logdepth, "filelist: Getting list of files in %s\n", dir);
330 free(out);
331 }
332
333 free(cmd);
334 end:;
335 db_cd(old_cwd);
336 free(old_cwd);
337 }
0 #include <stdlib.h>
1 #include <stdio.h>
2 #include <assert.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <ctype.h>
6 #include "log.h"
7 #include "libs.h"
8 #include "db.h"
9 #include "dep.h"
10 #include "regex.h"
11
12 static void zap(char **str)
13 {
14 const char *pat = get("/arg/sys/pkg-config-zap");
15 char *n;
16
17 if (pat == NULL)
18 return;
19 if (re_comp(pat) != NULL)
20 return;
21 while (re_exec(*str)) {
22 n = re_subs_dup("");
23 free(*str);
24 *str = n;
25 }
26 }
27
28 int run_gen_config(int logdepth, const char *confname, const char *pkgname, char **cflags, char **ldflags)
29 {
30 char cmd[256];
31
32 assert(strlen(pkgname) < sizeof(cmd) - 64);
33
34 if (cflags != NULL) {
35 sprintf(cmd, "%s --cflags %s", confname, pkgname);
36 if (run(logdepth, cmd, cflags) != 0) {
37 report("not found: %s --cflags failed.", confname);
38 logprintf(logdepth, "not found: %s --cflags failed.\n", confname);
39 return -1;
40 }
41 if (*cflags != NULL) {
42 zap(cflags);
43 strip(*cflags);
44 }
45 }
46
47 if (ldflags != NULL) {
48 sprintf(cmd, "%s --libs %s", confname, pkgname);
49 if (run(logdepth, cmd, ldflags) != 0) {
50 report("not found: %s --libs failed.", confname);
51 logprintf(logdepth, "not found: %s --libs failed.\n", confname);
52 if (cflags != NULL)
53 free(*cflags);
54 return -1;
55 }
56 if (*ldflags != NULL) {
57 zap(ldflags);
58 strip(*ldflags);
59 }
60 }
61
62 return 0;
63 }
64
65 const char *pkg_config_name()
66 {
67 const char *name;
68 name = get("/arg/sys/pkg-config");
69 if (name != NULL)
70 return name;
71 return "pkg-config"; /* fallback */
72 }
73
74 /** run_pkg_config_modversion:
75 run `pkg-config` on @pkgname:
76 - with `--modversion` if @modversion is not NULL, storing the result in @modversion (malloc()'d)
77 Returns 0 on success.
78 */
79 int run_pkg_config_modversion(int logdepth, const char *pkgname, char **modversion)
80 {
81 char cmd[256];
82 const char *confname = pkg_config_name();
83
84 assert(strlen(pkgname) < sizeof(cmd) - 64);
85
86 if (modversion != NULL) {
87 sprintf(cmd, "%s --modversion %s", confname, pkgname);
88 if (run(logdepth, cmd, modversion) != 0) {
89 /*report("Module version not found: %s --modversion %s failed.", confname, pkgname);
90 logprintf(logdepth, "Module version not found: %s --modversion %s failed.\n", confname, pkgname); */
91 return -1;
92 }
93 zap(modversion);
94 strip(*modversion);
95 }
96
97 return 0;
98 }
99
100 /** run_pkg_config_modversion_db:
101 run `pkg-config --modversion` on @pkgname to find module (or package) version
102 and store the result in @node/modversion
103 Returns 0 on success.
104 */
105 int run_pkg_config_modversion_db(int logdepth, const char *node, const char *pkgname /*, char **modversion */ )
106 {
107 char *modversion;
108 char *tmp;
109
110 if (run_pkg_config_modversion(logdepth, pkgname, &modversion) != 0) {
111 return -1;
112 }
113 /* Store the module version in node */
114 tmp = str_concat("/", node, "modversion", NULL);
115 put(tmp, modversion);
116 free(tmp);
117 free(modversion);
118
119 return 0;
120 }
121
122 int run_pkg_config(int logdepth, const char *pkgname, char **cflags, char **ldflags)
123 {
124
125 return run_gen_config(logdepth, pkg_config_name(), pkgname, cflags, ldflags);
126 }
127
128 void run_pkg_config_lst(int logdepth, const char *pkgpat, int *argc, char ***argv)
129 {
130 char *end, *s, *next;
131 int n = 0, a = 0;
132 char **sf = NULL;
133 static const char *pkg_cfg_cache = NULL;
134 static char no_pkg_cfg;
135 char *list;
136
137 if (pkg_cfg_cache == &no_pkg_cfg)
138 goto error;
139
140 if (pkg_cfg_cache == NULL) {
141 char *cmd = str_concat(" ", pkg_config_name(), "--list-all", NULL);
142 run(logdepth, cmd, (char **) &pkg_cfg_cache);
143 free(cmd);
144 if (pkg_cfg_cache == NULL) {
145 pkg_cfg_cache = &no_pkg_cfg;
146 goto error;
147 }
148 }
149
150 if (re_comp(pkgpat) != NULL)
151 goto error;
152
153 s = list = strclone(pkg_cfg_cache);
154 for (;;) {
155 while (isspace(*s))
156 s++;
157 if (*s == '\0')
158 break;
159 next = strpbrk(s, "\r\n");
160 if (next != NULL)
161 *next = '\0';
162 if (re_exec(s)) {
163 if ((n + 2) >= a) { /* n+2: make sure there's always room for the NULL at the end */
164 a += 16;
165 sf = realloc(sf, sizeof(char *) * a);
166 }
167 end = strpbrk(s, " \t");
168 if (end != NULL)
169 *end = '\0';
170
171 sf[n] = strclone(s);
172 sf[n + 1] = re_subs_dup("");
173 /* report("\ns='%s' sf='%s'\n", s, sf[n]);*/
174 n += 2;
175 }
176 s = next + 1;
177 }
178
179 if (sf != NULL)
180 sf[n] = NULL;
181
182 free(list);
183 error:;
184 *argc = n;
185 *argv = sf;
186 return;
187 }
0 /*
1 scconfig - library to explore the source tree
2 Copyright (C) 2015 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "db.h"
26 #include "libs.h"
27 #include "log.h"
28 #include "dep.h"
29
30
31 char *svn_info(int logdepth, const char *dir, const char *key)
32 {
33 char *cmd, *stdo = NULL;
34 char *res = NULL;
35 int keylen = strlen(key);
36
37 cmd = str_concat(" ", "svn info", dir, NULL);
38 if (run_shell(logdepth, cmd, &stdo) == 0) {
39 char *line, *nline;
40
41 /* check key against each line */
42 for(line = stdo; line != NULL; line = nline) {
43 /* split line */
44 nline = strpbrk(line, "\r\n");
45 if (nline != NULL) {
46 *nline = '\0';
47 nline++;
48 while((*nline == '\n') || (*nline == '\r')) nline++;
49 }
50
51 /* compare key */
52 if (strncmp(line, key, keylen) == 0) {
53 char *val;
54
55 /* extract value */
56 val = strchr(line, ':');
57 if (val != NULL) {
58 val++;
59 while((*val == ' ') || (*val == '\t')) val++;
60 }
61 else
62 val = line;
63
64 /* produce output */
65 res = strclone(val);
66 goto found;
67 }
68 }
69 }
70
71 found:;
72 if (stdo != NULL)
73 free(stdo);
74 free(cmd);
75 return res;
76 }
0 #include <stdlib.h>
1 #include <string.h>
2 #include <unistd.h>
3 #include "libs.h"
4 #include "log.h"
5 #include "db.h"
6 #include "dep.h"
7
8 /* Returns true if the first 2 characters of the output is OK */
9 static int try_icl_accept_ok(char *stdout_str)
10 {
11 return (strncmp(stdout_str, "OK", 2) == 0);
12 }
13
14 #define is_ctrl_prefix(ch) (((ch) == '!') || ((ch) == '^'))
15
16 static int try_icl__(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags, const char *db_includes, const char *db_cflags, const char *db_ldflags, int run, int (*accept_res)(char *stdout_str))
17 {
18 char *out = NULL;
19 char *tmp, *inc;
20 const char *test_c;
21 char c[1024];
22 int l, compres;
23
24 if (includes != NULL) {
25 l = strlen(includes);
26 memcpy(c, includes, l);
27 c[l] = '\n';
28 l++;
29 strcpy(c+l, test_c_in);
30 test_c = c;
31 }
32 else
33 test_c = test_c_in;
34
35 logprintf(logdepth, "trying '%s' and '%s' and '%s', %s\n", str_null(db_includes), str_null(db_cflags), str_null(db_ldflags), run ? "with a run" : "with no run");
36
37 if (run)
38 compres = compile_run(logdepth+1, test_c, NULL, cflags, ldflags, &out);
39 else {
40 char *fn_output = NULL;
41 compres = compile_code(logdepth+1, test_c, &fn_output, NULL, cflags, ldflags);
42 if (fn_output != NULL) {
43 unlink(fn_output);
44 free(fn_output);
45 }
46 }
47
48
49 if (compres == 0) {
50 if (!run || target_emu_fail(out) || accept_res(out)) {
51 free(out);
52
53 /* no prefix: don't modify the database, the caller will do that */
54 if (prefix == NULL)
55 return 1;
56
57 tmp = malloc(strlen(prefix) + 32);
58
59 if ((db_includes == NULL) || (*db_includes == '\0'))
60 inc = strclone("");
61 else
62 inc = uniq_inc_str(db_includes, NULL, "\\n", 0, 0, NULL);
63 sprintf(tmp, "%s/includes", prefix);
64 put(tmp, inc);
65
66 if (db_cflags == NULL)
67 db_cflags = "";
68
69 sprintf(tmp, "%s/cflags", prefix);
70 put(tmp, db_cflags);
71
72
73 if (db_ldflags == NULL)
74 db_ldflags = "";
75 sprintf(tmp, "%s/ldflags", prefix);
76 put(tmp, db_ldflags);
77
78 if (inc != NULL) {
79 report("OK ('%s', '%s' and '%s')\n", str_null(inc), str_null(db_cflags), str_null(db_ldflags));
80 free(inc);
81 }
82 else
83 report("OK ('%s' and '%s')\n", str_null(db_cflags), str_null(db_ldflags));
84
85 sprintf(tmp, "%s/presents", prefix);
86 put(tmp, strue);
87 free(tmp);
88 return 1;
89 }
90 free(out);
91 }
92 return 0;
93 }
94
95 #define LOAD(node) \
96 do { \
97 if (u ## node != NULL) break; \
98 strcpy(apath_end, #node); \
99 u ## node = get(apath); \
100 } while(0)
101
102 #define SET(dst, src, is_flag) \
103 do { \
104 char *__sep__ = is_flag ? " " : "\n"; \
105 const char *__dst__ = dst == NULL ? "" : dst; \
106 char *__out__; \
107 if (is_ctrl_prefix(*__dst__)) __dst__++; \
108 if (*src == '!') \
109 __out__ = strclone(src+1); \
110 else if (*src == '^') {\
111 if (src[1] != '\0') \
112 __out__ = str_concat("", src+1, __sep__, __dst__, NULL); \
113 else \
114 __out__ = strclone(__dst__); \
115 } \
116 else { \
117 if (*__dst__ != '\0') \
118 __out__ = str_concat("", __dst__, __sep__, src, NULL); \
119 else \
120 __out__ = strclone(src); \
121 } \
122 free(dst); \
123 dst = __out__; \
124 if (is_flag) { \
125 char *__s__; \
126 for(__s__ = dst; *__s__ != '\0'; __s__++) \
127 if ((*__s__ == '\n') || (*__s__ == '\r')) \
128 *__s__ = ' '; \
129 } \
130 } while(0)
131
132
133 /* Figure user overrides and call try_icl__() accordingly */
134 int try_icl_(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags, int run, int (*accept_res)(char *stdout_str))
135 {
136 char apath[1024], *apath_end;
137 int l, res;
138 const char *uincludes = NULL, *ucflags = NULL, *uldflags = NULL, *uprefix = NULL; /* user specified */
139 char *rincludes, *rcflags, *rldflags; /* real */
140 char *dbincludes = NULL, *dbcflags = NULL, *dbldflags = NULL; /* what to add in the db at the end */
141
142 /* load uincludes, uclfags, uldflags and uprefix - LOAD() inserts the u */
143 l = sprintf(apath, "/arg/icl/%s/", prefix); apath_end = apath+l;
144 LOAD(includes);
145 LOAD(cflags);
146 LOAD(ldflags);
147 LOAD(prefix);
148 l = sprintf(apath, "/arg/icl/%s/%s/", db_cwd, prefix); apath_end = apath+l;
149 LOAD(includes);
150 LOAD(cflags);
151 LOAD(ldflags);
152 LOAD(prefix);
153
154 /* special case: all three specified by the user - ignore what the detector wanted, but run only once per node prefix */
155 if ((uincludes != NULL) && (ucflags != NULL) && (uldflags != NULL)) {
156 const char *am;
157 sprintf(apath, "%s/icl/all_manual_result", prefix);
158 am = get(apath);
159 if (am != NULL)
160 return istrue(am); /* return cached result if available */
161 res = try_icl__(logdepth, prefix, test_c_in, uincludes, ucflags, uldflags, uincludes, ucflags, uldflags, run, accept_res);
162 put(apath, res ? strue : sfalse);
163 return res;
164 }
165
166 /* TODO: get default cflags here */
167 rincludes = NULL;
168 rcflags = strclone(get("cc/cflags"));
169 rldflags = strclone(get("cc/ldflags"));
170
171 /* override base/default values with detection requested ones */
172 if (includes != NULL) SET(rincludes, includes, 0);
173 if (cflags != NULL) SET(rcflags, cflags, 1);
174 if (ldflags != NULL) SET(rldflags, ldflags, 1);
175
176 if (includes != NULL) SET(dbincludes, includes, 0);
177 if (cflags != NULL) SET(dbcflags, cflags, 1);
178 if (ldflags != NULL) SET(dbldflags, ldflags, 1);
179
180 /* override detection with user specified ICL values */
181 if (uincludes != NULL) SET(rincludes, uincludes, 0);
182 if (ucflags != NULL) SET(rcflags, ucflags, 1);
183 if (uldflags != NULL) SET(rldflags, uldflags, 1);
184
185 if (uincludes != NULL) SET(dbincludes, uincludes, 0);
186 if (ucflags != NULL) SET(dbcflags, ucflags, 1);
187 if (uldflags != NULL) SET(dbldflags, uldflags, 1);
188
189 /* insert prefix as needed */
190 if (uprefix != NULL) {
191 char *old, *prfx;
192
193 old = rcflags;
194 if ((rcflags != NULL) && (*rcflags == '^')) {
195 rcflags++;
196 prfx = "^";
197 }
198 else
199 prfx = "";
200 rcflags = str_concat("", prfx, "-I", uprefix, "/include ", rcflags, NULL);
201 if (old != cflags) free(old);
202
203 old = rldflags;
204 if ((rldflags != NULL) && (*rldflags == '^')) {
205 rldflags++;
206 prfx = "^";
207 }
208 else
209 prfx = "";
210 rldflags = str_concat("", prfx, "-L", uprefix, "/lib ", rldflags, NULL);
211 if (old != ldflags) free(old);
212 }
213
214 res = try_icl__(logdepth, prefix, test_c_in, rincludes, rcflags, rldflags, dbincludes, dbcflags, dbldflags, run, accept_res);
215
216 /* if we had to alloc, free here */
217 free(rincludes);
218 free(rcflags);
219 free(rldflags);
220 free(dbincludes);
221 free(dbcflags);
222 free(dbldflags);
223
224 return res;
225 }
226
227 #undef LOAD
228 #undef SET
229
230 int try_icl(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags)
231 {
232 return try_icl_(logdepth, prefix, test_c_in, includes, cflags, ldflags, 1, try_icl_accept_ok);
233 }
234
235 int try_icl_with_deps(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags, const char *dep_includes, const char *dep_cflags, const char *dep_ldflags, int run)
236 {
237 int res;
238
239 if ((dep_includes != NULL) && (*dep_includes == '\0')) dep_includes = NULL;
240 if ((dep_cflags != NULL) && (*dep_cflags == '\0')) dep_cflags = NULL;
241 if ((dep_ldflags != NULL) && (*dep_ldflags == '\0')) dep_ldflags = NULL;
242
243 if (dep_includes != NULL) includes = str_concat(" ", dep_includes, includes, NULL);
244 if (dep_cflags != NULL) cflags = str_concat(" ", dep_cflags, cflags, NULL);
245 if (dep_ldflags != NULL) ldflags = str_concat(" ", dep_ldflags, ldflags, NULL);
246
247 res = try_icl_(logdepth, prefix, test_c_in, includes, cflags, ldflags, run, try_icl_accept_ok);
248
249 if (dep_includes != NULL) free((char *)includes);
250 if (dep_cflags != NULL) free((char *)cflags);
251 if (dep_ldflags != NULL) free((char *)ldflags);
252
253 return res;
254 }
255
256 int try_icl_norun(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags)
257 {
258 return try_icl_(logdepth, prefix, test_c_in, includes, cflags, ldflags, 0, try_icl_accept_ok);
259 }
260
261
262 int try_fail(int logdepth, const char *prefix)
263 {
264 char *tmp;
265 tmp = malloc(strlen(prefix) + 32);
266 sprintf(tmp, "%s/presents", prefix);
267 put(tmp, sfalse);
268 free(tmp);
269 report("not found\n");
270 logprintf(logdepth, "NOT FOUND.");
271 return 1;
272 }
273
274 static int try_pkg_config_(int logdepth, char *pkgname, const char *prefix, const char *test_c)
275 {
276 char *cflags, *ldflags;
277 int res;
278
279 logprintf(logdepth, "Trying pkg-config %s\n", pkgname);
280 if (run_pkg_config(logdepth+1, pkgname, &cflags, &ldflags) == 0)
281 res = try_icl(logdepth+1, prefix, test_c, NULL, cflags, ldflags);
282 else
283 res = 0;
284 free(cflags);
285 free(ldflags);
286
287 return res;
288 }
289
290 int try_icl_pkg_config(int logdepth, const char *prefix, const char *test_c, char *includes, const char *pkgpat, const char *reqver)
291 {
292 char **pkg_ver, **s;
293 int num_pkg_ver;
294 int res;
295 (void) includes; /* not used */
296
297 run_pkg_config_lst(logdepth, pkgpat, &num_pkg_ver, &pkg_ver);
298 if (pkg_ver == NULL)
299 return 0;
300
301 if (reqver != NULL) {
302 /* search the list for the preferred version */
303 for(s = pkg_ver; *s != NULL; s+=2) {
304 if (strcmp(s[1], reqver) == 0) {
305 if (try_pkg_config_(logdepth, s[0], prefix, test_c)) {
306 res = 1;
307 report("Found version required (%s) using pkg_config.\n", reqver);
308 goto out;
309 }
310 else {
311 report("The version required (%s) is found (via pkg_config) but does not work\n", reqver);
312 goto out;
313 }
314 }
315 }
316 goto out;
317 }
318
319 for(s = pkg_ver; *s != NULL; s+=2) {
320 if (try_pkg_config_(logdepth, s[0], prefix, test_c)) {
321 res = 1;
322 goto out;
323 }
324 }
325
326 out:;
327 filelist_free(&num_pkg_ver, &pkg_ver);
328 return res;
329 }
330
331
332 int import_icl(const char *key, const char *fn)
333 {
334 char path[1024];
335
336 switch(*key) {
337 case 'l': sprintf(path, "/arg/icl/%s/ldflags", key+8); break;
338 case 'c': sprintf(path, "/arg/icl/%s/cflags", key+7); break;
339 case 'i': sprintf(path, "/arg/icl/%s/includes", key+9); break;
340 case 'p': sprintf(path, "/arg/icl/%s/prefix", key+7); break;
341 default:
342 return 1;
343 }
344 printf("path='%s' fn='%s'\n", path, fn);
345 return put(path, fn) == NULL;
346 }
347
348
349 static long field_accept_len;
350 static int field_accept_res(char *stdout_str)
351 {
352 char *end;
353 field_accept_len = strtol(stdout_str, &end, 10);
354 if (((*end == '\0') || (*end == '\r') || (*end == '\n')) && (field_accept_len > 0))
355 return 1;
356 return 0;
357 }
358
359 int try_icl_sfield(int logdepth, const char *prefix, const char *structn, const char *fieldn, const char *includes, const char *cflags, const char *ldflags)
360 {
361 int res;
362 char test_c[512];
363 char ls[16];
364 const char *test_c_in =
365 NL "#include <stdio.h>"
366 NL "int main()"
367 NL "{"
368 NL " %s s;"
369 NL " printf(\"%%ld\\n\", (long)sizeof(s.%s));"
370 NL "}"
371 NL;
372
373 sprintf(test_c, test_c_in, structn, fieldn);
374
375 res = try_icl_(logdepth, prefix, test_c, includes, cflags, ldflags, 1, field_accept_res);
376 if (res) {
377 sprintf(test_c, "%s/sizeof", prefix);
378 sprintf(ls, "%ld", field_accept_len);
379 put(test_c, ls);
380 }
381 return res;
382 }
383
384 int try_icl_sfields(int logdepth, const char *prefix, const char *structn, const char **fields, const char *includes, const char *cflags, const char *ldflags, int silent_exit_first_fail)
385 {
386 int succ = 0, first = 1;
387 require("cc/cc", logdepth, 1);
388
389 for(; *fields != NULL; fields++) {
390 report("Checking for %s.%s... ", structn, *fields);
391 logprintf(logdepth, "%s: checking for field %s...\n", structn, *fields);
392
393 logdepth++;
394 if (try_icl_sfield(logdepth, prefix, structn, *fields, includes, cflags, ldflags)) {
395 succ = 1;
396 }
397 else if ((silent_exit_first_fail) && (first)) {
398 return 1;
399 }
400 logdepth--;
401 first = 0;
402 }
403
404
405 if (!succ)
406 try_fail(logdepth, "libs/fsmount/next_dev");
407
408 return 0;
409 }
0 /*
1 scconfig - library for making includes on a list unique
2 Copyright (C) 2012, 2017 Tibor Palinkas
3 Copyright (C) 2017 Aron Barath
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Project page: http://repo.hu/projects/scconfig
20 Contact via email: scconfig [at] igor2.repo.hu
21 */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "db.h"
27 #include "regex.h"
28
29 #define grow \
30 if (used >= alloced) { \
31 alloced += 16; \
32 list = realloc(list, alloced * sizeof(char *)); \
33 }
34
35 char **uniq_inc_arr(const char *includes, int indirect, const char *sep_, int *numlines)
36 {
37 char *node, *next, *cw, *nw, *snode, *orig_node;
38 char *sep;
39 char **list;
40 int alloced, used, n;
41
42 orig_node = strclone(includes);
43 node = orig_node;
44 if (sep_ == NULL)
45 sep = strclone("\r\n");
46 else
47 sep = strclone(sep_);
48
49 /* reset list */
50 alloced = used = 0;
51 list = NULL;
52 /* take arguments one by one */
53 while(node != NULL) {
54 if (indirect) {
55 while((*node == ' ') || (*node == '\t')) node++;
56 next = strpbrk(node, " \t");
57 }
58 else {
59 for(;;) {
60 next = strpbrk(node, sep);
61 if ((next > node) || (next == NULL))
62 break;
63 node = next+1;
64 }
65 }
66 if (next != NULL) {
67 *next = '\0';
68 next++;
69 }
70 if (indirect)
71 snode = str_subsn(get(node));
72 else
73 snode = node;
74 cw = snode;
75 /* split node value (s) by sep */
76 /* fprintf(stderr, "nodename=%s snode=%s next=%s\n", node, snode, next);*/
77 while(cw != NULL) {
78 nw = strpbrk(cw, sep);
79 if (nw != NULL) {
80 *nw = '\0';
81 nw++;
82 }
83
84 if (*cw != '\0') {
85 /* try to find cw in the existing list - this is a slow linear search for now */
86 for(n = 0; n < used; n++) {
87 if (strcmp(list[n], cw) == 0)
88 goto already_on_list;
89 }
90 /* not found, append */
91 grow;
92 list[used] = strclone(cw);
93 used++;
94 }
95 already_on_list:;
96 cw = nw;
97 }
98 if (indirect)
99 free(snode);
100 node = next;
101 }
102 grow;
103 list[used] = NULL;
104 if (numlines != NULL)
105 *numlines = used;
106
107 free(orig_node);
108 free(sep);
109
110 return list;
111 }
112
113 void uniq_inc_free(char **arr)
114 {
115 char **s;
116 for(s = arr; *s != NULL; s++)
117 free(*s);
118 free(arr);
119 }
120
121 static int uniq_inc_str_cmp(const void *a_, const void *b_)
122 {
123 char **a = (char **)a_, **b = (char **)b_;
124 return strcmp(*a, *b);
125 }
126
127 static void uniq_inc_assemble_normal(char* const ret, int numelem, char **arr, const char *osep, const int oseplen)
128 {
129 char *end;
130 int len;
131
132 for(end = ret; 0 < numelem; ++arr, --numelem) {
133 if (!*arr)
134 continue;
135
136 len = strlen(*arr);
137 memcpy(end, *arr, len);
138 end += len;
139 memcpy(end, osep, oseplen);
140 end += oseplen;
141 free(*arr);
142 }
143
144 *end = '\0';
145 }
146
147 static void uniq_inc_assemble_groups(char* const ret, int numelem, char **arr, const char *osep, const int oseplen, int eren, char **eres)
148 {
149 char *end = ret;
150 int erei, ndx, len;
151
152 /* re_comp() uses a global variable to store the compiler regex! */
153
154 for (erei = 0; erei < eren; ++erei) {
155 if (re_comp(eres[erei]))
156 abort();
157
158 for (ndx = 0; ndx < numelem; ++ndx) {
159 if (!arr[ndx])
160 continue;
161
162 if (re_exec(arr[ndx])) {
163 len = strlen(arr[ndx]);
164 memcpy(end, arr[ndx], len);
165 end += len;
166 memcpy(end, osep, oseplen);
167 end += oseplen;
168 free(arr[ndx]);
169 arr[ndx] = NULL;
170 }
171 }
172 }
173
174 /* collect remaining elements */
175
176 uniq_inc_assemble_normal(end, numelem, arr, osep, oseplen);
177 }
178
179 char *uniq_inc_str(const char *includes, const char *isep, const char *osep, int sort, int eren, char **eres)
180 {
181 char **arr, **s, *ret;
182 int len, numelem, oseplen;
183
184 /* split and uniq */
185
186 oseplen = strlen(osep);
187 arr = uniq_inc_arr(includes, 0, isep, NULL);
188
189 /* calculate the required amount of memory */
190
191 len = 4; /* safety margin, for terminator \0, etc. */
192 numelem = 0;
193 for(s = arr; *s != NULL; s++) {
194 len += strlen(*s) + oseplen + 1;
195 numelem++;
196 }
197
198 /* sort if needed */
199
200 if (sort)
201 qsort(arr, numelem, sizeof(char *), uniq_inc_str_cmp);
202
203 /* allocate memory to assemble into */
204
205 ret = malloc(len);
206
207 /* assemble the output */
208
209 if (0>=eren)
210 uniq_inc_assemble_normal(ret, numelem, arr, osep, oseplen);
211 else
212 uniq_inc_assemble_groups(ret, numelem, arr, osep, oseplen, eren, eres);
213
214 /* done */
215
216 free(arr);
217 return ret;
218 }
219
220 char *order_inc_str(const char *includes, const char *isep, const char *word1, int dir, const char *word2)
221 {
222 const char *s, *next, *pre, *mid, *post;
223 char *out, *end;
224 long w1o = -1, w2o = -1;
225 long w1len = strlen(word1), w2len = strlen(word2), tlen;
226 long pre_len, mid_len, post_len;
227
228 if (dir == 0)
229 return NULL;
230
231 if ((w1len == 0) || (w2len == 0))
232 return strclone(includes);
233
234 if ((w1len == w2len) && (strcmp(word1, word2) == 0))
235 return strclone(includes);
236
237 /* search the starting offset of the first occurence of word1 and word2 */
238 for(s = includes; (s != NULL) && ((w1o < 0) || (w2o < 0)); s = next) {
239 next = strpbrk(s, isep);
240 if (next == NULL)
241 tlen = strlen(s);
242 else
243 tlen = next-s;
244
245 if ((w1o < 0) && (w1len == tlen) && (memcmp(s, word1, tlen) == 0))
246 w1o = s - includes;
247 if ((w2o < 0) && (w2len == tlen) && (memcmp(s, word2, tlen) == 0))
248 w2o = s - includes;
249
250 if (next != NULL)
251 next += strspn(next, isep);
252 }
253
254 /* one of the words is not on the list, the list is ordered */
255 if ((w1o < 0) || (w2o < 0))
256 return strclone(includes);
257
258 /* both words are not on the list, but the list is ordered */
259 if (((dir < 0) && (w1o < w2o)) || ((dir > 0) && (w1o > w2o)))
260 return strclone(includes);
261
262 /* split up the input at word1 and word2 */
263 tlen = strlen(includes);
264 if (dir < 0) { /* input is: 'pre w2 mid w1 post', goal is mowing w1 before w2 */
265 pre = includes;
266 pre_len = w2o;
267 mid = includes + w2o + w2len + 1;
268 mid_len = (includes + w1o) - mid;
269 post = includes + w1o + w1len + 1;
270 post_len = (includes + tlen) - post + 1;
271 }
272 else { /* input is: 'pre w1 mid w2 post' goal is moving w1 after w2*/
273 pre = includes;
274 pre_len = w1o;
275 mid = includes + w1o + w1len + 1;
276 mid_len = (includes + w2o) - mid;
277 post = includes + w2o + w2len + 1;
278 post_len = (includes + tlen) - post + 1;
279 }
280
281 /* truncate trailing separator, if present */
282 if ((pre_len > 0) && (strchr(isep, pre[pre_len-1])))
283 pre_len--;
284
285 if ((mid_len > 0) && (strchr(isep, mid[mid_len-1])))
286 mid_len--;
287
288 if ((post_len > 0) && (strchr(isep, post[mid_len-1])))
289 post_len--;
290
291 /* allocate extra space for a trailing separator and/or \0 */
292 end = out = malloc(tlen+2);
293
294 /* build the string by appending the parts */
295 #define append(str, len) \
296 if (len > 0) { \
297 memcpy(end, str, len); \
298 end += len; \
299 *end = *isep; \
300 end++; \
301 }
302
303 append(pre, pre_len);
304 if (dir < 0) {
305 append(word1, w1len);
306 append(word2, w2len);
307 }
308 append(mid, mid_len);
309 if (dir > 0) {
310 append(word2, w2len);
311 append(word1, w1len);
312 }
313 append(post, post_len);
314
315 #undef append
316
317 /* replace the last separator with \0 or just add a \0 at the end */
318 if ((end > out) && (strchr(isep, end[-1])))
319 end[-1] = '\0';
320 else
321 end[0] = '\0';
322 return out;
323 }
0 #define NL "\n"
1
2 /* main.c */
3 extern int no_autodetect_sys; /* set this to 1 to suppress system and cross detection */
4 extern int no_save_cache; /* set this to 1 to avoid saving config.cache */
5
6 /* lib_try.c: try to compile and run a test code; save results under prefix, if worked */
7 /* include, compile-flags, link-flags;
8 NULL includes, cflags, *ldflags means don't put anything in the db; cflags
9 and ldflags may be prefixed with "+" to include standard flags;
10 the test code has to print "OK" if it worked. If prefix is NULL, do not
11 modify the db or announce the output, silently return 0 or 1.
12 Returns 1 if worked, 0 if not */
13 int try_icl(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags,
14 const char *ldflags);
15
16 /* same as try_icl(), but does not execute the code, only compiles. Useful
17 for test programs with undesirable side effects (e.g. gtk: would open a window) */
18 int try_icl_norun(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags,
19 const char *ldflags);
20
21 /* same as try_icl, but also insert flags picked up from deps (if not NULL);
22 useful for detecting features that depend on other detected features.
23 If run is 0, do not run the test program, compile only */
24 int try_icl_with_deps(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags, const char *dep_includes, const char *dep_cflags, const char *dep_ldflags, int run);
25
26 /* Low level function for the same, giving more control to the caller */
27 int try_icl_(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags, int run, int (*accept_res)(char *stdout_str));
28
29 /* use try_icl() on a list of packages found by pkg-config. Stick to the version
30 required if reqver is non-NULL, else try them in the order pkg-config returned
31 them. */
32 int try_icl_pkg_config(int logdepth, const char *prefix, const char *test_c, char *includes, const char *pkgpat,
33 const char *reqver);
34
35 /* call this when failed to find the feature (after multiple try_*() calls);
36 always returns 1 (so that return try_fail() does the Right Thing) */
37 int try_fail(int logdepth, const char *prefix);
38
39 /* Import an argument for controlling try_icl() */
40 int import_icl(const char *key, const char *fn);
41
42 /* Determine the sizeof() of a struct field; works the same way as icl() but
43 also sets prefix/sizeof */
44 int try_icl_sfield(int logdepth, const char *prefix, const char *structn, const char *fieldn, const char *includes, const char *cflags, const char *ldflags);
45 int try_icl_sfields(int logdepth, const char *prefix, const char *structn, const char **fields, const char *includes, const char *cflags, const char *ldflags, int silent_exit_first_fail);
46
47
48 /* lib_compile.c */
49 extern int cross_blind; /* 1 if crosscompiling is blind (no emulator to test with) */
50
51 char *shell_escape_dup(const char *in); /* strdup in and escape any special char for the shell */
52
53 int compile_file(int logdepth, const char *fn_input, char **fn_output, const char *cc, const char *cflags, const char *ldflags);
54 int compile_code(int logdepth, const char *testcode, char **fn_output, const char *cc, const char *cflags, const char *ldflags);
55
56 /* same as above, but do not add cc/cflags and cc/ldfags */
57 int compile_file_raw(int logdepth, const char *fn_input, char **fn_output, const char *cc, const char *cflags, const char *ldflags);
58 int compile_code_raw(int logdepth, const char *testcode, char **fn_output, const char *cc, const char *cflags, const char *ldflags);
59
60 int run(int logdepth, const char *cmd_, char **stdout_saved);
61 int run_shell(int logdepth, const char *cmd_, char **stdout_saved);
62 int compile_run(int logdepth, const char *testcode, const char *cc, const char *cflags, const char *ldflags,
63 char **stdout_saved);
64 int run_script(int logdepth, const char *interpreter, const char *script, const char *suffix, char **out);
65
66 /* lib_file.c */
67 int file_size(const char *name);
68 char *tempdir_new(int logdepth, const char *suffix);
69 char *tempfile_new(const char *suffix);
70 char *tempfile_dump(const char *testcode, const char *suffix);
71 char *load_file(const char *name);
72 int is_dir(const char *path);
73 int is_file(const char *path);
74 int exists(const char *path);
75 int exists_in(const char *dir, const char *file);
76 char *file_name(const char *path); /* returns malloc'd buffer */
77 char *dir_name(const char *path); /* returns malloc'd buffer */
78 char *tempfile_new_noabort(const char *suffix); /* for internal use - returns NULL instead of aborting when temp file can not be created */
79 int touch_file(const char *path);
80
81 /* lib_filelist.c */
82 void filelist(int logdepth, const char *dir, int *argc, char ***argv);
83 void filelist_free(int *argc, char ***argv);
84
85 /* lib_pkg_config.c */
86
87 /** run pkg config on @pkgname:
88 - with `--cflags` if cflags is not NULL, storing the result in cflags (malloc()'d)
89 - with `--libs` if ldflags is not NULL, storing the result in ldflags (malloc()'d)
90 Returns 0 on success.
91 */
92 int run_pkg_config(int logdepth, const char *pkgname, char **cflags, char **ldflags);
93
94 /** same as run_pkg_config(), but runs a generic config tool (e.g. gdconfig)
95 passed in confname */
96 int run_gen_config(int logdepth, const char *confname, const char *pkgname, char **cflags, char **ldflags);
97
98 int run_pkg_config_modversion(int logdepth, const char *pkgname, char **modversion);
99 int run_pkg_config_modversion_db(int logdepth, const char *node, const char *pkgname);
100
101 /** run pkg-config --list-all and keep lines matching regex pkgpat.
102
103 argc/argv is a filelist output, each item pair is package name returned by
104 pkg_config (odd items are full package names, even items are suffixes:
105 pkgpath match removed)
106 */
107 void run_pkg_config_lst(int logdepth, const char *pkgpat, int *argc, char ***argv);
108
109
110 /* lib_uniqinc.c */
111 char **uniq_inc_arr(const char *includes, int indirect, const char *sep, int *numlines); /* split includes by sep; includes is a list of nodes to get() if indirect is non-zero; return a NULL-terminated array of unique include strings and set *numlines if numlines is not NULL */
112 void uniq_inc_free(char **arr); /* free an array returned by uniq_inc_arr() */
113 char *uniq_inc_str(const char *includes, const char *isep, const char *osep, int sort, int eren, char **eres); /* take a long list of includes separated by isep and emit an uniq list separated by osep */
114 char *order_inc_str(const char *includes, const char *isep, const char *word1, int dir, const char *word2); /* take a long list of includes separated by isep and emit a new list where word1 is moved before/after of word2 if dir < 0 or dir > 0 */
115
116 /* find_types.c */
117 int find_types_something_t(const char *name, int logdepth, int fatal, const char* prefix, const char *typ, const char* define, const char *try_include);
118
119 /* str.c */
120 char *strclone(const char *str);
121 char *trim_left(char *str);
122 char *trim_right(char *str);
123 char *strip(char *str);
124 char *str_chr(char *str, char c);
125 char *str_rchr(char *str, char c);
126 char *str_subsn(const char *str); /* advanced strdup that also interprets \n */
127 char *str_concat(const char *sep, ...); /* concat a list of strings into a newly allocated buffer, putting sep between them */
128 char *esc_interpret(const char *str);
129 int chr_inset(char c, const char *set); /* returns whether c is in set */
130
131 /* srctree.c */
132
133 /* Run svn info on dir and extract the value for key;
134 key is case sensitive. The first match is returned or NULL if not found
135 or on error. */
136 char *svn_info(int logdepth, const char *dir, const char *key);
137
138 #define isblind(root) ((strncmp((root), "/target", 7) == 0) && cross_blind)
139 #define istarget(root) (strncmp((root), "/target", 7) == 0)
140
141 #define target_emu_fail(out) ((isblind(db_cwd)) && (out == NULL))
142
143 #define safeNULL(s) ((s) == NULL ? "(NULL)" : (s))
144 #define str_null(s) ((s) == NULL ? "" : (s))
145
146 /* Test program helper: generate code that ensures a given FUNCT exists
147 and is a function; can be turned off by defining SCCONFIG_ACCEPT_IMPLICIT
148 on scconfig compilation time */
149 /* Both FUNCT1 and FUNCT2 argument *must* be used exactly once! In some
150 cases FUNCT1 and FUNCT2 is a format string parameter. We expect, however,
151 both arguments will substituted to the same value. */
152 #ifdef SCCONFIG_ACCEPT_IMPLICIT
153 # define no_implicit(RET_TYPE, FUNCT1, FUNCT2) \
154 "/* accept implicit (" FUNCT1 ", " FUNCT2 ") */\n"
155 #else
156 # define no_implicit(RET_TYPE, FUNCT1, FUNCT2) \
157 "#ifndef " FUNCT1 "\n" \
158 "{ " #RET_TYPE " (*tmp)() = " FUNCT2 "; if (tmp) {}}\n" \
159 "#endif\n"
160 #endif
0 /*
1 scconfig - logging
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include "log.h"
23 #include <stdio.h>
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <string.h>
27
28 char *spaces = " ";
29 FILE *logfile = NULL;
30 char *fn_log = "config.log";
31
32 void log_init(void)
33 {
34 if (fn_log != NULL) {
35 /* double open for truncate - for extreme portability, please do not "fix" */
36 logfile = fopen(fn_log, "w");
37 assert(logfile != NULL);
38 fclose(logfile);
39 logfile = fopen(fn_log, "a");
40 assert(logfile != NULL);
41 }
42 }
43
44 void log_uninit(void)
45 {
46 if (logfile != NULL)
47 fclose(logfile);
48 }
49
50 void logprintf(int depth, const char *format, ...)
51 {
52 va_list ap;
53 va_start(ap, format);
54
55 if (logfile != NULL) {
56 fprintf(logfile, "%s", logprefix(depth));
57 vfprintf(logfile, format, ap);
58 fflush(logfile);
59 }
60
61 va_end(ap);
62 }
63
64 void error(const char *format, ...)
65 {
66 va_list ap;
67 va_start(ap, format);
68 vfprintf(stderr, format, ap);
69 va_end(ap);
70
71 va_start(ap, format);
72 if (logfile != NULL) {
73 fprintf(logfile, "###error### ");
74 vfprintf(logfile, format, ap);
75 fflush(logfile);
76 }
77 va_end(ap);
78
79 }
80
81 void report(const char *format, ...)
82 {
83 va_list ap;
84 va_start(ap, format);
85 vprintf(format, ap);
86 fflush(stdout);
87 va_end(ap);
88
89 va_start(ap, format);
90 if (logfile != NULL) {
91 fprintf(logfile, "###report### ");
92 vfprintf(logfile, format, ap);
93 fflush(logfile);
94 }
95 va_end(ap);
96 }
97
98 void log_merge(int logdepth, const char *fn)
99 {
100 FILE *f;
101 char line[2048];
102 int lines;
103
104 if (logfile == NULL)
105 return;
106
107 f = fopen(fn, "r");
108 if (f == NULL) {
109 logprintf(logdepth, "scconfig error: couldn't open %s for merging.\n", fn);
110 return;
111 }
112 lines = 0;
113 while(!(feof(f))) {
114 *line = '\0';
115 fgets(line, sizeof(line), f);
116 if (*line != '\0') {
117 if (lines == 0)
118 logprintf(logdepth, "========= output dump start ============\n");
119 lines++;
120 logprintf(logdepth, "%s", line);
121 /* Make sure we have newline at the end of each line */
122 if (line[strlen(line)-1] != '\n')
123 logprintf(0, "\n");
124 }
125 }
126 if (lines == 0)
127 logprintf(logdepth, "========= empty stderr =================\n");
128 else
129 logprintf(logdepth, "========= output dump end ==============\n");
130 fclose(f);
131 }
0 #include <stdlib.h>
1 #include <stdio.h>
2
3 #define max_spaces 64
4 extern char *spaces;
5
6 #define logprefix(n) (((n) > max_spaces) ? spaces : (spaces+max_spaces-(n)))
7
8 void logprintf(int depth, const char *format, ...);
9 void error(const char *format, ...);
10 void report(const char *format, ...);
11
12 void log_merge(int logdepth, const char *fn);
13
14 extern FILE *logfile;
15 extern void log_init(void);
16 void log_uninit(void);
17
18 extern char *fn_log;
0 /*
1 scconfig - test code for default and scripts
2 Copyright (C) 2009..2016 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "db.h"
26 #include "find.h"
27 #include "log.h"
28 #include "arg.h"
29 #include "dep.h"
30 #include "deps_default.h"
31 #include "libs.h"
32 #include "hooks.h"
33 #include "regex.h"
34 #include "main_custom_args.h"
35 #include "main_lib.h"
36
37 void re_fail(char *s, char c)
38 {
39 fprintf(stderr, "Regex error: %s [opcode %o]\n", s, c);
40 abort();
41 }
42
43 int no_autodetect_sys = 0;
44 int no_save_cache = 0;
45 int main(int argc, char *argv[])
46 {
47 int blind_save;
48
49 if (main_init() != 0)
50 return 1;
51
52 if (main_process_args(argc, argv) != 0)
53 return 1;
54
55 if (!no_autodetect_sys) {
56 find_target("", 0, 1);
57 blind_save = cross_blind;
58 cross_blind = 0;
59 printf("--- Detecting host\n");
60
61 require("sys/name", 0, 1);
62 }
63
64 if (hook_detect_host()) {
65 fprintf(stderr, "hook_detect_host failed, exiting\n");
66 return 1;
67 }
68
69 cross_blind = blind_save;
70 if (!no_autodetect_sys) {
71 if (!iscross)
72 printf("--- Detecting target (same as host)\n");
73 else
74 printf("--- Detecting target (differs from host)\n");
75 }
76 db_cd("/target");
77 run_custom_reqs();
78
79
80 if (hook_detect_target()) {
81 fprintf(stderr, "hook_detect_target failed, exiting\n");
82 return 1;
83 }
84
85 #ifdef RUNTIME
86 if (!no_autodetect_sys) {
87 if (!iscross)
88 printf("--- Detecting runtime (same as host)\n");
89 else
90 printf("--- Detecting runtime (differs from host)\n");
91 }
92 db_cd("/runtime");
93 if (hook_detect_runtime()) {
94 fprintf(stderr, "hook_detect_runtime failed, exiting\n");
95 return 1;
96 }
97 #endif
98
99 if (hook_generate()) {
100 fprintf(stderr, "hook_generate failed, exiting\n");
101 return 1;
102 }
103
104 if (!no_save_cache)
105 export("config.cache", 1, "/");
106
107 main_uninit();
108 return 0;
109 }
110
0 /*
1 scconfig - default way to handle custom args (save them in an array)
2 Copyright (C) 2016 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "hooks.h"
28 #include "main_custom_args.h"
29
30 char *custom_reqs[MAX_CUSTOM_REQS];
31 int num_custom_reqs = 0;
32
33 int custom_arg(const char *key, const char *value)
34 {
35 if (hook_custom_arg(key, value))
36 return 1;
37 if (strcmp(key, "detect") == 0) {
38 printf("Will detect: %s\n", value);
39 if (num_custom_reqs >= MAX_CUSTOM_REQS) {
40 report("Too many custom reqs from the command line, exiting\n");
41 exit(1);
42 }
43 custom_reqs[num_custom_reqs] = strclone(value);
44 num_custom_reqs++;
45 return 1;
46 }
47 return 0;
48 }
0 #define MAX_CUSTOM_REQS 32
1 extern char *custom_reqs[MAX_CUSTOM_REQS];
2 extern int num_custom_reqs;
3
4 int custom_arg(const char *key, const char *value);
5
0 /*
1 scconfig - helpers for a main()
2 Copyright (C) 2009..2016 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "db.h"
26 #include "find.h"
27 #include "log.h"
28 #include "arg.h"
29 #include "dep.h"
30 #include "deps_default.h"
31 #include "libs.h"
32 #include "hooks.h"
33 #include "regex.h"
34 #include "main_custom_args.h"
35
36 #ifdef PLUGIN_SCRIPTS
37 #include "../scripts/INIT.h"
38 #endif
39
40 #ifdef PLUGIN_PARSER
41 #include "../parser/INIT.h"
42 #endif
43
44 #ifdef PLUGIN_C99
45 #include "../c99/INIT.h"
46 #endif
47
48 #ifdef PLUGIN_PARSGEN
49 #include "../parsgen/INIT.h"
50 #endif
51
52 #ifdef PLUGIN_MATH
53 #include "../math/INIT.h"
54 #endif
55
56 #ifdef PLUGIN_SOCKET
57 #include "../socket/INIT.h"
58 #endif
59
60 #ifdef PLUGIN_USERPASS
61 #include "../userpass/INIT.h"
62 #endif
63
64 #ifdef PLUGIN_GUI
65 #include "../gui/INIT.h"
66 #endif
67
68 #ifdef PLUGIN_TTY
69 #include "../tty/INIT.h"
70 #endif
71
72 #ifdef PLUGIN_SUL
73 #include "../sul/INIT.h"
74 #endif
75
76 #ifdef PLUGIN_POSIX
77 #include "../posix/INIT.h"
78 #endif
79
80 #ifdef PLUGIN_GENERATOR
81 #include "generator.h"
82 #endif
83
84
85 void init(void)
86 {
87 db_init();
88 log_init();
89 dep_init();
90 deps_default_init();
91
92 /* common internal directory */
93 db_mkdir("/internal");
94
95 /* We have a host system for sure - also make it the default */
96 db_mkdir("/host");
97 db_cd("/host");
98
99 /* emulator for the host system is empty string */
100 put("sys/emu", "");
101
102 #ifdef PLUGIN_SCRIPTS
103 #include "../scripts/INIT.c"
104 #endif
105
106 #ifdef PLUGIN_PARSER
107 #include "../parser/INIT.c"
108 #endif
109
110 #ifdef PLUGIN_C99
111 #include "../c99/INIT.c"
112 #endif
113
114 #ifdef PLUGIN_PARSGEN
115 #include "../parsgen/INIT.c"
116 #endif
117
118 #ifdef PLUGIN_MATH
119 #include "../math/INIT.c"
120 #endif
121
122 #ifdef PLUGIN_SOCKET
123 #include "../socket/INIT.c"
124 #endif
125
126 #ifdef PLUGIN_USERPASS
127 #include "../userpass/INIT.c"
128 #endif
129
130 #ifdef PLUGIN_GUI
131 #include "../gui/INIT.c"
132 #endif
133
134 #ifdef PLUGIN_TTY
135 #include "../tty/INIT.c"
136 #endif
137
138 #ifdef PLUGIN_SUL
139 #include "../sul/INIT.c"
140 #endif
141
142 #ifdef PLUGIN_POSIX
143 #include "../posix/INIT.c"
144 #endif
145
146 #ifdef PLUGIN_GENERATOR
147 #include "../generator/INIT.c"
148 #endif
149 }
150
151 void uninit(void)
152 {
153 log_uninit();
154 dep_uninit();
155 db_uninit();
156 }
157
158 void run_custom_reqs(void)
159 {
160 int n;
161 if (num_custom_reqs > 0) {
162 printf("Running custom requirements\n");
163 for(n = 0; n < num_custom_reqs; n++) {
164 if (custom_reqs[n] == NULL) {
165 fprintf(stderr, "Error: requested detection of empty string - please check your command line, syntax is --detect=node\n");
166 exit(1);
167 }
168 require(custom_reqs[n], 1, 1);
169 }
170 }
171 }
172
173 int main_init(void)
174 {
175 re_modw("./\\");
176 if (hook_preinit()) {
177 fprintf(stderr, "hook_preinit failed, exiting\n");
178 return 1;
179 }
180 init();
181 if (hook_postinit()) {
182 fprintf(stderr, "hook_postinit failed, exiting\n");
183 return 1;
184 }
185 return 0;
186 }
187
188 int main_process_args(int argc, char *argv[])
189 {
190 process_args(argc, argv);
191 if (hook_postarg()) {
192 fprintf(stderr, "hook_postarg failed, exiting\n");
193 return 1;
194 }
195 return 0;
196 }
197
198 void main_uninit(void)
199 {
200 hook_preuninit();
201 uninit();
202 hook_postuninit();
203 }
0 int main_init(void);
1 int main_process_args(int argc, char *argv[]);
2 void main_uninit(void);
3
4 /* internal */
5 void init(void);
6 void uninit(void);
7 void run_custom_reqs(void);
0 /*
1
2 * regex - Regular expression pattern matching and replacement
3 *
4 * By: Ozan S. Yigit (oz)
5 * Dept. of Computer Science
6 * York University
7 *
8 * These routines are the PUBLIC DOMAIN equivalents of regex
9 * routines as found in 4.nBSD UN*X, with minor extensions.
10 *
11 * These routines are derived from various implementations found
12 * in software tools books, and Conroy's grep. They are NOT derived
13 * from licensed/restricted software.
14 * For more interesting/academic/complicated implementations,
15 * see Henry Spencer's regexp routines, or GNU Emacs pattern
16 * matching module.
17 *
18 * const correctness patch by Tibor 'Igor2' Palinkas in 2009..2010
19 * new subs code by Tibor 'Igor2' Palinkas in 2015
20 */
21 #include <stdlib.h>
22 #include <string.h>
23 #include "regex.h"
24
25 #define MAXNFA 1024
26 #define MAXTAG 10
27
28 #define OKP 1
29 #define NOP 0
30
31 #define CHR 1
32 #define ANY 2
33 #define CCL 3
34 #define BOL 4
35 #define EOL 5
36 #define BOT 6
37 #define EOT 7
38 #define BOW 8
39 #define EOW 9
40 #define REF 10
41 #define CLO 11
42
43 #define END 0
44
45 /*
46 * The following defines are not meant to be changeable.
47 * They are for readability only.
48 */
49 #define MAXCHR 128
50 #define CHRBIT 8
51 #define BITBLK MAXCHR/CHRBIT
52 #define BLKIND 0170
53 #define BITIND 07
54
55 #define ASCIIB 0177
56
57 #ifdef NO_UCHAR
58 typedef char CHAR;
59 #else
60 typedef unsigned char CHAR;
61 #endif
62
63 static int tagstk[MAXTAG]; /* subpat tag stack..*/
64 static CHAR nfa[MAXNFA]; /* automaton.. */
65 static int sta = NOP; /* status of lastpat */
66
67 static CHAR bittab[BITBLK]; /* bit table for CCL */
68 /* pre-set bits... */
69 static CHAR bitarr[] = {1,2,4,8,16,32,64,128};
70
71 static void
72 chset(CHAR c)
73 {
74 bittab[(CHAR) ((c) & BLKIND) >> 3] |= bitarr[(c) & BITIND];
75 }
76
77 #define badpat(x) (*nfa = END, x)
78 #define store(x) *mp++ = x
79
80 char *
81 re_comp(const char *pat)
82 {
83 register const char *p; /* pattern pointer */
84 register CHAR *mp=nfa; /* nfa pointer */
85 register CHAR *lp; /* saved pointer.. */
86 register CHAR *sp=nfa; /* another one.. */
87
88 register int tagi = 0; /* tag stack index */
89 register int tagc = 1; /* actual tag count */
90
91 register int n;
92 register CHAR mask; /* xor mask -CCL/NCL */
93 int c1, c2;
94
95 if (!pat || !*pat) {
96 if (sta)
97 return 0;
98 else
99 return badpat("No previous regular expression");
100 }
101 sta = NOP;
102
103 for (p = pat; *p; p++) {
104 lp = mp;
105 switch(*p) {
106
107 case '.': /* match any char.. */
108 store(ANY);
109 break;
110
111 case '^': /* match beginning.. */
112 if (p == pat)
113 store(BOL);
114 else {
115 store(CHR);
116 store(*p);
117 }
118 break;
119
120 case '$': /* match endofline.. */
121 if (!*(p+1))
122 store(EOL);
123 else {
124 store(CHR);
125 store(*p);
126 }
127 break;
128
129 case '[': /* match char class..*/
130 store(CCL);
131
132 if (*++p == '^') {
133 mask = 0377;
134 p++;
135 }
136 else
137 mask = 0;
138
139 if (*p == '-') /* real dash */
140 chset(*p++);
141 if (*p == ']') /* real brac */
142 chset(*p++);
143 while (*p && *p != ']') {
144 if (*p == '-' && *(p+1) && *(p+1) != ']') {
145 p++;
146 c1 = *(p-2) + 1;
147 c2 = *p++;
148 while (c1 <= c2)
149 chset((CHAR)c1++);
150 }
151 #ifdef EXTEND
152 else if (*p == '\\' && *(p+1)) {
153 p++;
154 chset(*p++);
155 }
156 #endif
157 else
158 chset(*p++);
159 }
160 if (!*p)
161 return badpat("Missing ]");
162
163 for (n = 0; n < BITBLK; bittab[n++] = (char) 0)
164 store(mask ^ bittab[n]);
165
166 break;
167
168 case '*': /* match 0 or more.. */
169 case '+': /* match 1 or more.. */
170 if (p == pat)
171 return badpat("Empty closure");
172 lp = sp; /* previous opcode */
173 if (*lp == CLO) /* equivalence.. */
174 break;
175 switch(*lp) {
176
177 case BOL:
178 case BOT:
179 case EOT:
180 case BOW:
181 case EOW:
182 case REF:
183 return badpat("Illegal closure");
184 default:
185 break;
186 }
187
188 if (*p == '+')
189 for (sp = mp; lp < sp; lp++)
190 store(*lp);
191
192 store(END);
193 store(END);
194 sp = mp;
195 while (--mp > lp)
196 *mp = mp[-1];
197 store(CLO);
198 mp = sp;
199 break;
200
201 case '\\': /* tags, backrefs .. */
202 switch(*++p) {
203
204 case '(':
205 if (tagc < MAXTAG) {
206 tagstk[++tagi] = tagc;
207 store(BOT);
208 store(tagc++);
209 }
210 else
211 return badpat("Too many \\(\\) pairs");
212 break;
213 case ')':
214 if (*sp == BOT)
215 return badpat("Null pattern inside \\(\\)");
216 if (tagi > 0) {
217 store(EOT);
218 store(tagstk[tagi--]);
219 }
220 else
221 return badpat("Unmatched \\)");
222 break;
223 case '<':
224 store(BOW);
225 break;
226 case '>':
227 if (*sp == BOW)
228 return badpat("Null pattern inside \\<\\>");
229 store(EOW);
230 break;
231 case '1':
232 case '2':
233 case '3':
234 case '4':
235 case '5':
236 case '6':
237 case '7':
238 case '8':
239 case '9':
240 n = *p-'0';
241 if (tagi > 0 && tagstk[tagi] == n)
242 return badpat("Cyclical reference");
243 if (tagc > n) {
244 store(REF);
245 store(n);
246 }
247 else
248 return badpat("Undetermined reference");
249 break;
250 #ifdef EXTEND
251 case 'b':
252 store(CHR);
253 store('\b');
254 break;
255 case 'n':
256 store(CHR);
257 store('\n');
258 break;
259 case 'f':
260 store(CHR);
261 store('\f');
262 break;
263 case 'r':
264 store(CHR);
265 store('\r');
266 break;
267 case 't':
268 store(CHR);
269 store('\t');
270 break;
271 #endif
272 default:
273 store(CHR);
274 store(*p);
275 }
276 break;
277
278 default : /* an ordinary char */
279 store(CHR);
280 store(*p);
281 break;
282 }
283 sp = lp;
284 }
285 if (tagi > 0)
286 return badpat("Unmatched \\(");
287 store(END);
288 sta = OKP;
289 return 0;
290 }
291
292
293 static const char *bol;
294 const char *bopat[MAXTAG];
295 const char *eopat[MAXTAG];
296 static const char *pmatch(const char *, CHAR *, int *);
297
298 /*
299 * re_exec:
300 * execute nfa to find a match.
301 *
302 * special cases: (nfa[0])
303 * BOL
304 * Match only once, starting from the
305 * beginning.
306 * CHR
307 * First locate the character without
308 * calling pmatch, and if found, call
309 * pmatch for the remaining string.
310 * END
311 * re_comp failed, poor luser did not
312 * check for it. Fail fast.
313 *
314 * If a match is found, bopat[0] and eopat[0] are set
315 * to the beginning and the end of the matched fragment,
316 * respectively.
317 *
318 */
319
320 int
321 re_exec(const char *lp)
322 {
323 register CHAR c;
324 register const char *ep = 0;
325 register CHAR *ap = nfa;
326 int score = 1;
327
328 bol = lp;
329
330 bopat[0] = 0;
331 bopat[1] = 0;
332 bopat[2] = 0;
333 bopat[3] = 0;
334 bopat[4] = 0;
335 bopat[5] = 0;
336 bopat[6] = 0;
337 bopat[7] = 0;
338 bopat[8] = 0;
339 bopat[9] = 0;
340
341 switch(*ap) {
342
343 case BOL: /* anchored: match from BOL only */
344 ep = pmatch(lp,ap, &score);
345 break;
346 case CHR: /* ordinary char: locate it fast */
347 c = *(ap+1);
348 while (*lp && *lp != c)
349 lp++;
350 if (!*lp) /* if EOS, fail, else fall thru. */
351 return 0;
352 default: /* regular matching all the way. */
353 #ifdef OLD
354 while (*lp) {
355 if ((ep = pmatch(lp,ap, &score)))
356 break;
357 lp++;
358 }
359 #else /* match null string */
360 do {
361 if ((ep = pmatch(lp,ap, &score)))
362 break;
363 } while (*lp++);
364 #endif
365 break;
366 case END: /* munged automaton. fail always */
367 return 0;
368 }
369 if (!ep)
370 return 0;
371
372 bopat[0] = lp;
373 eopat[0] = ep;
374 return score;
375 }
376
377 /*
378 * pmatch: internal routine for the hard part
379 *
380 * This code is partly snarfed from an early grep written by
381 * David Conroy. The backref and tag stuff, and various other
382 * innovations are by oz.
383 *
384 * special case optimizations: (nfa[n], nfa[n+1])
385 * CLO ANY
386 * We KNOW .* will match everything up to the
387 * end of line. Thus, directly go to the end of
388 * line, without recursive pmatch calls. As in
389 * the other closure cases, the remaining pattern
390 * must be matched by moving backwards on the
391 * string recursively, to find a match for xy
392 * (x is ".*" and y is the remaining pattern)
393 * where the match satisfies the LONGEST match for
394 * x followed by a match for y.
395 * CLO CHR
396 * We can again scan the string forward for the
397 * single char and at the point of failure, we
398 * execute the remaining nfa recursively, same as
399 * above.
400 *
401 * At the end of a successful match, bopat[n] and eopat[n]
402 * are set to the beginning and end of subpatterns matched
403 * by tagged expressions (n = 1 to 9).
404 *
405 */
406
407 #ifndef re_fail
408 extern void re_fail(char *, unsigned char);
409 #endif
410
411 /*
412 * character classification table for word boundary operators BOW
413 * and EOW. the reason for not using ctype macros is that we can
414 * let the user add into our own table. see re_modw. This table
415 * is not in the bitset form, since we may wish to extend it in the
416 * future for other character classifications.
417 *
418 * TRUE for 0-9 A-Z a-z _
419 */
420 static CHAR chrtyp[MAXCHR] = {
421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
424 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
425 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
426 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
427 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
428 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
429 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
430 1, 0, 0, 0, 0, 1, 0, 1, 1, 1,
431 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
432 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
433 1, 1, 1, 0, 0, 0, 0, 0
434 };
435
436 #define inascii(x) (0177&(x))
437 #define iswordc(x) chrtyp[inascii(x)]
438 #define isinset(x,y) ((x)[((y)&BLKIND)>>3] & bitarr[(y)&BITIND])
439
440 /*
441 * skip values for CLO XXX to skip past the closure
442 */
443
444 #define ANYSKIP 2 /* [CLO] ANY END ... */
445 #define CHRSKIP 3 /* [CLO] CHR chr END ... */
446 #define CCLSKIP 18 /* [CLO] CCL 16bytes END ... */
447
448 static const char *
449 pmatch(const char *lp, CHAR *ap, int *score)
450 {
451 register int op, c, n;
452 register const char *e; /* extra pointer for CLO */
453 register const char *bp; /* beginning of subpat.. */
454 register const char *ep; /* ending of subpat.. */
455 const char *are; /* to save the line ptr. */
456
457 while ((op = *ap++) != END)
458 switch(op) {
459
460 case CHR:
461 if (*lp++ != *ap++)
462 return 0;
463 (*score) += 100;
464 break;
465 case ANY:
466 if (!*lp++)
467 return 0;
468 (*score)++;
469 break;
470 case CCL:
471 c = *lp++;
472 if (!isinset(ap,c))
473 return 0;
474 ap += BITBLK;
475 (*score) += 2;
476 break;
477 case BOL:
478 if (lp != bol)
479 return 0;
480 (*score) += 10;
481 break;
482 case EOL:
483 if (*lp)
484 return 0;
485 (*score) += 10;
486 break;
487 case BOT:
488 bopat[*ap++] = lp;
489 break;
490 case EOT:
491 eopat[*ap++] = lp;
492 break;
493 case BOW:
494 if ((lp!=bol && iswordc(lp[-1])) || !iswordc(*lp))
495 return 0;
496 (*score) += 5;
497 break;
498 case EOW:
499 if (lp==bol || !iswordc(lp[-1]) || iswordc(*lp))
500 return 0;
501 (*score) += 5;
502 break;
503 case REF:
504 n = *ap++;
505 bp = bopat[n];
506 ep = eopat[n];
507 while (bp < ep) {
508 if (*bp++ != *lp++)
509 return 0;
510 (*score) += 2;
511 }
512 break;
513 case CLO:
514 are = lp;
515 switch(*ap) {
516
517 case ANY:
518 while (*lp)
519 lp++;
520 n = ANYSKIP;
521 (*score)++;
522 break;
523 case CHR:
524 c = *(ap+1);
525 while (*lp && c == *lp)
526 lp++;
527 n = CHRSKIP;
528 (*score) += 100;
529 break;
530 case CCL:
531 while ((c = *lp) && isinset(ap+1,c))
532 lp++;
533 n = CCLSKIP;
534 (*score) += 2;
535 break;
536 default:
537 re_fail("closure: bad nfa.", *ap);
538 return 0;
539 }
540
541 ap += n;
542
543 while (lp >= are) {
544 e = pmatch(lp, ap, score);
545 if (e)
546 return e;
547 --lp;
548 }
549 return 0;
550 default:
551 re_fail("re_exec: bad nfa.", op);
552 return 0;
553 }
554 return lp;
555 }
556
557 /*
558 * re_modw:
559 * add new characters into the word table to change re_exec's
560 * understanding of what a word should look like. Note that we
561 * only accept additions into the word definition.
562 *
563 * If the string parameter is 0 or null string, the table is
564 * reset back to the default containing A-Z a-z 0-9 _. [We use
565 * the compact bitset representation for the default table]
566 */
567
568 static CHAR deftab[16] = {
569 0, 0, 0, 0, 0, 0, 0377, 003, 0376, 0377, 0377, 0207,
570 0376, 0377, 0377, 007
571 };
572
573 void
574 re_modw(char *s)
575 {
576 register int i;
577
578 if (!s || !*s) {
579 for (i = 0; i < MAXCHR; i++)
580 if (!isinset(deftab,i))
581 iswordc(i) = 0;
582 }
583 else
584 while(*s)
585 iswordc(*s++) = 1;
586 }
587
588 /* Substitute the matching part in the last re_exec call with sub. The
589 result is returned in a newly allocated string. */
590 char *re_subs_dup(char *sub)
591 {
592 char *dst;
593 const char *end;
594 int l1, l2, l3;
595 end = bol + strlen(bol);
596 l1 = bopat[0] - bol;
597 if (sub != NULL)
598 l2 = strlen(sub);
599 else
600 l2 = 0;
601 l3 = end - eopat[0];
602 if (l3 < 0)
603 l3 = 0;
604 dst = malloc(l1+l2+l3+1);
605 memcpy(dst, bol, l1);
606 if (l2 != 0)
607 memcpy(dst+l1, sub, l2);
608 memcpy(dst+l1+l2, eopat[0], l3+1);
609 return dst;
610 }
0 #ifndef REGEX_H
1 #define REGEX_H
2
3 extern const char *bopat[];
4 extern const char *eopat[];
5
6
7 extern char *re_comp(const char *);
8 extern int re_exec(const char *);
9 extern void re_modw(char *);
10 char *re_subs_dup(char *sub);
11
12
13 #endif /* REGEX_H */
0 /*
1 scconfig - non-standard string manipulation routines
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdarg.h>
26
27 char *strclone(const char *str)
28 {
29 int l;
30 char *ret;
31
32 if (str == NULL)
33 return NULL;
34
35 l = strlen(str)+1;
36 ret = malloc(l);
37 memcpy(ret, str, l);
38 return ret;
39 }
40
41 #define SPACE(c) (((c) == '\r') || ((c) == '\n') || ((c) == '\t') || ((c) == ' '))
42
43 char *trim_left(char *str)
44 {
45 while(SPACE(*str)) str++;
46 return str;
47 }
48
49 char *trim_right(char *str)
50 {
51 char *end;
52
53 end = str + strlen(str) - 1;
54 while((end >= str) && SPACE(*end)) { *end = '\0'; end--; }
55 return str;
56 }
57
58 char *strip(char *str)
59 {
60 return trim_left(trim_right(str));
61 }
62
63 char *str_chr(char *str, char c)
64 {
65 char *s;
66
67 for(s = str; *s != '\0'; s++)
68 if (*s == c)
69 return s;
70 return NULL;
71 }
72
73 char *str_rchr(char *str, char c)
74 {
75 char *s, *last;
76
77 last = NULL;
78 for(s = str; *s != '\0'; s++)
79 if (*s == c)
80 last = s;
81 return last;
82 }
83
84 char *str_subsn(const char *str)
85 {
86 char *out, *o;
87 const char *i;
88 if (str == NULL)
89 return strclone("");
90 o = out = malloc(strlen(str)+1);
91 for(i = str; *i != '\0'; i++, o++) {
92 if ((i[0] == '\\') && (i[1] == 'n')) {
93 i++;
94 *o = '\n';
95 }
96 else
97 *o = *i;
98 }
99 *o = '\0';
100 return out;
101 }
102
103 char *str_concat(const char *sep, ...)
104 {
105 # define CONCAT_MAX 64
106 int len[CONCAT_MAX];
107 const char *str[CONCAT_MAX];
108 int n, v, sum, sl;
109 char *out, *o;
110 va_list ap;
111 va_start(ap, sep);
112
113 if (sep == NULL)
114 sep = "";
115
116 /* load all strings into an array, measure their lengths */
117 sum = 0;
118 for(v = 0; ;v++) {
119 if (v >= CONCAT_MAX) {
120 fprintf(stderr, "Internal error: str_concat got more strings than CONCAT_MAX\n");
121 abort();
122 }
123 str[v] = va_arg(ap, const char *);
124 if (str[v] == NULL) {
125 len[v] = 0;
126 break;
127 }
128 len[v] = strlen(str[v]);
129 sum += len[v];
130 }
131
132 sl = strlen(sep);
133 sum += (v-1) * sl + 1; /* + a sep between each two strings and a terminator at the end */
134 o = out = malloc(sum);
135 for(n = 0; n < v; n++) {
136 if ((n > 0) && (sl > 0)) {
137 memcpy(o, sep, sl);
138 o += sl;
139 }
140 if (len[n] > 0) {
141 memcpy(o, str[n], len[n]);
142 o += len[n];
143 }
144 }
145 *o = '\0';
146 va_end(ap);
147 return out;
148 }
149
150 char *esc_interpret(const char *str)
151 {
152 char *out, *si, *so;
153
154 out = strclone(str);
155 /* replace (interpret) \ sequences in seq */
156 for(si = so = out; *si != '\0'; si++,so++) {
157 if (si[0] == '\\') {
158 switch(si[1]) {
159 case 'n': *so = '\n'; break;
160 case 't': *so = '\t'; break;
161 case 's': *so = ' '; break;
162 case '\\': *so = '\\'; break;
163 }
164 si++;
165 }
166 else
167 *so = *si;
168 }
169 *so = '\0';
170 return out;
171 }
172
173 int chr_inset(char c, const char *set)
174 {
175 while (*set != '\0') {
176 if (c == *set)
177 return 1;
178 set++;
179 }
180 return 0;
181 }
182
0 deps_math_init();
1
0 void deps_math_init();
0 MATH_CFLAGS = -DPLUGIN_MATH
1 MATH_OBJS = \
2 $(BIN)/math/find_math.o \
3 $(BIN)/math/find_fpenan.o \
4 $(BIN)/math/find_func.o \
5 $(BIN)/math/find_mfunc_cc.o
6
7 $(BIN)/math/find_math.o: $(SRC)/math/find_math.c
8 $(CC) $(CFLAGS) -c $(SRC)/math/find_math.c -o $(BIN)/math/find_math.o
9
10 $(BIN)/math/find_fpenan.o: $(SRC)/math/find_fpenan.c
11 $(CC) $(CFLAGS) -c $(SRC)/math/find_fpenan.c -o $(BIN)/math/find_fpenan.o
12
13 $(BIN)/math/find_func.o: $(SRC)/math/find_func.c
14 $(CC) $(CFLAGS) -c $(SRC)/math/find_func.c -o $(BIN)/math/find_func.o
15
16 $(BIN)/math/find_mfunc_cc.o: $(SRC)/math/find_mfunc_cc.c
17 $(CC) $(CFLAGS) -c $(SRC)/math/find_mfunc_cc.c -o $(BIN)/math/find_mfunc_cc.o
0 /*
1 scconfig - math feature detection
2 Copyright (C) 2013 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include "libs.h"
27 #include "log.h"
28 #include "db.h"
29 #include "dep.h"
30 #include "find_mfunc_cc.h"
31
32 #define MATHH "#include <math.h>"
33 int find_math_isnan(const char *name, int logdepth, int fatal)
34 {
35 char *test_c =
36 NL "int main() {"
37 NL " if (!isnan(1.0))"
38 NL " puts(\"OK\");"
39 NL " return 0;"
40 NL "}"
41 NL;
42
43 require("cc/cc", logdepth, fatal);
44
45 report("Checking for isnan... ");
46 logprintf(logdepth, "find_math_isnan: trying to find isnan...\n");
47 logdepth++;
48
49 if (try_icl(logdepth, "libs/math/isnan", test_c, MATHH, NULL, NULL)) return 0;
50 if (try_icl(logdepth, "libs/math/isnan", test_c, MATHH, NULL, "-lm")) return 0;
51 if (try_icl(logdepth, "libs/math/isnan", test_c, "#define _BSD_SOURCE\n" MATHH, NULL, NULL)) return 0;
52 if (try_icl(logdepth, "libs/math/isnan", test_c, "#define _BSD_SOURCE\n" MATHH, NULL, "-lm")) return 0;
53 if (try_icl(logdepth, "libs/math/isnan", test_c, "#define _XOPEN_SOURCE\n" MATHH, NULL, NULL)) return 0;
54 if (try_icl(logdepth, "libs/math/isnan", test_c, "#define _XOPEN_SOURCE\n" MATHH, NULL, "-lm")) return 0;
55
56 return try_fail(logdepth, "libs/math/isnan");
57 }
58
59 int find_math_isinf(const char *name, int logdepth, int fatal)
60 {
61 char *test_c =
62 NL "int main() {"
63 NL " if (!isinf(1.0))"
64 NL " puts(\"OK\");"
65 NL " return 0;"
66 NL "}"
67 NL;
68
69 require("cc/cc", logdepth, fatal);
70
71 report("Checking for isinf... ");
72 logprintf(logdepth, "find_math_isinf: try_icling to find isinf...\n");
73 logdepth++;
74
75 if (try_icl(logdepth, "libs/math/isinf", test_c, MATHH, NULL, NULL)) return 0;
76 if (try_icl(logdepth, "libs/math/isinf", test_c, MATHH, NULL, "-lm")) return 0;
77 if (try_icl(logdepth, "libs/math/isinf", test_c, "#define _BSD_SOURCE\n" MATHH, NULL, NULL)) return 0;
78 if (try_icl(logdepth, "libs/math/isinf", test_c, "#define _BSD_SOURCE\n" MATHH, NULL, "-lm")) return 0;
79 if (try_icl(logdepth, "libs/math/isinf", test_c, "#define _XOPEN_SOURCE\n" MATHH, NULL, NULL)) return 0;
80 if (try_icl(logdepth, "libs/math/isinf", test_c, "#define _XOPEN_SOURCE\n" MATHH, NULL, "-lm")) return 0;
81
82 return try_fail(logdepth, "libs/math/isinf");
83 }
84
85
86 int find_math_isfinite(const char *name, int logdepth, int fatal)
87 {
88 char *test_c =
89 NL "int main() {"
90 NL " if (isfinite(1.0))"
91 NL " puts(\"OK\");"
92 NL " return 0;"
93 NL "}"
94 NL;
95
96 require("cc/cc", logdepth, fatal);
97
98 report("Checking for isfinite... ");
99 logprintf(logdepth, "find_math_isfinite: try_icling to find isfinite...\n");
100 logdepth++;
101
102 if (try_icl(logdepth, "libs/math/isfinite", test_c, MATHH, NULL, NULL)) return 0;
103 if (try_icl(logdepth, "libs/math/isfinite", test_c, MATHH, NULL, "-lm")) return 0;
104 if (try_icl(logdepth, "libs/math/isfinite", test_c, "#define _BSD_SOURCE\n" MATHH, NULL, NULL)) return 0;
105 if (try_icl(logdepth, "libs/math/isfinite", test_c, "#define _BSD_SOURCE\n" MATHH, NULL, "-lm")) return 0;
106 if (try_icl(logdepth, "libs/math/isfinite", test_c, "#define _XOPEN_SOURCE\n" MATHH, NULL, NULL)) return 0;
107 if (try_icl(logdepth, "libs/math/isfinite", test_c, "#define _XOPEN_SOURCE\n" MATHH, NULL, "-lm")) return 0;
108
109 return try_fail(logdepth, "libs/math/isfinite");
110 }
111
112
113 int find_math_isnormal(const char *name, int logdepth, int fatal)
114 {
115 char *test_c =
116 NL "int main() {"
117 NL " if (isnormal(1.0))"
118 NL " puts(\"OK\");"
119 NL " return 0;"
120 NL "}"
121 NL;
122
123 require("cc/cc", logdepth, fatal);
124
125 report("Checking for isnormal... ");
126 logprintf(logdepth, "find_math_isnormal: try_icling to find isnormal...\n");
127 logdepth++;
128
129 if (try_icl(logdepth, "libs/math/isnormal", test_c, MATHH, NULL, NULL)) return 0;
130 if (try_icl(logdepth, "libs/math/isnormal", test_c, MATHH, NULL, "-lm")) return 0;
131 if (try_icl(logdepth, "libs/math/isnormal", test_c, "#define _BSD_SOURCE\n" MATHH, NULL, NULL)) return 0;
132 if (try_icl(logdepth, "libs/math/isnormal", test_c, "#define _BSD_SOURCE\n" MATHH, NULL, "-lm")) return 0;
133 if (try_icl(logdepth, "libs/math/isnormal", test_c, "#define _XOPEN_SOURCE\n" MATHH, NULL, NULL)) return 0;
134 if (try_icl(logdepth, "libs/math/isnormal", test_c, "#define _XOPEN_SOURCE\n" MATHH, NULL, "-lm")) return 0;
135 if (try_icl(logdepth, "libs/math/isnormal", test_c, "#define _ISOC99_SOURCE\n" MATHH, NULL, NULL)) return 0;
136 if (try_icl(logdepth, "libs/math/isnormal", test_c, "#define _ISOC99_SOURCE\n" MATHH, NULL, "-lm")) return 0;
137 if (try_icl(logdepth, "libs/math/isnormal", test_c, "#define _XOPEN_SOURCE 600\n" MATHH, NULL, NULL)) return 0;
138 if (try_icl(logdepth, "libs/math/isnormal", test_c, "#define _XOPEN_SOURCE 600\n" MATHH, NULL, "-lm")) return 0;
139
140 return try_fail(logdepth, "libs/math/isnormal");
141 }
142
143
144 int find_math_nan(const char *name, int logdepth, int fatal)
145 {
146 char *test_c =
147 NL "int main() {"
148 NL " if (nan(\"foo\") != 0.0)"
149 NL " puts(\"OK\");"
150 NL " return 0;"
151 NL "}"
152 NL;
153
154 require("cc/cc", logdepth, fatal);
155
156 report("Checking for nan... ");
157 logprintf(logdepth, "find_math_nan: try_icling to find nan...\n");
158 logdepth++;
159
160 if (try_icl(logdepth, "libs/math/nan", test_c, MATHH, NULL, NULL)) return 0;
161 if (try_icl(logdepth, "libs/math/nan", test_c, MATHH, NULL, "-lm")) return 0;
162 if (try_icl(logdepth, "libs/math/nan", test_c, "#define _ISOC99_SOURCE\n" MATHH, NULL, NULL)) return 0;
163 if (try_icl(logdepth, "libs/math/nan", test_c, "#define _ISOC99_SOURCE\n" MATHH, NULL, "-lm")) return 0;
164 if (try_icl(logdepth, "libs/math/nan", test_c, "#define _XOPEN_SOURCE 600\n" MATHH, NULL, NULL)) return 0;
165 if (try_icl(logdepth, "libs/math/nan", test_c, "#define _XOPEN_SOURCE 600\n" MATHH, NULL, "-lm")) return 0;
166
167 return try_fail(logdepth, "libs/math/nan");
168 }
169
170
171 int find_math_nanop(const char *name, int logdepth, int fatal)
172 {
173 char *test_c_temp =
174 NL "#include <stdlib.h>"
175 NL "#include <stdio.h>"
176 NL "%s"
177 NL
178 NL "double s2d(const char *s)"
179 NL "{"
180 NL " if (strcmp(s, \"nan\") == 0)"
181 NL " return nan(\"nan\");"
182 NL " return atof(s);"
183 NL "}"
184 NL "int main(int argc, char *argv[])"
185 NL "{"
186 NL " double op1, op2, res;"
187 NL " op1 = s2d(argv[1]);"
188 NL " op2 = s2d(argv[3]);"
189
190 NL " switch(*argv[2]) {"
191 NL " case '+': res = op1 + op2; break;"
192 NL " case '-': res = op1 - op2; break;"
193 NL " case 'M': res = op1 * op2; break;"
194 NL " case '/': res = op1 / op2; break;"
195 NL " }"
196 NL " if (isnan(res))"
197 NL " printf(\"nan\\n\");"
198 NL " else"
199 NL " printf(\"%%f\\n\", res);"
200 NL " return 0;"
201 NL "}"
202 NL;
203 char test_c[2048];
204 char *inc, *test_bin, *test_bin_esc, *out, *s, *cmd = test_c;
205 char *tests[] = {
206 "%s 1 + 1", "2.0", NULL,
207 "%s nan + 1", "nan", "add",
208 "%s nan - 1", "nan", "sub",
209 "%s nan M 1", "nan", "multiply",
210 "%s nan / 1", "nan", "divide",
211 NULL, NULL
212 };
213 char **test;
214 int bad = 0;
215
216 require("libs/math/nan/presents", logdepth, fatal);
217 require("libs/math/isnan/presents", logdepth, fatal);
218 require("cc/cc", logdepth, fatal);
219 if (!istrue(get("libs/math/isnan/presents")) || !istrue(get("libs/math/nan/presents")))
220 return try_fail(logdepth, "libs/math/nanop/presents");
221
222 inc = esc_interpret(get("libs/math/isnan/includes"));
223 sprintf(test_c, test_c_temp, inc);
224 free(inc);
225
226 report("Checking for nanop... ");
227 logprintf(logdepth, "find_math_nan: try_icling to find nan...\n");
228 logdepth++;
229
230 test_bin = NULL;
231 if (compile_code(logdepth, test_c, &test_bin, NULL, get("libs/math/nan/cflags"), get("libs/math/nan/ldflags")) != 0)
232 return try_fail(logdepth, "libs/math/nanop/presents");
233 report("found\n");
234
235 test_bin_esc = shell_escape_dup(test_bin);
236 for(test = tests; *test != NULL; test += 3) {
237 report(test[0], "");
238 report("... ");
239 sprintf(cmd, test[0], test_bin_esc);
240 run(logdepth, cmd, &out);
241 if (test[2] != NULL)
242 sprintf(cmd, "libs/math/nanop/%s", test[2]);
243 if (out != NULL) {
244 if (target_emu_fail(out) || (test[1] == NULL) || (strncmp(out, test[1], strlen(test[1])) == 0)) {
245 report("OK (%s)\n", test[1]);
246 if (test[2] != NULL)
247 put(cmd, test[1]);
248 }
249 else {
250 report("? (");
251 for(s = out; *s != '\0'; s++)
252 if ((*s == '\n') || (*s == '\r'))
253 *s = ' ';
254 report(out);
255 report(")\n");
256 if (test[2] != NULL)
257 put(cmd, out);
258 bad = 1;
259 }
260 free(out);
261 }
262 else
263 bad = 1;
264 }
265
266 if (bad)
267 put("libs/math/nanop/allok", sfalse);
268 else
269 put("libs/math/nanop/allok", strue);
270
271 put("libs/math/nanop/presents", strue);
272
273 unlink(test_bin);
274 free(test_bin);
275 free(test_bin_esc);
276 return 0;
277 }
278
0 int find_math_isnan(const char *name, int logdepth, int fatal);
1 int find_math_isinf(const char *name, int logdepth, int fatal);
2 int find_math_isfinite(const char *name, int logdepth, int fatal);
3 int find_math_isnormal(const char *name, int logdepth, int fatal);
4 int find_math_nan(const char *name, int logdepth, int fatal);
5 int find_math_nanop(const char *name, int logdepth, int fatal);
6
0 /*
1 scconfig - math feature detection
2 Copyright (C) 2015 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "db.h"
28 #include "dep.h"
29
30 #define MATHH "#include <math.h>"
31
32 static int test_mathf(const char *name, int logdepth, int fatal, const char *fname, const char *cond)
33 {
34 char *test_c_template =
35 NL "float one=1.0, zero=0.0;"
36 NL "int main() {"
37 NL " if (%s)"
38 NL " puts(\"OK\");"
39 NL " return 0;"
40 NL "}"
41 NL;
42
43 char test_c[512];
44 char node_name[128];
45
46 sprintf(test_c, test_c_template, cond);
47 sprintf(node_name, "libs/math/%s", fname);
48
49 require("cc/cc", logdepth, fatal);
50
51 report("Checking for %s... ", fname);
52 logprintf(logdepth, "test_mathf: trying to find %s...\n",fname);
53 logdepth++;
54
55
56 if (try_icl(logdepth, node_name, test_c, MATHH, NULL, NULL)) return 0;
57 if (try_icl(logdepth, node_name, test_c, MATHH, NULL, "-lm")) return 0;
58 if (try_icl(logdepth, node_name, test_c, "#define _BSD_SOURCE\n" MATHH, NULL, NULL)) return 0;
59 if (try_icl(logdepth, node_name, test_c, "#define _BSD_SOURCE\n" MATHH, NULL, "-lm")) return 0;
60 if (try_icl(logdepth, node_name, test_c, "#define _XOPEN_SOURCE\n" MATHH, NULL, NULL)) return 0;
61 if (try_icl(logdepth, node_name, test_c, "#define _XOPEN_SOURCE\n" MATHH, NULL, "-lm")) return 0;
62
63 return try_fail(logdepth, node_name);
64 }
65
66 int find_math_expf(const char *name, int logdepth, int fatal)
67 {
68 return test_mathf(name, logdepth, fatal, "expf", "expf(zero) == 1.0");
69 }
70
71
72 int find_math_logf(const char *name, int logdepth, int fatal)
73 {
74 return test_mathf(name, logdepth, fatal, "logf", "logf(one) == 0.0");
75 }
76
77 int find_math_rint(const char *name, int logdepth, int fatal)
78 {
79 return test_mathf(name, logdepth, fatal, "rint", "rint(4.0) == 4.0");
80 }
81
82 int find_math_round(const char *name, int logdepth, int fatal)
83 {
84 return test_mathf(name, logdepth, fatal, "round", "round(3.6) == 4.0");
85 }
0 int find_math_expf(const char *name, int logdepth, int fatal);
1 int find_math_logf(const char *name, int logdepth, int fatal);
2 int find_math_rint(const char *name, int logdepth, int fatal);
3 int find_math_round(const char *name, int logdepth, int fatal);
0 /*
1 scconfig - math feature detection
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "db.h"
28 #include "dep.h"
29 #include "find_func.h"
30 #include "find_mfunc_cc.h"
31 #include "find_fpenan.h"
32
33 int find_math_minpack(const char *name, int logdepth, int fatal)
34 {
35 char *test_c =
36 NL "int main() {"
37 NL " int one=1;"
38 NL " if (dpmpar_(&one) != 0.0)"
39 NL " puts(\"OK\");"
40 NL " return 0;"
41 NL "}"
42 NL;
43
44 require("cc/cc", logdepth, fatal);
45
46 report("Checking for minpack... ");
47 logprintf(logdepth, "find_math_minpack: trying to find minpack...\n");
48 logdepth++;
49
50 /* Look at the standard places */
51 if (try_icl(logdepth, "libs/math/minpack", test_c, "#include <minpack.h>", NULL, "-lminpack")) return 0;
52
53 return try_fail(logdepth, "libs/math/minpack");
54 }
55
56
57 void deps_math_init()
58 {
59 dep_add("libs/math/minpack/*", find_math_minpack);
60 dep_add("libs/math/cc/log/*", find_math_cc_log);
61 dep_add("libs/math/isnan/*", find_math_isnan);
62 dep_add("libs/math/isinf/*", find_math_isinf);
63 dep_add("libs/math/isfinite/*", find_math_isfinite);
64 dep_add("libs/math/isnormal/*", find_math_isnormal);
65 dep_add("libs/math/nan/*", find_math_nan);
66 dep_add("libs/math/nanop/*", find_math_nanop);
67
68 dep_add("libs/math/expf/*", find_math_expf);
69 dep_add("libs/math/logf/*", find_math_logf);
70 dep_add("libs/math/rint/*", find_math_rint);
71 dep_add("libs/math/round/*", find_math_round);
72 }
0 /*
1 scconfig - math func corner case detection
2 Copyright (C) 2012 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <unistd.h>
27 #include "libs.h"
28 #include "log.h"
29 #include "db.h"
30 #include "dep.h"
31
32 static char *test_c_templ =
33 NL "#include <stdio.h>"
34 NL "#include <math.h>"
35 NL "#include <errno.h>"
36 NL "int main(int argc, char *argv[]) {"
37 NL " double magic[] = { %s };"
38 NL " errno = 0;\n"
39 NL " printf(\"%%f:%%d\\n\", %s(magic[atoi(argv[1])]), errno);"
40 NL " return 0;"
41 NL "}"
42 NL;
43
44 /* returns 0 if couldn't run (emu), -1 on error and 1 when got enough results */
45 static int try(int logdepth, const char *func, const char *values, char **res, int num_res)
46 {
47 char *test_c, *fn = NULL, *fn_esc, *cmd, *out;
48 int n, len;
49
50 len = strlen(test_c_templ) + strlen(func) + strlen(values) + 1;
51 test_c = malloc(len);
52 sprintf(test_c, test_c_templ, values, func);
53
54 logprintf(logdepth, "testing '%s' on '%s'\n", func, values);
55
56 if (compile_code(logdepth+1, test_c, &fn, NULL, NULL, "-lm") != 0) {
57 free(test_c);
58 return -1;
59 }
60 free(test_c);
61
62 if (isblind(db_cwd)) {
63 /* assume corner cases passed as we have nothing better to do */
64 for(n = 0; n < num_res; n++)
65 res[n] = strclone("unknown");
66 unlink(fn);
67 free(fn);
68 return 0;
69 }
70
71 fn_esc = shell_escape_dup(fn);
72 cmd = malloc(strlen(fn_esc) + 32);
73 for(n = 0; n < num_res; n++) {
74 sprintf(cmd, "%s %d", fn_esc, n);
75 if (run(logdepth+1, cmd, &out) == 0) {
76 char *s, *dot = NULL;
77 int is_int = 1;
78 for(s = out; *s != '\0'; s++) {
79 switch(*s) {
80 case '\n':
81 case '\r':
82 *s = '\0';
83 goto at_end;
84 case '.':
85 dot = s;
86 break;
87 default:
88 if ((dot != NULL) && (*s != '0'))
89 is_int = 0;
90 *s = tolower(*s);
91 }
92 }
93 at_end:;
94 if ((is_int) && (dot != NULL))
95 *dot = '\0';
96 if (*out == '+')
97 res[n] = strclone(out+1);
98 else
99 res[n] = strclone(out);
100 free(out);
101 }
102 else
103 res[n] = strclone("fpe");
104 }
105 free(cmd);
106 free(fn_esc);
107 unlink(fn);
108 free(fn);
109 return 1;
110 }
111
112
113 static int find_math_cc(const char *name, int logdepth, int fatal, char *func, char *inp, char **node_names, int num_tests)
114 {
115 char *res[256];
116 char node_name[256];
117 int n, ret;
118
119 ret = 0;
120 require("cc/cc", logdepth, fatal);
121
122 report("Checking for %s() corner cases... ", func);
123 logprintf(logdepth, "find_math_cc_log: Checking for %s() corner cases... \n", func);
124 logdepth++;
125
126 if (try(logdepth, func, inp, res, num_tests) >= 0) {
127 for(n = 0; n < num_tests; n++) {
128 char *sep;
129 report(".");
130 sep = strchr(res[n], ':');
131 if (sep != NULL) {
132 *sep = 0;
133 sep++;
134 sprintf(node_name, "libs/math/cc/%s/%s/return", func, node_names[n]);
135 put(node_name, res[n]);
136 sprintf(node_name, "libs/math/cc/%s/%s/errno", func, node_names[n]);
137 put(node_name, sep);
138 }
139 else
140 ret = 1;
141 }
142 }
143
144 /* avoid redetection */
145 sprintf(node_name, "libs/math/cc/%s/presents", func);
146 put(node_name, strue);
147
148
149 report(ret ? "done with errors\n" : " done.\n");
150 return ret;
151 }
152
153 int find_math_cc_log(const char *name, int logdepth, int fatal)
154 {
155 char *inp = "+0.0, -0.0, 1.0, -1.0, 1/0.0";
156 char *nodes[] = {"p_0", "m_0", "p_1", "m_1", "p_inf"};
157 return find_math_cc(name, logdepth, fatal, "log", inp, nodes, sizeof(nodes) / sizeof(char *));
158 }
0 int find_math_cc_log(const char *name, int logdepth, int fatal);
0 deps_parsgen_init();
1
0 void deps_parsgen_init();
0 PARSGEN_CFLAGS = -DPLUGIN_PARSGEN
1 PARSGEN_OBJS = \
2 $(BIN)/parsgen/find_parsgen.o
3
4 $(BIN)/parsgen/find_parsgen.o: $(SRC)/parsgen/find_parsgen.c
5 $(CC) $(CFLAGS) -c $(SRC)/parsgen/find_parsgen.c -o $(BIN)/parsgen/find_parsgen.o
0 /*
1 scconfig - parser generator detection
2 Copyright (C) 2009 Tibor Palinkas
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Project page: http://repo.hu/projects/scconfig
19 Contact via email: scconfig [at] igor2.repo.hu
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "libs.h"
26 #include "log.h"
27 #include "db.h"
28 #include "dep.h"
29
30 int find_parsgen_flex(const char *name, int logdepth, int fatal)
31 {
32 const char *test_flex =
33 NL "%%"
34 NL "foo { return 1; }"
35 NL "%%"
36 NL ;
37 char *out, *temp_in, *temp_in_esc, *cmd;
38 int ret;
39 char *lexfile = "lex.yy.c";
40 (void) fatal; /* not used */
41
42 report("Checking for flex... ");
43 logprintf(logdepth, "find_flex: trying to find flex...\n");
44 logdepth++;
45
46 if (is_file(lexfile)) {
47 report("ERROR: %s exists, and I don't dare to delete it. Can't test flex, please remove the file by hand.\n", lexfile);
48 logprintf(logdepth, "ERROR: %s exists, and I don't dare to delete it. Can't test flex, please remove the file by hand.\n", lexfile);
49 exit(1);
50 }
51 temp_in = tempfile_dump(test_flex, ".lex");
52 temp_in_esc = shell_escape_dup(temp_in);
53 cmd = malloc(strlen(temp_in_esc) + 16);
54 sprintf(cmd, "flex %s", temp_in_esc);
55 free(temp_in_esc);
56 ret = run(logdepth, cmd, &out);
57 remove(temp_in);
58 free(temp_in);
59 if (out != NULL)
60 free(out);
61
62 if (is_file(lexfile)) {
63 remove(lexfile);
64 if (ret == 0) {
65 put("parsgen/flex", "flex");
66 put("parsgen/flex/presents", strue);
67 report("Found.\n");
68 return 0;
69 }
70 }
71
72 put("parsgen/flex/presents", sfalse);
73 report("Not found.\n");
74 return 1;
75 }
76
77 int find_parsgen_bison(const char *name, int logdepth, int fatal)
78 {
79 const char *test_bison =
80 NL "%union { char *str; double num;}"
81 NL "%%"
82 NL "%token <str> TOK1;"
83 NL "%token <num> TOK2;"
84 NL "root: one | two;"
85 NL "one: TOK1;"
86 NL "two: TOK2;"
87 NL ;
88 char *out, *temp_in, *temp_in_esc, *cmd;
89 int ret;
90 char *bisfile, *s;
91 (void) fatal; /* not used */
92
93 report("Checking for bison... ");
94 logprintf(logdepth, "find_bison: trying to find bison...\n");
95 logdepth++;
96
97 temp_in = tempfile_dump(test_bison, ".y");
98 bisfile = malloc(strlen(temp_in) + 32);
99 strcpy(bisfile, temp_in);
100 s = strrchr(bisfile+1, '.');
101 strcpy(s, ".tab.c");
102 if (is_file(bisfile)) {
103 report("ERROR: %s exists, and I don't dare to delete it. Can't test bison, please remove the file by hand.\n", bisfile);
104 logprintf(logdepth, "ERROR: %s exists, and I don't dare to delete it. Can't test bison, please remove the file by hand.\n", bisfile);
105 exit(1);
106 }
107 temp_in_esc = shell_escape_dup(temp_in);
108 cmd = malloc(strlen(temp_in_esc) + 16);
109 sprintf(cmd, "bison %s", temp_in_esc);
110 free(temp_in_esc);
111
112
113 ret = run(logdepth, cmd, &out);
114 remove(temp_in);
115 free(temp_in);
116 if (out != NULL)
117 free(out);
118
119 if (is_file(bisfile)) {
120 remove(bisfile);
121 if (ret == 0) {
122 put("parsgen/bison", "bison");
123 put("parsgen/bison/presents", strue);
124 report("Found.\n");
125 return 0;
126 }
127 }
128
129 put("parsgen/bison/presents", sfalse);
130 report("Not found.\n");
131 return 1;
132 }
133
134 void deps_parsgen_init()
135 {
136 dep_add("parsgen/flex/*", find_parsgen_flex);
137 dep_add("parsgen/bison/*", find_parsgen_bison);
138 }
0 CFLAGS = -Wall -g \
1 -I../default -DTMPASM_TESTER \
2
3 tester: tester.o tmpasm.o debug.o tmpasm_scconfig.o openfiles.o \
4 ../default/db.o ../default/ht.o ../default/str.o ../default/log.o \
5 ../default/regex.o ../default/lib_uniqinc.o
6
7 tmpasm.o: tmpasm.c tmpasm.h
8
9 test: regression/Makefile
10 cd regression && make
11
12 regression/Makefile: regression/Makefile.in tester
13 ./tester -e < regression/Makefile.in > regression/Makefile
14
15 debug.o: debug.c debug.h tmpasm.h
0 TMPASM_OBJS = \
1 $(BIN)/tmpasm/tmpasm.o \
2 $(BIN)/tmpasm/tmpasm_scconfig.o \
3 $(BIN)/tmpasm/openfiles.o
4
5 TMPASM_CFLAGS = -I$(SRC)/tmpasm
6
7 $(BIN)/tmpasm/tmpasm.o: $(SRC)/tmpasm/tmpasm.c $(SRC)/tmpasm/tmpasm.h $(SRC)/default/dep.h $(SRC)/default/log.h $(SRC)/default/regex.h
8 $(CC) $(CFLAGS) -c $(SRC)/tmpasm/tmpasm.c -o $(BIN)/tmpasm/tmpasm.o
9
10 $(BIN)/tmpasm/tmpasm_scconfig.o: $(SRC)/tmpasm/tmpasm_scconfig.c $(SRC)/tmpasm/tmpasm.h $(SRC)/default/libs.h $(SRC)/default/log.h $(SRC)/default/regex.h
11 $(CC) $(CFLAGS) -c $(SRC)/tmpasm/tmpasm_scconfig.c -o $(BIN)/tmpasm/tmpasm_scconfig.o
12
13 $(BIN)/tmpasm/openfiles.o: $(SRC)/tmpasm/openfiles.c
14 $(CC) $(CFLAGS) -c $(SRC)/tmpasm/openfiles.c -o $(BIN)/tmpasm/openfiles.o
15
0 - regression test syntax errors and improve syntax error reporting
1 - switch:
2 - data instead of case
3 - multiple defaults
4 - deafult must be at end of the list
5 - case out of switch
6 - default out of switch
7 - forarch
8 - tutorial
9 - append
10 - [[]] eval? what's the output? -> generate and include scripts (may need mktemp binding)
11 - update docs
0 #include <stdio.h>
1 #include "tmpasm.h"
2
3 static void indent(FILE *f, int depth)
4 {
5 for(;depth > 0; depth--) fputc(' ', f);
6 }
7
8 static void print_arg(FILE *f, tmpasm_arg_t *a)
9 {
10 if (a == NULL) {
11 fprintf(f, "*NULL - broken AST*");
12 return;
13 }
14 if (a->next != NULL) {
15 /* block mode */
16 fprintf(f, "[~");
17 for(;a != NULL; a = a->next) {
18 if (a->is_addr)
19 fprintf(f, "~%s~", a->data);
20 else
21 fprintf(f, "%s", a->data);
22 }
23 fprintf(f, "~]");
24 }
25 else {
26 if (a->is_addr)
27 fprintf(f, "%s", a->data);
28 else
29 fprintf(f, "{%s}", a->data);
30 }
31 }
32
33 static void print_loc(FILE *f, tmpasm_exec_t *c)
34 {
35 if ((c->line != 0) || (c->col != 0))
36 fprintf(f, " [at %d:%d]\n", c->line, c->col);
37 else
38 fprintf(f, "\n");
39 }
40
41 static void dump(FILE *f, int depth, tmpasm_exec_t *c)
42 {
43 tmpasm_case_t *cc;
44 int n;
45 for(; c != NULL; c = c->next) {
46 switch(c->kw) {
47 case KW_NOP:
48 indent(f, depth);
49 fprintf(f, "(NOP)");
50 print_loc(f, c);
51 break;
52 case KW_none:
53 indent(f, depth);
54 fprintf(f, "%s", c->payload.instr.call_name);
55 print_loc(f, c);
56 for(n = 0; n < c->payload.instr.argc; n++) {
57 indent(f, depth+1);
58 fprintf(f, "arg: ");
59 print_arg(f, c->payload.instr.argv[n]);
60 fprintf(f, "\n");
61 }
62 break;
63 case KW_IF:
64 indent(f, depth);
65 fprintf(f, "if ");
66 print_arg(f, c->payload.fc_if.cond);
67 print_loc(f, c);
68 indent(f, depth);
69 fprintf(f, "then:\n");
70 dump(f, depth+1, c->payload.fc_if.code_then);
71 indent(f, depth);
72 fprintf(f, "else:\n");
73 dump(f, depth+1, c->payload.fc_if.code_else);
74 break;
75 case KW_FOREACH:
76 indent(f, depth);
77 fprintf(f, "foreach %s in ", c->payload.fc_foreach.loop_var);
78 print_arg(f, c->payload.fc_foreach.data);
79 print_loc(f, c);
80 dump(f, depth+1, c->payload.fc_foreach.code_body);
81 break;
82 case KW_SWITCH:
83 indent(f, depth);
84 fprintf(f, "switch ");
85 print_arg(f, c->payload.fc_switch.cond);
86 print_loc(f, c);
87 for(cc = c->payload.fc_switch.first; cc != NULL; cc = cc->next) {
88 indent(f, depth+1);
89 if (cc->data != NULL) {
90 fprintf(f, "case ");
91 print_arg(f, cc->data);
92 fprintf(f, "\n");
93 }
94 else
95 printf("default\n");
96 dump(f, depth+2, cc->body);
97 }
98 break;
99 default:
100 indent(f, depth);
101 fprintf(f, "invalid kw ");
102 print_loc(f, c);
103 }
104 }
105 }
106
107 void tmpasm_dump(tmpasm_t *ctx, FILE *f)
108 {
109 dump(f, 0, ctx->code);
110 }
0 void tmpasm_dump(tmpasm_t *ctx, FILE *f);
1
0 #include <stdlib.h>
1 #include <string.h>
2 #include "openfiles.h"
3 #include "libs.h"
4
5 static openfile_t *find_file_by_name(openfiles_t *of, const char *name, int alloc, const char *mode, int recursion)
6 {
7 int n;
8 struct stat buf;
9 FILE *f;
10
11 if (recursion > 4) {
12 fprintf(stderr, "scconfig internal error: openfiles infinite recursion for %s\n", name);
13 abort();
14 }
15
16 if (stat(name, &buf) != 0) {
17 /* File does not exist - try to create it or return NULL */
18 if (*mode == 'w') {
19 f = fopen(name, "w");
20 if (f == NULL)
21 return NULL;
22 fclose(f);
23 return find_file_by_name(of, name, alloc, mode, recursion + 1);
24 }
25 return NULL;
26 }
27
28 /* look for an existing open file in the list */
29 for(n = 0; n < of->used; n++)
30 if ((of->files[n].dev == buf.st_dev) && (of->files[n].ino == buf.st_ino) && (strcmp(of->files[n].mode, mode) == 0))
31 return &(of->files[n]);
32
33 if (!alloc)
34 return NULL;
35
36 /* File exists but not on the list yet, allocate a new slot for it */
37 /* TODO: try to find an empty slot first */
38 if (of->used >= of->alloced) {
39 of->alloced += 16;
40 of->files = realloc(of->files, sizeof(openfile_t) * of->alloced);
41 }
42
43 n = of->used;
44 of->files[n].dev = buf.st_dev;
45 of->files[n].ino = buf.st_ino;
46 of->files[n].f = NULL;
47 of->files[n].mode = strclone(mode);
48 of->used++;
49 return &(of->files[n]);
50 }
51
52 void release(openfile_t *o)
53 {
54 if (o->mode != NULL) {
55 free(o->mode);
56 o->mode = NULL;
57 }
58 if (o->f != NULL) {
59 fclose(o->f);
60 o->f = NULL;
61 }
62 o->dev = -1;
63 o->ino = -1;
64 }
65
66 FILE *openfile_open(openfiles_t *of, const char *fn, const char *mode)
67 {
68 openfile_t *o;
69 o = find_file_by_name(of, fn, 1, mode, 0);
70 if (o == NULL)
71 return NULL;
72 o->f = fopen(fn, mode);
73 if (o->f == NULL) {
74 release(o);
75 return NULL;
76 }
77 return o->f;
78 }
79
80 void openfile_closeall(openfiles_t *of)
81 {
82 int n;
83 if (of->files == NULL)
84 return;
85 for(n = 0; n < of->used; n++)
86 release(&(of->files[n]));
87 }
88
89 void openfile_free(openfiles_t *of)
90 {
91 openfile_closeall(of);
92 if (of->files != NULL)
93 free(of->files);
94 }
0 #include <stdio.h>
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <unistd.h>
4
5 typedef struct openfile_s {
6 FILE *f;
7
8 /* identify the file: */
9 dev_t dev;
10 ino_t ino;
11
12 char *mode;
13 } openfile_t;
14
15 typedef struct openfiles_s {
16 int alloced, used;
17 openfile_t *files;
18 } openfiles_t;
19
20 FILE *openfile_open(openfiles_t *of, const char *fn, const char *mode);
21 void openfile_closeall(openfiles_t *of);
22 void openfile_free(openfiles_t *of);
0 # list of tests
1 put tests [@
2 Tutor01_hello
3 Tutor02_vars
4 Tutor03_blocks
5 Tutor04_if
6 Tutor05_switch
7 Tutor06_foreach
8 Tutor07_sub
9 Tutor08_uniq
10 Tutor09_ui
11 Tutor10_include_redir
12 Tutor11_missing
13 Tutor12_halt
14 comment
15 foreach
16 if
17 switch
18 test
19 then
20 append
21 order
22 err_if_end
23 err_if_else
24 err_excess_end
25 err_switch_end
26 err_switch_nocond
27 err_no_end
28 @]
29
30 uniq tests
31
32 put test_diffs tests
33 gsub test_diffs {[ \t\r\n]+} { }
34 gsub test_diffs {\\>} {.diff}
35 # TODO: replace this with wrap
36 sub test_diffs {^ *} {}
37 sub test_diffs { *$} {}
38
39 print [@### PLEASE DO NOT EDIT THIS FILE, it has been generated from Makefile.in. ###
40
41 TESTER=../tester
42
43 all: @test_diffs@
44
45 # Explicit test rules
46 @]
47
48 foreach test in tests
49 print [@
50 @test@.out: @test@.gasm $(TESTER) Makefile
51 $(TESTER) < @test@.gasm > @test@.out 2>&1
52
53 @test@.diff: @test@.ref @test@.out
54 diff -u @test@.ref @test@.out
55 @]
56 end
0 # Comments start with # and end at the end of the line; comments
1 # can be started anywhere outside of strings and blocks
2
3 # Print will print each argument without appending a newline. An argument
4 # is a data, string literals are written in brace. Escape sequences
5 # are as usual
6 print {hello world!\n}
7
8 # Print doesn't have any hidden side effect: no separators printed
9 # between arguments
10 print {hello} {world!} {\n}
11
12 # Print works without an argument as well: it just prints nothing
13 print
14
15 # instructions are separated by newlines and/or semicolons:
16 print {HELLO}; print { WORLD!};;;; print {\n};
17
0 print [at 7:1]
1 arg: {hello world!
2 }
3 print [at 11:1]
4 arg: {hello}
5 arg: {world!}
6 arg: {
7 }
8 print [at 14:1]
9 print [at 17:1]
10 arg: {HELLO}
11 print [at 17:16]
12 arg: { WORLD!}
13 print [at 17:36]
14 arg: {
15 }
0 # Variables are stored in a hash. Variable names follow the normal
1 # identifier rules with less restrictions (can start with number)
2 # To set the value of a variable, use: put var value
3 put myvar {Hello world!\n}
4
5 # Referencing the variable is done by using its name
6 print myvar
7
8 # In most context arguments are data; data can be both string literal and
9 # variable reference:
10 print {Hello universe! } myvar
11
12 # the second var of put is just data, can be string or variable; copying
13 # a variable:
14 put str {cats raining from the sky}
15 put tmp str
16 print str {==} tmp {\n}
17
18 # the ? prefix results in empty string if a variable doesnt exist, instead
19 # of throwing a runtime error
20 print {safe get: '} ?nonexist {'\n}
21
22 # the & prefix evaluates to "true" or "false" depending on whether the node
23 # exists in the tree or not
24 print {exists (no): } &nonexist {\n}
25 print {exists (yes): } &myvar {\n}
0 put [at 4:1]
1 arg: myvar
2 arg: {Hello world!
3 }
4 print [at 7:1]
5 arg: myvar
6 print [at 11:1]
7 arg: {Hello universe! }
8 arg: myvar
9 put [at 15:1]
10 arg: str
11 arg: {cats raining from the sky}
12 put [at 16:1]
13 arg: tmp
14 arg: str
15 print [at 17:1]
16 arg: str
17 arg: {==}
18 arg: tmp
19 arg: {
20 }
21 print [at 21:1]
22 arg: {safe get: '}
23 arg: ?nonexist
24 arg: {'
25 }
26 print [at 25:1]
27 arg: {exists (no): }
28 arg: &nonexist
29 arg: {
30 }
31 print [at 26:1]
32 arg: {exists (yes): }
33 arg: &myvar
34 arg: {
35 }
0 # Blocks are special syntax to make it easier to handle large,
1 # to-be-printed-verbatim blocks of data, which is essential in a template
2 # language. Blocks are enclosed in [$ $], where $ is an arbitrary character
3 # that shall be chosen by the programmer, per block; once a characher is
4 # chosen, it can not appear in the string. There is no backslash escaping
5 # in blocks. Blocks can be used anywhere where strings could be used.
6 print [@this is a string@] {\n}
7
8 print {--\n}
9
10 put myblk [!a block
11 of multiline
12 data.
13 !]
14
15 print myblk
16
17 # A special feature of the block is inline variable substitution using the same
18 # separator character chosen at the opening brace. In the example below
19 # myvar is substituted because it is sorrounded by the separator (@ in
20 # the first case and $ in the second case). Whitespace and newlines
21 # are preserved in the block, even in the inline variable name!
22
23 put myvar {world}
24 print {--\n}
25 print [@ hello @myvar@! @] {\n}
26 print {--\n}
27 print [$
28 hi @myvar@!
29 $]
30 print {--\n}
0 print [at 7:1]
1 arg: {this is a string}
2 arg: {
3 }
4 print [at 9:1]
5 arg: {--
6 }
7 put [at 11:1]
8 arg: myblk
9 arg: {a block
10 of multiline
11 data.
12 }
13 print [at 16:1]
14 arg: myblk
15 put [at 24:1]
16 arg: myvar
17 arg: {world}
18 print [at 25:1]
19 arg: {--
20 }
21 print [at 26:1]
22 arg: [~ hello ~myvar~! ~]
23 arg: {
24 }
25 print [at 27:1]
26 arg: {--
27 }
28 print [at 28:1]
29 arg: {
30 hi @myvar@!
31 }
32 print [at 31:1]
33 arg: {--
34 }
0 put myvar {true}
1
2 # The simplest flow control is an if. It takes its first argument and
3 # calls the environment to decide if it is true or false. If it's true
4 # the "then" branch is executed, if it's false, the "else" branch runs.
5 if myvar then
6 print {myvar is true (1)\n}
7 else
8 print {myvar is false (1)\n}
9 end
10
11
12 # it is possible to omit the else branch
13 if myvar then
14 print {myvar is true (2)\n}
15 end
16
17 # the then branch may be empty:
18 if myvar then else
19 print {myvar is false (3)\n}
20 end
21
22 # embedding controls is legal:
23 put foo {false}
24 if myvar then
25 if foo then
26 print {myvar and bar are true (4)\n}
27 else
28 print {myvar is true, bar is false (4)\n}
29 end
30 end
0 put [at 1:1]
1 arg: myvar
2 arg: {true}
3 if myvar [at 6:10]
4 then:
5 print [at 7:2]
6 arg: {myvar is true (1)
7 }
8 else:
9 print [at 9:2]
10 arg: {myvar is false (1)
11 }
12 if myvar [at 14:10]
13 then:
14 print [at 15:2]
15 arg: {myvar is true (2)
16 }
17 else:
18 (NOP)
19 if myvar [at 19:10]
20 then:
21 (NOP)
22 else:
23 print [at 20:2]
24 arg: {myvar is false (3)
25 }
26 put [at 24:1]
27 arg: foo
28 arg: {false}
29 if myvar [at 25:10]
30 then:
31 if foo [at 26:9]
32 then:
33 print [at 27:3]
34 arg: {myvar and bar are true (4)
35 }
36 else:
37 print [at 29:3]
38 arg: {myvar is true, bar is false (4)
39 }
40 else:
41 (NOP)
0 # Switch is similar to case in posix shell and switch in C. It takes a
1 # data argument and matches is against cases until the first match. It
2 # executes the code for that match and stops executing the switch (unlike
3 # in C, and like in sh, there is no fall-thru). A default case can be
4 # defined as a catch-all rule.
5 #
6 # Scconfig uses regex matching (unlike sh (shell globbing) and C (integer)).
7 #
8 # The first word after the switch keyword is the string that is matched
9 # against case patterns; the first word after a case is the pattern
10 # the string is matched against. Each branch must be terminated by an "end",
11 # just as the whole switch. Default doesn't have pattern, instructions start
12 # immediately.
13
14 put myvar {foobar}
15 switch myvar
16 case {baz} put res {1}; print {this is baz.\n}; end;
17 case {^oob} put res {2}; print {did you mean out-of-band?\n}; end;
18 case {^f} put res {3}; print {starts with f.\n}; end;
19 case {oob} put res {4}; print {OOB!\n}; end;
20 default put res {0}; print {none.\n}; end;
21 end;
22
23 print {result is: } res {\n}
24
25
26 # data is data - can be block as well, anywhere, in switch or case:
27 put patt {^number$}
28 put REF {3}
29 switch [@num @res@ ber@]
30 case patt print {empty\n}; end;
31 case [!^num !REF!!] print {reference\n}; end;
32 end
33
34 # one of the uses of switch is to construct an if-then-else that uses
35 # matching instead of checking for true/false; the following example
36 # demonstrates how an "if cond matches {lob}" is done with switch.
37 put cond {blobb}
38 switch cond
39 case {lob} print {"then"\n}; end
40 default print {"else"\n}; end
41 end
0 put [at 15:1]
1 arg: myvar
2 arg: {foobar}
3 switch myvar [at 16:1]
4 case {baz}
5 put [at 17:14]
6 arg: res
7 arg: {1}
8 print [at 17:27]
9 arg: {this is baz.
10 }
11 case {^oob}
12 put [at 18:14]
13 arg: res
14 arg: {2}
15 print [at 18:27]
16 arg: {did you mean out-of-band?
17 }
18 case {^f}
19 put [at 19:14]
20 arg: res
21 arg: {3}
22 print [at 19:27]
23 arg: {starts with f.
24 }
25 case {oob}
26 put [at 20:14]
27 arg: res
28 arg: {4}
29 print [at 20:27]
30 arg: {OOB!
31 }
32 default
33 put [at 21:14]
34 arg: res
35 arg: {0}
36 print [at 21:27]
37 arg: {none.
38 }
39 print [at 24:1]
40 arg: {result is: }
41 arg: res
42 arg: {
43 }
44 put [at 28:1]
45 arg: patt
46 arg: {^number$}
47 put [at 29:1]
48 arg: REF
49 arg: {3}
50 switch [~num ~res~ ber~] [at 30:1]
51 case patt
52 print [at 31:23]
53 arg: {empty
54 }
55 case [~^num ~REF~~]
56 print [at 32:23]
57 arg: {reference
58 }
59 put [at 38:1]
60 arg: cond
61 arg: {blobb}
62 switch cond [at 39:1]
63 case {lob}
64 print [at 40:15]
65 arg: {"then"
66 }
67 default
68 print [at 41:15]
69 arg: {"else"
70 }
0 # The only loop tmpasm implements is a foreach that iterates on a list.
1 # How the list is split into items is up to the environment. In scconfig
2 # the list is white space separated by default. The word following foreach
3 # must be the name of a variable (that will be set to the next item before
4 # each iteration). The word after "in" is data (string, variable, block).
5
6 foreach item in {this is a list of words}
7 print item {\n}
8 end
9
10 # Like any other control, foreach can be nested. The following
11 # example will iterate item on foo, bar and baz, printing 3 words
12 # for each from a block: {next:}, the item and a newline. The newline
13 # is specified as a vairable since \ escaping does not work in blocks.
14 put nl {\n}
15 foreach item in {foo bar baz}
16 foreach w in [@next: @item@@nl@@]
17 print w
18 end
19 end
20
21 # Foreach makes a copy of the list before the first iteration. This
22 # is relevant if the list is a variable that may change during the
23 # loop. The following exmaple takes a list of libs and if -lsdl is
24 # present on the list, appends -lsvga to the list and inserts -lm;
25 # these changes to "libs" will not alter the loop.
26 put libs {-lsdl -ltcl8.4}
27 foreach l in libs
28 print {l=} l {\n}
29 switch l
30 case {^-lsdl} put libs [@-lm @libs@ -lsvga@]; end
31 end
32 end
33 print {libs=} libs {\n}
34
0 foreach item in {this is a list of words} [at 7:1]
1 print [at 8:2]
2 arg: item
3 arg: {
4 }
5 put [at 15:1]
6 arg: nl
7 arg: {
8 }
9 foreach item in {foo bar baz} [at 16:1]
10 foreach w in [~next: ~item~~nl~~] [at 17:2]
11 print [at 18:3]
12 arg: w
13 put [at 27:1]
14 arg: libs
15 arg: {-lsdl -ltcl8.4}
16 foreach l in libs [at 28:1]
17 print [at 29:2]
18 arg: {l=}
19 arg: l
20 arg: {
21 }
22 switch l [at 30:2]
23 case {^-lsdl}
24 put [at 31:19]
25 arg: libs
26 arg: [~-lm ~libs~ -lsvga~]
27 print [at 34:1]
28 arg: {libs=}
29 arg: libs
30 arg: {
31 }
0 # The following regex sub utils are scconfig specific.
1
2 # Regex: substitute the first match of a pattern with str in a variable:
3 # sub address pattern str
4
5 put myvar {Hello world!\n}
6 sub myvar {l} {2}
7 print myvar
8
9 # Address must resolve to an existing variable, pattern and str are data;
10 # this means address can be a string that holds a variable name, it's the
11 # same as if it was an addreess:
12 sub {myvar} {l} {3}
13 print myvar
14
15 # Or it can be a block, which makes indirect addressing possible:
16 # in [@@pointer@@] the @pointer@ part will be substituted with
17 # the value of pointer, which is "myvar".
18 put pointer {myvar}
19 sub [@@pointer@@] {l} {4}
20 print myvar
21
22 # Since pattern and str are also data, address and blocks work there as well
23 # (but this is _not_ a regex backreference):
24 put punctuation {[!?.]}
25 sub [@@pointer@@] punctuation [@ PUNCT:@punctuation@@]
26 print myvar
27
28 # gsub does the same, but substutites all matches, not only the first:
29 gsub [@@pointer@@] {o} {_0_}
30 print myvar
0 put [at 6:1]
1 arg: myvar
2 arg: {Hello world!
3 }
4 sub [at 7:1]
5 arg: myvar
6 arg: {l}
7 arg: {2}
8 print [at 8:1]
9 arg: myvar
10 sub [at 13:1]
11 arg: {myvar}
12 arg: {l}
13 arg: {3}
14 print [at 14:1]
15 arg: myvar
16 put [at 19:1]
17 arg: pointer
18 arg: {myvar}
19 sub [at 20:1]
20 arg: [~~pointer~~]
21 arg: {l}
22 arg: {4}
23 print [at 21:1]
24 arg: myvar
25 put [at 25:1]
26 arg: punctuation
27 arg: {[!?.]}
28 sub [at 26:1]
29 arg: [~~pointer~~]
30 arg: punctuation
31 arg: [~ PUNCT:~punctuation~~]
32 print [at 27:1]
33 arg: myvar
34 gsub [at 30:1]
35 arg: [~~pointer~~]
36 arg: {o}
37 arg: {_0_}
38 print [at 31:1]
39 arg: myvar
0 # The following string util is scconfig specific.
1
2 # Uniq: filter a list of words and remove duplicate items. This instruction
3 # is useful for using text nodes as lists.
4 # The simplest syntax is "uniq address" which will do the filtering on
5 # the content of a database address. The default separator is \n
6 put list [@this
7 is
8 a
9 list
10 of
11 words,
12 a
13 list
14 of
15 words.
16 @]
17 print {original:\n} list {\n}
18 uniq list
19 print {uniq:\n} list {\n}
20
21 # If the original list needs to be left intact, the alternative syntax is
22 # "uniq dest-addr src-addr":
23 put foo [@this
24 foo
25 is
26 a
27 this
28 foo
29 @]
30 uniq tmp foo
31 print {original:\n} foo {\nuniq:\n} tmp {\n}
32
33 # Note: the algorithm of uniq is slow, and will not be efficient for very long
34 # lists. Uniq preserves the order of words (by their first appearance).
35
36 # Sortuniq performs the same action, except it also orders the list using
37 # qsort() (so it is even slower on big lists).
38 sortuniq tmp foo
39 print {\nsortuniq:\n} tmp {\n}
40
41
42 # A typical use case is having #defines and #includes on a list; #defines
43 # should end up on the top, but order of #incldues should be preserved, so
44 # sortuniq is not an option. When uniq is called with more than 2 argument,s
45 # the extra arguments specify group regexps; the input is first organized into
46 # groups then uniq is ran on these groups. Anything that doesn't match the
47 # groups listed are put in a "misc" group that ends up as the last group.
48 put list [@#define foo
49 #include "foo20.h"
50 #include "foo10.h"
51 /* misc1 */
52 #define bar
53 #include "bar1.h"
54 #include "bar2.h"
55 /* misc2 */
56 @]
57
58 # set input field separator to \n so uniq is splitting by lines, not by
59 # words
60 put /tmpasm/IFS {\n}
61
62 uniq tmp list {^#define} {^#include}
63 print {original:\n} list {\ngrouped uniq:\n} tmp {\n}
0 put [at 7:1]
1 arg: list
2 arg: {this
3 is
4 a
5 list
6 of
7 words,
8 a
9 list
10 of
11 words.
12 }
13 print [at 18:1]
14 arg: {original:
15 }
16 arg: list
17 arg: {
18 }
19 uniq [at 19:1]
20 arg: list
21 print [at 20:1]
22 arg: {uniq:
23 }
24 arg: list
25 arg: {
26 }
27 put [at 24:1]
28 arg: foo
29 arg: {this
30 foo
31 is
32 a
33 this
34 foo
35 }
36 uniq [at 31:1]
37 arg: tmp
38 arg: foo
39 print [at 32:1]
40 arg: {original:
41 }
42 arg: foo
43 arg: {
44 uniq:
45 }
46 arg: tmp
47 arg: {
48 }
49 sortuniq [at 39:1]
50 arg: tmp
51 arg: foo
52 print [at 40:1]
53 arg: {
54 sortuniq:
55 }
56 arg: tmp
57 arg: {
58 }
59 put [at 49:1]
60 arg: list
61 arg: {#define foo
62 #include "foo20.h"
63 #include "foo10.h"
64 /* misc1 */
65 #define bar
66 #include "bar1.h"
67 #include "bar2.h"
68 /* misc2 */
69 }
70 put [at 61:1]
71 arg: /tmpasm/IFS
72 arg: {
73 }
74 uniq [at 63:1]
75 arg: tmp
76 arg: list
77 arg: {^#define}
78 arg: {^#include}
79 print [at 64:1]
80 arg: {original:
81 }
82 arg: list
83 arg: {
84 grouped uniq:
85 }
86 arg: tmp
87 arg: {
88 }
0 # The following user interface utils are scconfig specific.
1
2 # The report infrstructure is the main UI in scconfig. It prints
3 # messages to the console. The "report" instruction works similar
4 # to print, but its output is always the console, immune to
5 # redirections and default file output (tmpasm is most commonly
6 # used for generating files, so the default output file is not
7 # the console but a file being generated)
8 put myvar {!\n}
9 report {hello } {world} myvar
10 report [@hello world@myvar@@]
11
12 # If an error is detected during generation of a file, the script should abort.
13 # This is a direct call to abort(2).
14 abort
0 put [at 9:1]
1 arg: myvar
2 arg: {!
3 }
4 report [at 10:1]
5 arg: {hello }
6 arg: {world}
7 arg: myvar
8 report [at 11:1]
9 arg: [~hello world~myvar~~]
10 abort [at 15:1]
0 # NOTE: THIS EXAMPLE WILL NOT WORK IN THE ON-LINE WEB VERSION
1
2 # These features are scconfig specific.
3
4 # There is a default output file coming from the environment; this
5 # is the file being generated. In the most common cases this is the
6 # only file the script will ever write. Any "print" instruction will
7 # write this file by default. However, sometimes it is handy
8 # to generate a small misc file during generating a large file. Thus
9 # the output file that "print" writes is not hardwired. Instead, there
10 # is the default output file and the current output file. Instruction
11 # "redir" can change the current output file.
12
13 print {this goes to the default output\n}
14
15 # redirect to Tutor10.inc; any "print" until the next "redir" will
16 # write that file
17 redir {Tutor10.inc}
18 print {# this is a generated file.}
19 print [@
20 print {hello world from my include!\n}
21 @]
22
23 # switch back to the default output
24 redir
25 print {back at default output.\n}
26
27
28 # Dynamic include: the script may include another script, runtime. When
29 # an include instruction is executed, the referred file is open, read,
30 # parsed and executed, recusively.
31 #
32 # Include being dynamic (or runtime) is unusual, but has the following
33 # advantages:
34 # - file name for inclusion can be calculated
35 # - conditional include is easily possible without an extra preprocessing layer
36 # - it is possible to generate a script on the fly and include it (sort of eval)
37 # Drawbacks:
38 # - it is possible to end up in an infinite loop that will only stop when
39 # resources run out (open fds or memory)
40 # - it is slow, e.g. if the body of a foreach contains include, the whole
41 # read-parse-execute procedure is repeated for each item
42 # Redir files are overwritten when first open from an execution.
43
44 print {Include:\n}
45 include {Tutor10.inc}
46
47 # NOTE: the above script works only because "redir" has a side effect:
48 # whenever redirection switches away from a file, that file is flushed.
49 # This happens even if the new current output is the same as the old
50 # current output (no actual switch takes place).
51
0 print [at 14:1]
1 arg: {this goes to the default output
2 }
3 redir [at 18:1]
4 arg: {Tutor10.inc}
5 print [at 19:1]
6 arg: {# this is a generated file.}
7 print [at 20:1]
8 arg: {
9 print {hello world from my include!\n}
10 }
11 redir [at 25:1]
12 print [at 26:1]
13 arg: {back at default output.
14 }
15 print [at 45:1]
16 arg: {Include:
17 }
18 include [at 46:1]
19 arg: {Tutor10.inc}
0 # conditional/safe variable reference: name prefixed by ?
1 # if the variable does not exist, no error is thrown but empty
2 # string is returned
3
4 if ?a then
5 print {empty}
6 else
7 print {not empty}
8 end
9
10 put b ?a
0 if ?a [at 5:7]
1 then:
2 print [at 6:2]
3 arg: {empty}
4 else:
5 print [at 8:2]
6 arg: {not empty}
7 put [at 11:1]
8 arg: b
9 arg: ?a
0 if ?a [at 5:7]
1 then:
2 print [at 6:2]
3 arg: {empty}
4 else:
5 print [at 8:2]
6 arg: {not empty}
7 put [at 11:1]
8 arg: b
9 arg: ?a
0 # Instruction "halt" breaks the execution of the current script file
1 # (returning from the C call to tmpasm() or stop processing an "include",
2 # returning to executing the parent script). It is useful for cheap
3 # termination of the script file from deep inside nested loops/ifs.
4
5 put tmp {true}
6 if tmp then
7 foreach item in {foo bar true baz}
8 print item {\n}
9 if item then
10 halt
11 end
12 end
13 end
0 put [at 6:1]
1 arg: tmp
2 arg: {true}
3 if tmp [at 7:8]
4 then:
5 foreach item in {foo bar true baz} [at 8:2]
6 print [at 9:3]
7 arg: item
8 arg: {
9 }
10 if item [at 10:11]
11 then:
12 halt [at 11:4]
13 else:
14 (NOP)
15 else:
16 (NOP)
0 append tmp {foo}
1 append tmp {bar}
2 append tmp {baz}
3 foreach n in tmp
4 print {-> } n {\n}
5 end
0 append [at 1:1]
1 arg: tmp
2 arg: {foo}
3 append [at 2:1]
4 arg: tmp
5 arg: {bar}
6 append [at 3:1]
7 arg: tmp
8 arg: {baz}
9 foreach n in tmp [at 4:1]
10 print [at 5:2]
11 arg: {-> }
12 arg: n
13 arg: {
14 }
0 print data1 # this is a comment; until the end of this line
1 print data2 # this shall be a second print
2
0 print [at 1:1]
1 arg: data1
2 print [at 2:1]
3 arg: data2
0 error: Excess "end" at 3:4
1 if {1} [at 1:8]
2 then:
3 (NOP)
4 else:
5 (NOP)
0 error: unexpected 'else' - must be in a 'then' block before an else at 2:5
1 if *NULL - broken AST* [at 1:1]
2 then:
3 (NOP)
4 else:
5 (NOP)
0 error: unexpected "end" in "if" - expected "then" at 2:4
1 if v [at 2:1]
2 then:
3 (NOP)
4 else:
5 (NOP)
0 pritn {foo}
1 switch {cond}
2 case {1} print {foo}; end
0 pritn [at 1:1]
1 arg: {foo}
2 switch {cond} [at 2:1]
3 case {1}
4 print [at 3:11]
5 arg: {foo}
0 error: unexpected end of if switch statement; expected a data at 1:7
1 (NOP)
0 switch
1 case data print {foo}; end
2 end
0 error: unexpected end of if switch statement; expected a data at 1:7
1 (NOP)
0 put a {1}
1 put foo {example-FOO}
2 put bar {example-BAR}
3 put baz {example-BAZ}
4 put hah {haha}
5
6 # should set n to the string foo, the value of bar and the string baz
7 # per iteration
8 foreach n in [~foo ~bar~ baz~]
9 print {n=} n {\n}
10 print {a11} [@a12 @hah@ a14@] {\n}
11 print {a21} {a22 a23} {\n}
12 print {a31\n}
13 end
14 print {a41} {a42} {a43} {\n}
15 print
16
17
0 put [at 1:1]
1 arg: a
2 arg: {1}
3 put [at 2:1]
4 arg: foo
5 arg: {example-FOO}
6 put [at 3:1]
7 arg: bar
8 arg: {example-BAR}
9 put [at 4:1]
10 arg: baz
11 arg: {example-BAZ}
12 put [at 5:1]
13 arg: hah
14 arg: {haha}
15 foreach n in [~foo ~bar~ baz~] [at 9:1]
16 print [at 10:2]
17 arg: {n=}
18 arg: n
19 arg: {
20 }
21 print [at 11:2]
22 arg: {a11}
23 arg: [~a12 ~hah~ a14~]
24 arg: {
25 }
26 print [at 12:2]
27 arg: {a21}
28 arg: {a22 a23}
29 arg: {
30 }
31 print [at 13:2]
32 arg: {a31
33 }
34 print [at 15:1]
35 arg: {a41}
36 arg: {a42}
37 arg: {a43}
38 arg: {
39 }
40 print [at 16:1]
0 put a 1
1 if a then
2 if b then
3 print {then-then}
4 else
5 print {then-else}
6 end
7 else
8 print {else}
9 end
0 put [at 1:1]
1 arg: a
2 arg: 1
3 if a [at 2:6]
4 then:
5 if b [at 3:7]
6 then:
7 print [at 4:3]
8 arg: {then-then}
9 else:
10 print [at 6:3]
11 arg: {then-else}
12 else:
13 print [at 9:2]
14 arg: {else}
0 # test if without an else
1 put list {one two three four}
2
3 print list {\n}
4
5 print {\nnothing:\n}
6
7 # do nothing: order matches
8 order out list {one} {before} {two}
9 print out {\n}
10
11 order out list {one} {before} {one}
12 print out {\n}
13
14 order out list {one} {after} {one}
15 print out {\n}
16
17 order out list {two} {after} {one}
18 print out {\n}
19
20 # do nothing: not on list matches
21 order out list {nine} {after} {one}
22 print out {\n}
23 order out list {one} {after} {nine}
24 print out {\n}
25
26 print {\nbefore:\n}
27 order out list {two} {before} {one}
28 print out {\n}
29
30 order out list {four} {before} {one}
31 print out {\n}
32
33 order out list {four} {before} {three}
34 print out {\n}
35
36 order out list {three} {before} {two}
37 print out {\n}
38
39 print {\nafter:\n}
40 order out list {one} {after} {two}
41 print out {\n}
42
43 order out list {one} {after} {four}
44 print out {\n}
45
46 order out list {two} {after} {three}
47 print out {\n}
48
49 order out list {two} {after} {four}
50 print out {\n}
0 put [at 2:1]
1 arg: list
2 arg: {one two three four}
3 print [at 4:1]
4 arg: list
5 arg: {
6 }
7 print [at 6:1]
8 arg: {
9 nothing:
10 }
11 order [at 9:1]
12 arg: out
13 arg: list
14 arg: {one}
15 arg: {before}
16 arg: {two}
17 print [at 10:1]
18 arg: out
19 arg: {
20 }
21 order [at 12:1]
22 arg: out
23 arg: list
24 arg: {one}
25 arg: {before}
26 arg: {one}
27 print [at 13:1]
28 arg: out
29 arg: {
30 }
31 order [at 15:1]
32 arg: out
33 arg: list
34 arg: {one}
35 arg: {after}
36 arg: {one}
37 print [at 16:1]
38 arg: out
39 arg: {
40 }
41 order [at 18:1]
42 arg: out
43 arg: list
44 arg: {two}
45 arg: {after}
46 arg: {one}
47 print [at 19:1]
48 arg: out
49 arg: {
50 }
51 order [at 22:1]
52 arg: out
53 arg: list
54 arg: {nine}
55 arg: {after}
56 arg: {one}
57 print [at 23:1]
58 arg: out
59 arg: {
60 }
61 order [at 24:1]
62 arg: out
63 arg: list
64 arg: {one}
65 arg: {after}
66 arg: {nine}
67 print [at 25:1]
68 arg: out
69 arg: {
70 }
71 print [at 27:1]
72 arg: {
73 before:
74 }
75 order [at 28:1]
76 arg: out
77 arg: list
78 arg: {two}
79 arg: {before}
80 arg: {one}
81 print [at 29:1]
82 arg: out
83 arg: {
84 }
85 order [at 31:1]
86 arg: out
87 arg: list
88 arg: {four}
89 arg: {before}
90 arg: {one}
91 print [at 32:1]
92 arg: out
93 arg: {
94 }
95 order [at 34:1]
96 arg: out
97 arg: list
98 arg: {four}
99 arg: {before}
100 arg: {three}
101 print [at 35:1]
102 arg: out
103 arg: {
104 }
105 order [at 37:1]
106 arg: out
107 arg: list
108 arg: {three}
109 arg: {before}
110 arg: {two}
111 print [at 38:1]
112 arg: out
113 arg: {
114 }
115 print [at 40:1]
116 arg: {
117 after:
118 }
119 order [at 41:1]
120 arg: out
121 arg: list
122 arg: {one}
123 arg: {after}
124 arg: {two}
125 print [at 42:1]
126 arg: out
127 arg: {
128 }
129 order [at 44:1]
130 arg: out
131 arg: list
132 arg: {one}
133 arg: {after}
134 arg: {four}
135 print [at 45:1]
136 arg: out
137 arg: {
138 }
139 order [at 47:1]
140 arg: out
141 arg: list
142 arg: {two}
143 arg: {after}
144 arg: {three}
145 print [at 48:1]
146 arg: out
147 arg: {
148 }
149 order [at 50:1]
150 arg: out
151 arg: list
152 arg: {two}
153 arg: {after}
154 arg: {four}
155 print [at 51:1]
156 arg: out
157 arg: {
158 }
0 put swdata {lol}
1 switch swdata
2 case data1 print {1a} {11}; print {1b} 12; print {1c} 13; print {1d} 14; end;
3 case [~data2 ~a~~] print {2a} 21; print {2b} 22; print {2c} 23; print {2d} 24; end;
4 default print {3a} 31; print {3b} 32; print {3c} 33; print {3d} 34; end;
5 end;
6 print {i1}
7 print {i2}
0 put [at 1:1]
1 arg: swdata
2 arg: {lol}
3 switch swdata [at 2:1]
4 case data1
5 print [at 3:24]
6 arg: {1a}
7 arg: {11}
8 print [at 3:41]
9 arg: {1b}
10 arg: 12
11 print [at 3:56]
12 arg: {1c}
13 arg: 13
14 print [at 3:71]
15 arg: {1d}
16 arg: 14
17 case [~data2 ~a~~]
18 print [at 4:24]
19 arg: {2a}
20 arg: 21
21 print [at 4:41]
22 arg: {2b}
23 arg: 22
24 print [at 4:56]
25 arg: {2c}
26 arg: 23
27 print [at 4:71]
28 arg: {2d}
29 arg: 24
30 default
31 print [at 5:24]
32 arg: {3a}
33 arg: 31
34 print [at 5:41]
35 arg: {3b}
36 arg: 32
37 print [at 5:56]
38 arg: {3c}
39 arg: 33
40 print [at 5:71]
41 arg: {3d}
42 arg: 34
43 print [at 7:1]
44 arg: {i1}
45 print [at 8:1]
46 arg: {i2}
0 ### set up internal variables ###
1 put /local/cflags {-std=c99 -Wall}
2 put /local/ldflags {-lm}
3 put /local/objs {main.o foo.o bar.o}
4
5 # turn off optimization and add -g in debug mode
6 if /local/debug then
7 append /local/cflags {-g}
8 else
9 append /local/cflags {-O2}
10 end
11
12 # if somelib is selected, add -I and -l
13 isempty /local/r /local/somelib
14 invert /local/r
15 if /local/r then
16 append /local/cflags { -I/usr/include/somelib}
17 append /local/ldflags { -lsomelib}
18 end
19
20 ### Generate the Makefile ###
21 print [@
22 # Makefile generated by scconfig - DO NOT EDIT - please edit Makefile.in
23 CFLAGS=@/local/cflags@
24 LDFLAGS=@/local/ldflags@
25 OBJS=@/local/objs@
26
27 all: main
28
29 main: $(OBJS)
30 $(CC) $(LDFLAGS)
31
32 @]
33
34 # loop over each object and generate an explicit rule
35 # (we are generating a dumb Makefile that would work with any
36 # old version of make)
37 foreach /local/o in /local/objs
38 put /local/c /local/o
39 sub /local/c {.o$} {.c}
40 print [@
41 @/local/o@: @/local/c@
42 $(CC) -c $(CFLAGS) @/local/c@ -o @/local/o@
43 @]
44 end
45
46 print {#end\n}
0 put [at 2:1]
1 arg: /local/cflags
2 arg: {-std=c99 -Wall}
3 put [at 3:1]
4 arg: /local/ldflags
5 arg: {-lm}
6 put [at 4:1]
7 arg: /local/objs
8 arg: {main.o foo.o bar.o}
9 if /local/debug [at 7:17]
10 then:
11 append [at 8:2]
12 arg: /local/cflags
13 arg: {-g}
14 else:
15 append [at 10:2]
16 arg: /local/cflags
17 arg: {-O2}
18 isempty [at 14:1]
19 arg: /local/r
20 arg: /local/somelib
21 invert [at 15:1]
22 arg: /local/r
23 if /local/r [at 16:13]
24 then:
25 append [at 17:2]
26 arg: /local/cflags
27 arg: { -I/usr/include/somelib}
28 append [at 18:2]
29 arg: /local/ldflags
30 arg: { -lsomelib}
31 else:
32 (NOP)
33 print [at 22:1]
34 arg: [~
35 # Makefile generated by scconfig - DO NOT EDIT - please edit Makefile.in
36 CFLAGS=~/local/cflags~
37 LDFLAGS=~/local/ldflags~
38 OBJS=~/local/objs~
39
40 all: main
41
42 main: $(OBJS)
43 $(CC) $(LDFLAGS)
44
45 ~]
46 foreach /local/o in /local/objs [at 38:1]
47 put [at 39:2]
48 arg: /local/c
49 arg: /local/o
50 sub [at 40:2]
51 arg: /local/c
52 arg: {.o$}
53 arg: {.c}
54 print [at 41:2]
55 arg: [~
56 ~/local/o~: ~/local/c~
57 $(CC) -c $(CFLAGS) ~/local/c~ -o ~/local/o~
58 ~]
59 print [at 47:1]
60 arg: {#end
61 }
0 # test if without an else
1 if cnd then
2 print a1 a2 a3
3 end
4
5 print a1 a2 a3
0 if cnd [at 2:8]
1 then:
2 print [at 3:2]
3 arg: a1
4 arg: a2
5 arg: a3
6 else:
7 (NOP)
8 print [at 6:1]
9 arg: a1
10 arg: a2
11 arg: a3
0 #include <stdlib.h>
1 #include <stdio.h>
2 #include "tmpasm.h"
3 #include "tmpasm_scconfig.h"
4 #include "debug.h"
5 #include "db.h"
6
7 tmpasm_t *ctx;
8
9 void re_fail(char *s, char c)
10 {
11 fprintf(stderr, "Regex error: %s [opcode %o]\n", s, c);
12 abort();
13 }
14
15 static void do_dump()
16 {
17 tmpasm_dump(ctx, stdout);
18 }
19
20 static void do_exec()
21 {
22 if (ctx->dead)
23 fprintf(stderr, "Can not execute the script due to the above compilation error.\n");
24 else
25 tmpasm_execute(ctx);
26 }
27
28 static void scc_init(void)
29 {
30 db_init();
31 db_mkdir("/local");
32 db_cd("/local");
33 }
34
35 int main(int argc, char *argv[])
36 {
37 scc_init();
38 ctx = tmpasm_init(&scc_cb);
39 scc_tmpasm_parse(ctx, NULL, stdin, stdout);
40
41 if (argc > 1) {
42 char *cmd;
43 cmd = argv[1];
44 while(*cmd == '-') cmd++;
45 switch(*cmd) {
46 case 'd': do_dump(); break;
47 case 'e': do_exec(); break;
48 }
49 }
50 else
51 do_dump();
52
53 if (ctx->runtime_error != 0) {
54 const char *fmt = tmpasm_runtime_error_fmt(ctx);
55 fprintf(stderr, "Runtime error at %d:%d: ", ctx->runtime_error_line, ctx->runtime_error_col);
56 fprintf(stderr, fmt, (ctx->runtime_error_data == NULL ? "" : ctx->runtime_error_data));
57 fprintf(stderr, "\n");
58 }
59
60 tmpasm_uninit(ctx);
61 db_uninit();
62 return 0;
63 }
0 #include <stdlib.h>
1 #include <stdio.h>
2 #include <string.h>
3 #include <assert.h>
4 #include "tmpasm.h"
5 #include "debug.h"
6
7 #define is_space(c) (((c) == ' ') || ((c) == '\t'))
8 #define is_sep(c) (((c) == '\n') || ((c) == '\r') || ((c) == ';'))
9 #define is_addr(c) ( (((c) >= '0') && ((c) <= '9')) || (((c) >= 'a') && ((c) <= 'z')) || (((c) >= 'A') && ((c) <= 'Z')) || ((c) == '_') || ((c) == '?') || ((c) == '.') || ((c) == ',') || ((c) == ',') || ((c) == '-') || ((c) == '/') || ((c) == '&') )
10
11 /* this local copy is to make tmpasm compile independently */
12 static char *strclone(const char *str)
13 {
14 int l;
15 char *ret;
16
17 if (str == NULL)
18 return NULL;
19
20 l = strlen(str)+1;
21 ret = malloc(l);
22 memcpy(ret, str, l);
23 return ret;
24 }
25
26
27 #define TOP ctx->st
28
29 static const char *kw_names[] = {"-", "if", "then", "else", "end", "foreach", "in", "switch", "case", "default", "nop", NULL };
30
31 static tmpasm_kw_t kw_lookup(const char *str)
32 {
33 const char **k;
34 tmpasm_kw_t i;
35
36 /* slow linear search is enough: we have only a few keywords */
37 for(k = kw_names, i = KW_none; *k != NULL; k++,i++)
38 if (strcmp(*k, str) == 0)
39 return i;
40 return KW_none;
41 }
42
43
44 tmpasm_exec_t *code_new(tmpasm_kw_t kw)
45 {
46 tmpasm_exec_t *c;
47 c = calloc(sizeof(tmpasm_exec_t), 1);
48 c->kw = kw;
49 return c;
50 }
51
52 /*tmpasm_exec_t *code_end(tmpasm_exec_t *start)
53 {
54 while(start->next != NULL)
55 start = start->next;
56 return start;
57 }*/
58
59 tmpasm_exec_t *code_append(tmpasm_t *ctx, tmpasm_kw_t kw)
60 {
61 tmpasm_exec_t *c;
62 /* c = code_end(TOP->code);*/
63 c = TOP->last_code;
64 if (TOP->last_code->kw != KW_NOP) {
65 c->next = code_new(kw);
66 return c->next;
67 }
68 c->kw = kw;
69 return c;
70 }
71
72 static void error(tmpasm_t *ctx, char c, char *msg)
73 {
74 fprintf(stderr, "error: %s at %d:%d\n", msg, ctx->line, ctx->col);
75 if (c != 0)
76 fprintf(stderr, " character last seen: %c\n", c);
77 ctx->dead = 1;
78 }
79
80 static void push(tmpasm_t *ctx, tmpasm_kw_t kw, tmpasm_state_t st, tmpasm_exec_t *code)
81 {
82 tmpasm_stack_t *new;
83 new = calloc(sizeof(tmpasm_stack_t), 1);
84 new->kw = kw;
85 new->state = st;
86 new->next = ctx->st;
87 new->last_code = code;
88 ctx->st = new;
89 }
90
91 static void pop_(tmpasm_t *ctx, int chk_underfl)
92 {
93 tmpasm_stack_t *old;
94 old = ctx->st;
95 ctx->st = old->next;
96
97 /* stack underflow? */
98 if (chk_underfl) {
99 if (TOP == NULL) {
100 error(ctx, 0, "Excess \"end\"");
101 TOP = old;
102 return;
103 }
104 }
105 if (old->argv != NULL)
106 free(old->argv);
107 if (old->argend != NULL)
108 free(old->argend);
109 if (old->arg_used != NULL)
110 free(old->arg_used);
111 if (old->arg_alloced != NULL)
112 free(old->arg_alloced);
113 free(old);
114 }
115
116 static void pop(tmpasm_t *ctx)
117 {
118 pop_(ctx, 1);
119 }
120
121
122 #define grow(arr, size) arr = realloc(arr, sizeof((arr)[0]) * size)
123
124 static void arg_new(tmpasm_t *ctx, int is_addr)
125 {
126 if (TOP->args_used >= TOP->args_alloced) {
127 TOP->args_alloced = TOP->args_alloced + 16;
128 grow(TOP->argv, TOP->args_alloced);
129 grow(TOP->argend, TOP->args_alloced);
130 grow(TOP->arg_alloced, TOP->args_alloced);
131 grow(TOP->arg_used, TOP->args_alloced);
132 }
133
134 TOP->arg_alloced[TOP->args_used] = 64;
135 TOP->arg_used[TOP->args_used] = 0;
136
137 TOP->argv[TOP->args_used] = malloc(TOP->arg_alloced[TOP->args_used]+sizeof(tmpasm_arg_t));
138 TOP->argv[TOP->args_used]->is_addr = is_addr;
139 TOP->argv[TOP->args_used]->next = NULL;
140 TOP->argend[TOP->args_used] = TOP->argv[TOP->args_used];
141
142 TOP->args_used++;
143 }
144
145
146 static void arg_append(tmpasm_t *ctx, char c)
147 {
148 int i = TOP->args_used - 1;
149
150 if (TOP->arg_used[i] >= TOP->arg_alloced[i]) {
151 tmpasm_arg_t *prev, *last;
152
153 /* since argend[i] is also in the ->next pointer of the previous item in a block chain, we need to look it up */
154 for(prev = NULL, last = TOP->argv[i]; last->next != NULL; last = last->next)
155 prev = last;
156
157 TOP->arg_alloced[i] += 64;
158 last = realloc(last, TOP->arg_alloced[i]+sizeof(tmpasm_arg_t));
159
160 if (prev == NULL)
161 TOP->argv[i] = last;
162 else
163 prev->next = last;
164
165 TOP->argend[i] = last;
166 }
167 TOP->argend[i]->data[TOP->arg_used[i]] = c;
168 TOP->arg_used[i]++;
169 }
170
171 static void arg_free(tmpasm_arg_t *a)
172 {
173 tmpasm_arg_t *next;
174 if (a == NULL)
175 return;
176 next = a->next;
177 free(a);
178 if (next != NULL)
179 arg_free(next);
180 }
181
182 static void arg_new_next(tmpasm_t *ctx, int is_addr)
183 {
184 tmpasm_arg_t *a;
185 int id;
186
187 arg_append(ctx, '\0');
188
189 id = TOP->args_used - 1;
190 assert(id>=0);
191 TOP->arg_alloced[id] = 64;
192 TOP->arg_used[id] = 0;
193
194 a = malloc(TOP->arg_alloced[id]+sizeof(tmpasm_arg_t));
195 strcpy(a->data, "QWERT");
196 a->is_addr = is_addr;
197 a->next = NULL;
198 TOP->argend[id]->next = a;
199 TOP->argend[id] = a;
200 }
201
202 static void arg_remove(tmpasm_t *ctx)
203 {
204 assert(TOP->args_used == 1);
205 TOP->args_used = 0;
206 TOP->argv[0] = NULL;
207 TOP->argend[0] = NULL;
208 TOP->arg_alloced[0] = 0;
209 TOP->arg_used[0] = 0;
210 }
211
212 static int arg_is_addr(tmpasm_arg_t *a)
213 {
214 return (a->next == NULL) && (a->is_addr);
215 }
216
217 static void arg_end(tmpasm_t *ctx, int cmd_ctx)
218 {
219 tmpasm_arg_t *a;
220 arg_append(ctx, '\0');
221
222 a = TOP->argv[TOP->args_used-1];
223 if (cmd_ctx) {
224 /* when argument ends in a command context (not in a block inline), we
225 may may need to switch back to command mode; example: after
226 the cond of an "if cond then"*/
227 switch(TOP->kw) {
228 case KW_IF:
229 TOP->state = ST_PRECMD;
230 break;
231 case KW_FOREACH:
232 if (!arg_is_addr(a)) {
233 error(ctx, 0, "variable of a foreach must be an address");
234 return;
235 }
236 TOP->last_code->payload.fc_foreach.loop_var = strclone(a->data);
237 arg_free(a);
238 arg_remove(ctx);
239 TOP->state = ST_PRECMD;
240 break;
241 case KW_IN:
242 /* pop will free the argv[] array, but not the elements so "a" is safe to use after this line */
243 pop(ctx);
244 /* in foreach context, after the IN-data */
245 TOP->last_code->payload.fc_foreach.data = a;
246
247 /* we are in the body now, TOP is the foreach context, last_code is body */
248 TOP->last_code->payload.fc_foreach.code_body = code_new(KW_NOP);
249 push(ctx, KW_none, ST_PRECMD, TOP->last_code->payload.fc_foreach.code_body);
250 break;
251 case KW_CASE:
252 ctx->st->next->last_code->payload.fc_switch.last->data = a;
253 arg_remove(ctx);
254 push(ctx, KW_none, ST_PRECMD, TOP->last_code);
255 break;
256 case KW_SWITCH:
257 TOP->last_code->payload.fc_switch.cond = a;
258 arg_remove(ctx);
259 TOP->state = ST_PRECMD;
260 break;
261 default:
262 TOP->state = ST_PREDATA;
263 }
264 }
265 }
266
267
268
269 /* end of statement; update kw state for a composite control kw; for the rest
270 just call the lib */
271 static void end_of_statement(tmpasm_t *ctx)
272 {
273 switch(TOP->kw) {
274 case KW_none:
275 case KW_THEN:
276 case KW_ELSE:
277 case KW_CASE:
278 case KW_DEFAULT:
279 TOP->last_code->payload.instr.argc = TOP->args_used;
280 TOP->last_code->payload.instr.argv = TOP->argv;
281 TOP->argv = NULL;
282 free(TOP->argend);
283 TOP->argend = NULL;
284 TOP->args_used = 0;
285 TOP->args_alloced = 0;
286 break;
287 default:
288 /* don't mess with the payload */
289 ;
290 }
291 TOP->state = ST_PRECMD;
292 }
293
294 #define loc_update() \
295 do { \
296 TOP->last_code->line = TOP->kwline; \
297 TOP->last_code->col = TOP->kwcol; \
298 } while(0)
299
300 static void got_kw(tmpasm_t *ctx, tmpasm_kw_t kw, int terminated)
301 {
302 switch(kw) {
303 case KW_END:
304 /* then-else threads have their own subcontext within the if subcontext; end needs to pop the innermost subcontext before terminating the if context */
305 if (TOP->kw == KW_IF) {
306 error(ctx, 0, "unexpected \"end\" in \"if\" - expected \"then\"");
307 goto bind_if_cond;
308 }
309 if ((TOP->kw == KW_ELSE) || (TOP->kw == KW_THEN))
310 pop(ctx);
311
312
313 if (TOP->kw == KW_SWITCH)
314 TOP->kw = TOP->old_kw;
315 else {
316 pop(ctx);
317
318 if ((TOP->kw == KW_CASE) || (TOP->kw == KW_DEFAULT))
319 pop(ctx);
320
321 }
322 TOP->state = ST_PRECMD;
323
324 /* have to restore context keyword after these */
325 if (TOP->kw == KW_FOREACH)
326 TOP->kw = TOP->old_kw;
327
328 break;
329 case KW_IF:
330 if (terminated) {
331 error(ctx, 0, "unexpected end of if statement; expected a condition");
332 return;
333 }
334 TOP->last_code = code_append(ctx, KW_IF);
335 TOP->last_code->payload.fc_if.code_then = code_new(KW_NOP);
336 TOP->last_code->payload.fc_if.code_else = code_new(KW_NOP);
337 loc_update();
338 TOP->state = ST_PRECMD;
339 /* prepare for reading a condition */
340 push(ctx, KW_IF, ST_PREDATA, TOP->last_code);
341 break;
342 case KW_THEN:
343 /* we are in an if context, right after reading a condition */
344 if (TOP->kw != KW_IF) {
345 error(ctx, 0, "unexpected 'then' - must be in an 'if' after the condition");
346 return;
347 }
348 bind_if_cond:;
349 TOP->last_code->payload.fc_if.cond = TOP->argv[0];
350 loc_update();
351 arg_remove(ctx);
352 push(ctx, KW_THEN, ST_PRECMD, TOP->last_code->payload.fc_if.code_then);
353 break;
354 case KW_ELSE:
355 /* we are in an if context, after and end */
356 if (TOP->kw != KW_THEN) {
357 error(ctx, 0, "unexpected 'else' - must be in a 'then' block before an else");
358 return;
359 }
360 pop(ctx); /* that was the then branch */
361 push(ctx, KW_ELSE, ST_PRECMD, TOP->last_code->payload.fc_if.code_else);
362 break;
363 case KW_FOREACH:
364 if (terminated) {
365 error(ctx, 0, "unexpected end of if foreach statement; expected an address");
366 return;
367 }
368 TOP->last_code = code_append(ctx, KW_FOREACH);
369 loc_update();
370 TOP->state = ST_PREDATA;
371 TOP->old_kw = TOP->kw;
372 TOP->kw = KW_FOREACH;
373 break;
374 case KW_IN:
375 if (TOP->kw != KW_FOREACH)
376 error(ctx, 0, "unexpected \"in\"; should be after the address in foreach");
377 else
378 push(ctx, KW_IN, ST_PREDATA, NULL);
379 break;
380 case KW_SWITCH:
381 if (terminated) {
382 error(ctx, 0, "unexpected end of if switch statement; expected a data");
383 return;
384 }
385 TOP->last_code = code_append(ctx, KW_SWITCH);
386 TOP->state = ST_PREDATA;
387 TOP->old_kw = TOP->kw;
388 TOP->kw = KW_SWITCH;
389 loc_update();
390 break;
391 case KW_CASE:
392 case KW_DEFAULT:
393 if (TOP->kw == KW_SWITCH) {
394 tmpasm_case_t *c;
395 c = malloc(sizeof(tmpasm_case_t));
396 c->body = code_new(KW_NOP);
397 c->data = NULL;
398 c->next = NULL;
399 if (TOP->last_code->payload.fc_switch.last == NULL) {
400 TOP->last_code->payload.fc_switch.first = c;
401 TOP->last_code->payload.fc_switch.last = c;
402 }
403 else {
404 TOP->last_code->payload.fc_switch.last->next = c;
405 TOP->last_code->payload.fc_switch.last = c;
406 }
407 if (kw == KW_DEFAULT) {
408 push(ctx, KW_DEFAULT, ST_PRECMD, c->body);
409 push(ctx, KW_none, ST_PRECMD, c->body);
410 c->data = NULL;
411 }
412 else
413 push(ctx, KW_CASE, ST_PREDATA, c->body);
414 }
415 else
416 error(ctx, 0, "unexpected \"case\" or \"default\"; should be in a switch (is the last case terminated by an \"end\"?)");
417 break;
418 default:
419 TOP->last_code = code_append(ctx, KW_none);
420 TOP->last_code->payload.instr.call_name = strclone(TOP->cmd_buff);
421 if (TOP->last_code->payload.instr.call_name != NULL) {
422 TOP->last_code->payload.instr.call = ctx->cb->resolve(ctx, TOP->last_code->payload.instr.call_name);
423 loc_update();
424 }
425 if (terminated)
426 TOP->state = ST_PRECMD;
427 else
428 TOP->state = ST_PREDATA;
429 }
430 }
431
432 static void comment_start(tmpasm_t *ctx)
433 {
434 push(ctx, KW_none, ST_COMMENT, NULL);
435 }
436
437 int tmpasm_gotchar(tmpasm_t *ctx, char c)
438 {
439 if (ctx->dead)
440 return -1;
441 switch(TOP->state) {
442 case ST_COMMENT:
443 if ((c == '\n') || (c == '\r')) {
444 pop(ctx);
445 if (TOP->state == ST_PREDATA)
446 end_of_statement(ctx);
447 }
448 break;
449 case ST_PRECMD:
450 if (c == '#') {
451 comment_start(ctx);
452 break;
453 }
454 if (is_space(c) || is_sep(c))
455 break;
456 TOP->cmdi = 0;
457 TOP->state = ST_CMD;
458 TOP->kwline = ctx->line;
459 TOP->kwcol = ctx->col;
460 /* fall thru */
461 case ST_CMD:
462 /* end of command or keyword */
463 if (is_space(c) || is_sep(c)) {
464 TOP->cmd_buff[TOP->cmdi] = '\0';
465 got_kw(ctx, kw_lookup(TOP->cmd_buff), is_sep(c));
466 }
467 else {
468 TOP->cmd_buff[TOP->cmdi] = c;
469 TOP->cmdi++;
470 if (TOP->cmdi >= sizeof(TOP->cmd_buff))
471 error(ctx, 0, "keyword or instruction name is too long");
472 }
473 break;
474 case ST_PREDATA:
475 if (c == '#') {
476 comment_start(ctx);
477 break;
478 }
479 if (is_space(c))
480 break;
481 if (is_sep(c))
482 end_of_statement(ctx);
483 else if (c == '{') {
484 TOP->state = ST_STRING;
485 arg_new(ctx, 0);
486 }
487 else if (c == '[') {
488 TOP->state = ST_PREBLOCKSEP;
489 arg_new(ctx, 0);
490 }
491 else if (is_addr(c)) {
492 TOP->state = ST_ADDRESS;
493 arg_new(ctx, 1);
494 arg_append(ctx, c);
495 }
496 else
497 error(ctx, c, "unexpected character; expected '{' for starting a string or an address");
498 break;
499 case ST_PREBLOCKSEP:
500 TOP->block_sep = c;
501 TOP->state = ST_BLOCK;
502 break;
503 case ST_BLOCK:
504 if (c == TOP->block_sep)
505 TOP->state = ST_BLOCKSEP;
506 else
507 arg_append(ctx, c);
508 break;
509 case ST_BLOCKSEP:
510 if (c != ']') {
511 arg_new_next(ctx, 1);
512 arg_append(ctx, c);
513 TOP->state = ST_BLOCK_INLINE;
514 }
515 else
516 arg_end(ctx, 1);
517 break;
518 case ST_BLOCK_INLINE:
519 if (c == TOP->block_sep) {
520 arg_new_next(ctx, 0);
521 TOP->state = ST_BLOCK;
522 }
523 else
524 arg_append(ctx, c);
525 break;
526 case ST_STRING:
527 if (c == '}')
528 arg_end(ctx, 1);
529 else if (c == '\\')
530 TOP->state = ST_STRING_ESCAPE;
531 else
532 arg_append(ctx, c);
533 break;
534 case ST_STRING_ESCAPE:
535 {
536 char co;
537 switch(c) {
538 case 'n': co = '\n'; break;
539 case 'r': co = '\r'; break;
540 case 't': co = '\t'; break;
541 case '\\': co = '\\'; break;
542 case 'o': co = '{'; break;
543 case 'c': co = '}'; break;
544 default: co = c;
545 }
546 arg_append(ctx, co);
547 TOP->state = ST_STRING;
548 }
549 break;
550 case ST_ADDRESS:
551 if (is_space(c))
552 arg_end(ctx, 1);
553 else if (is_sep(c)) {
554 arg_end(ctx, 1);
555 end_of_statement(ctx);
556 }
557 else if (is_addr(c))
558 arg_append(ctx, c);
559 else
560 error(ctx, c, "unexpected character; expected next character of the address");
561 break;
562 }
563 if (c == '\n') {
564 ctx->line++;
565 ctx->col = 1;
566 }
567 else
568 ctx->col++;
569 return 0;
570 }
571
572 tmpasm_t *tmpasm_init(const tmpasm_cb_t *cb)
573 {
574 tmpasm_t *ctx;
575 ctx = calloc(sizeof(tmpasm_t), 1);
576 ctx->line = 1;
577 ctx->col = 1;
578 ctx->code = code_new(KW_NOP);
579 ctx->cb = cb;
580 push(ctx, KW_none, ST_PRECMD, ctx->code);
581 return ctx;
582 }
583
584 static void free_exec(tmpasm_exec_t *e)
585 {
586 int n;
587 tmpasm_case_t *c, *c_next;
588 tmpasm_exec_t *e_next;
589
590 for(; e != NULL; e = e_next) {
591 e_next = e->next;
592 switch(e->kw) {
593 case KW_none:
594 if (e->payload.instr.call_name != NULL)
595 free(e->payload.instr.call_name);
596 for(n = 0; n < e->payload.instr.argc; n++)
597 arg_free(e->payload.instr.argv[n]);
598 free(e->payload.instr.argv);
599 break;
600 case KW_IF:
601 arg_free(e->payload.fc_if.cond);
602 free_exec(e->payload.fc_if.code_then);
603 free_exec(e->payload.fc_if.code_else);
604 break;
605 case KW_FOREACH:
606 free(e->payload.fc_foreach.loop_var);
607 arg_free(e->payload.fc_foreach.data);
608 free_exec(e->payload.fc_foreach.code_body);
609 break;
610 case KW_SWITCH:
611 arg_free(e->payload.fc_switch.cond);
612 for(c = e->payload.fc_switch.first; c != NULL; c = c_next) {
613 c_next = c->next;
614 if (c->data != NULL)
615 arg_free(c->data);
616 free_exec(c->body);
617 free(c);
618 }
619 break;
620 default:;
621 }
622 free(e);
623 }
624 }
625
626 void tmpasm_uninit(tmpasm_t *ctx)
627 {
628 free_exec(ctx->code);
629 while (ctx->st != NULL)
630 pop_(ctx, 0);
631 if (ctx->runtime_error_data != NULL)
632 free(ctx->runtime_error_data);
633 free(ctx);
634 }
635
636 /****************** runtime ********************/
637
638 static const char *tmpasm_runtime_error_fmts[] = {
639 "success %s",
640 "variable '%s' does not exist",
641 "empty argument (broken AST)%s",
642 "compilation error: control block without an \"end\"; premature end of script%s",
643 "attempt to call unresolved instruction '%s'",
644 NULL
645 };
646
647 void tmpasm_runtime_error(tmpasm_t *ctx, int code, const char *data)
648 {
649 ctx->runtime_error = code;
650 if (ctx->runtime_error_data != NULL)
651 free(ctx->runtime_error_data);
652 ctx->runtime_error_data = strclone(data);
653 if (ctx->executing != NULL) {
654 ctx->runtime_error_line = ctx->executing->line;
655 ctx->runtime_error_col = ctx->executing->col;
656 }
657 else {
658 ctx->runtime_error_line = 0;
659 ctx->runtime_error_col = 0;
660 }
661 }
662
663 const char *tmpasm_runtime_error_fmt(tmpasm_t *ctx)
664 {
665 if (ctx->runtime_error == 0)
666 return NULL;
667 if ((ctx->runtime_error < 0) && (ctx->cb->runtime_error_fmt != NULL)) {
668 const char *fmt;
669 fmt = ctx->cb->runtime_error_fmt(ctx);
670 if (fmt != NULL)
671 return fmt;
672 }
673 if ((ctx->runtime_error < 0) || ((size_t)ctx->runtime_error > (sizeof(tmpasm_runtime_error_fmts)/sizeof(char *))))
674 return "invalid error code %s";
675 return tmpasm_runtime_error_fmts[ctx->runtime_error];
676 }
677
678 char *tmpasm_arg2str(tmpasm_t *ctx, tmpasm_arg_t *a, int keep_addr)
679 {
680 if (a == NULL) {
681 tmpasm_runtime_error(ctx, 2, NULL);
682 return strclone("");
683 }
684 if (a->next != NULL) {
685 /* block mode */
686 int alloced = 0, used = 0;
687 char *s = NULL;
688 const char *i;
689
690 for(;a != NULL; a = a->next) {
691 int l;
692 if (a->is_addr) {
693 i = ctx->cb->get(ctx, a->data);
694 if (i == NULL) {
695 i = "";
696 tmpasm_runtime_error(ctx, 1, strclone(a->data));
697 }
698 }
699 else
700 i = a->data;
701 l = strlen(i);
702 if (used + l >= alloced) {
703 alloced = used + l + 256;
704 s = realloc(s, alloced);
705 }
706 memcpy(s+used, i, l);
707 used += l;
708 }
709 s[used] = '\0';
710 return s;
711 }
712
713 /* non-block */
714 if (a->is_addr) {
715 const char *i;
716 if (keep_addr)
717 i = a->data;
718 else
719 i = ctx->cb->get(ctx, a->data);
720 if (i == NULL) {
721 i = "";
722 tmpasm_runtime_error(ctx, 1, strclone(a->data));
723 }
724 return strclone(i);
725 }
726
727 return strclone(a->data);
728 }
729
730 static void execute(tmpasm_t *ctx, tmpasm_exec_t *e)
731 {
732 tmpasm_case_t *c;
733 void *state;
734 char *cond, *list;
735 const char *i;
736
737 while((e != NULL) && (ctx->runtime_error == 0) && (ctx->halt == 0)) {
738 ctx->executing = e;
739 switch(e->kw) {
740 case KW_none:
741 if (e->payload.instr.call != NULL)
742 e->payload.instr.call(ctx, e->payload.instr.call_name, e->payload.instr.argc, e->payload.instr.argv);
743 else
744 tmpasm_runtime_error(ctx, 4, e->payload.instr.call_name);
745 break;
746 case KW_IF:
747 cond = tmpasm_arg2str(ctx, e->payload.fc_if.cond, 0);
748 if (ctx->cb->is_true(ctx, cond))
749 execute(ctx, e->payload.fc_if.code_then);
750 else
751 execute(ctx, e->payload.fc_if.code_else);
752 free(cond);
753 break;
754 case KW_FOREACH:
755 list = tmpasm_arg2str(ctx, e->payload.fc_foreach.data, 0);
756 for(i = ctx->cb->first(ctx, &state, list); i != NULL; i = ctx->cb->next(ctx, &state)) {
757 ctx->cb->set(ctx, e->payload.fc_foreach.loop_var, i);
758 execute(ctx, e->payload.fc_foreach.code_body);
759 }
760 free(list);
761 break;
762 case KW_SWITCH:
763 cond = tmpasm_arg2str(ctx, e->payload.fc_switch.cond, 0);
764 for(c = e->payload.fc_switch.first; c != NULL; c = c->next) {
765 char *cv = NULL;
766 if (c->data != NULL)
767 cv = tmpasm_arg2str(ctx, c->data, 0);
768 if ((c->data == NULL) || (ctx->cb->match(ctx, cond, cv))) {
769 execute(ctx, c->body);
770 if (cv != NULL)
771 free(cv);
772 break;
773 }
774 if (cv != NULL)
775 free(cv);
776 }
777 free(cond);
778 break;
779 default:;
780 }
781 e = e->next;
782 }
783 }
784
785 void tmpasm_execute(tmpasm_t *ctx)
786 {
787 if (TOP->next != NULL) {
788 ctx->executing = TOP->next->last_code;
789 tmpasm_runtime_error(ctx, 3, NULL);
790 return;
791 }
792 if ((TOP->state != ST_PRECMD) || (TOP->kw != KW_none)) {
793 ctx->executing = TOP->last_code;
794 tmpasm_runtime_error(ctx, 3, NULL);
795 return;
796 }
797 ctx->halt = 0;
798 ctx->runtime_error = 0;
799 if (ctx->runtime_error_data != NULL) {
800 free(ctx->runtime_error_data);
801 ctx->runtime_error_data = NULL;
802 }
803 if (ctx->cb->preexec != NULL)
804 ctx->cb->preexec(ctx);
805 execute(ctx, ctx->code);
806 if (ctx->cb->postexec != NULL)
807 ctx->cb->postexec(ctx);
808 }
809
0 #ifndef TMPASM_H
1 #define TMPASM_H
2 #ifndef TMPASM_INSTR_MAXLEN
3 #define TMPASM_INSTR_MAXLEN 32
4 #endif
5
6 typedef struct tmpasm_s tmpasm_t;
7
8 typedef struct tmpasm_arg_s tmpasm_arg_t;
9
10 struct tmpasm_arg_s {
11 tmpasm_arg_t *next; /* block: the resulting string is a list of strings and addresses */
12 char is_addr; /* 1: arg is a node address; 0: arg is a string immediate */
13 char data[1]; /* arg string - obviously longer than 1 char (but there's not special hack for that in C89), \0 terminated */
14 };
15
16 /* user specified instruction prototype */
17 typedef void tmpasm_instr(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[]);
18
19
20 typedef struct tmpasm_cb_s {
21 /* return the value of a node at addr - NULL is an error */
22 const char *(*get)(tmpasm_t *ctx, const char *addr);
23
24 /* set the value of a node at addr to data; data may be NULL */
25 void (*set)(tmpasm_t *ctx, const char *addr, const char *data);
26
27 /* return 1 if data is true, 0 otherwise; data may be NULL (if an unknown variable is referenced) */
28 int (*is_true)(tmpasm_t *ctx, const char *data);
29
30 /* return 1 if str matches pat, 0 otherwise; str and pat may be NULL */
31 int (*match)(tmpasm_t *ctx, const char *str, const char *pat);
32
33 /* first iteration over list; return the first element (or NULL to end); the string returned is not free'd by the caller */
34 const char *(*first)(tmpasm_t *ctx, void **state, char *list);
35
36 /* return next element of a list or NULL on end (in which case state shall be also free'd by the caller); the string returned is not free'd by the caller */
37 const char *(*next)(tmpasm_t *ctx, void **state);
38
39 /* resolve an instruction name to a function pointer */
40 tmpasm_instr *(*resolve)(tmpasm_t *ctx, const char *name);
41
42 /* optional: called once before execution of a context starts */
43 void (*preexec)(tmpasm_t *ctx);
44
45 /* optional: called once before execution of a context starts */
46 void (*postexec)(tmpasm_t *ctx);
47
48 /* optional: resolve the current runtime error, called only for negative
49 error codes; should return a format string with exactly one %s in it
50 or NULL. */
51 const char *(*runtime_error_fmt)(tmpasm_t *ctx);
52 } tmpasm_cb_t;
53
54 int tmpasm_gotchar(tmpasm_t *ctx, char c);
55
56 tmpasm_t *tmpasm_init(const tmpasm_cb_t *cb);
57 void tmpasm_uninit(tmpasm_t *ctx);
58
59 /* return the string version of an arg in a newly malloc()'d string
60 if keep_addr is non-zero and a is a single address, no get() is run
61 but the address is returned as a string */
62 char *tmpasm_arg2str(tmpasm_t *ctx, tmpasm_arg_t *a, int keep_addr);
63
64 /* execute the code recursively until it exits */
65 void tmpasm_execute(tmpasm_t *ctx);
66
67 /* Set or get the runtime error of a context. 0 means no error, negative
68 codes are user errors handled by the runtime_error_fmt() callback
69 and positive codes are internal error. */
70 void tmpasm_runtime_error(tmpasm_t *ctx, int code, const char *data);
71 const char *tmpasm_runtime_error_fmt(tmpasm_t *ctx);
72
73 /* --- internals: not required for normal use --- */
74 typedef enum {
75 ST_PRECMD, /* waiting for a command to start - ignore whitespace */
76 ST_CMD,
77 ST_PREDATA, /* waiting for data */
78 ST_PREBLOCKSEP, /* waiting for a block sep when opening a block */
79 ST_BLOCKSEP, /* found a block sep within the block - either an address or a termination follows */
80 ST_BLOCK, /* in [@ @] block, text part */
81 ST_BLOCK_INLINE, /* in [@ @] block, within inline @@ part */
82 ST_STRING, /* in {} string */
83 ST_STRING_ESCAPE, /* in {} string, right after a \ */
84 ST_ADDRESS, /* shifting address bytes */
85 ST_COMMENT /* after #, until the next newline */
86 } tmpasm_state_t;
87
88 typedef enum {
89 KW_none,
90 KW_IF,
91 KW_THEN,
92 KW_ELSE,
93 KW_END,
94 KW_FOREACH,
95 KW_IN,
96 KW_SWITCH,
97 KW_CASE,
98 KW_DEFAULT,
99
100 KW_NOP /* virtual instruction */
101 } tmpasm_kw_t;
102
103 /* execution structs */
104 typedef struct tmpasm_exec_s tmpasm_exec_t;
105 typedef struct tmpasm_case_s tmpasm_case_t;
106
107 struct tmpasm_case_s {
108 tmpasm_arg_t *data;
109 tmpasm_exec_t *body;
110 tmpasm_case_t *next;
111 };
112
113
114 struct tmpasm_exec_s {
115 tmpasm_kw_t kw; /* kw_none means a hook instruction */
116 union {
117 struct { /* normal instruction */
118 tmpasm_instr *call;
119 char *call_name; /* temporary */
120 int argc;
121 tmpasm_arg_t **argv;
122 } instr;
123 struct {
124 tmpasm_arg_t *cond;
125 tmpasm_exec_t *code_then;
126 tmpasm_exec_t *code_else;
127 } fc_if;
128 struct {
129 char *loop_var; /* must be a single address */
130 tmpasm_arg_t *data; /* what to loop in */
131 tmpasm_exec_t *code_body;
132 } fc_foreach;
133 struct {
134 tmpasm_arg_t *cond;
135 tmpasm_case_t *first;
136 tmpasm_case_t *last;
137 } fc_switch;
138 } payload;
139 int line, col;
140 tmpasm_exec_t *next;
141 };
142
143
144 /* parser structs */
145 typedef struct stack_s tmpasm_stack_t;
146 struct stack_s {
147 tmpasm_state_t state;
148 /* tmpasm_state_t kwstate; internal states of composite keywords like switch */
149 char cmd_buff[TMPASM_INSTR_MAXLEN+1];
150 unsigned int cmdi;
151 tmpasm_kw_t kw, old_kw;
152 char block_sep;
153 int kwcol, kwline;
154
155 int args_used, args_alloced; /* number of arguments in argv[] */
156
157 tmpasm_arg_t **argv; /* an array of linked lists */
158 tmpasm_arg_t **argend; /* each argv[] is a linked list (for blocks); argend points to the tail */
159 int *arg_alloced; /* of argend */
160 int *arg_used; /* of argend */
161
162 tmpasm_exec_t *last_code; /* tail of the code list */
163
164 tmpasm_stack_t *next;
165 };
166
167 struct tmpasm_s {
168 tmpasm_stack_t *st;
169 int dead;
170 int col, line;
171 tmpasm_exec_t *code;
172 tmpasm_exec_t *executing; /* points to the code most recently executed (or being executed when in callbacks) */
173 const tmpasm_cb_t *cb;
174 int halt;
175 int runtime_error;
176 char *runtime_error_data;
177 int runtime_error_line;
178 int runtime_error_col;
179 void *user_data;
180 };
181 #endif
0 #include <stdlib.h>
1 #include <stdio.h>
2 #include <string.h>
3 #include "tmpasm.h"
4 #include "db.h"
5 #include "regex.h"
6 #include "openfiles.h"
7 #include "libs.h"
8 #include "tmpasm_scconfig.h"
9 #include "log.h"
10 #include "regex.h"
11
12 #ifndef TMPASM_PATH
13 #define TMPASM_PATH "/tmpasm"
14 #endif
15
16 #ifndef IFS_PATH
17 #define IFS_PATH TMPASM_PATH "/IFS"
18 #endif
19
20 #ifndef IFS_DEFAULT
21 #define IFS_DEFAULT " \t\r\n"
22 #endif
23
24 #ifndef OFS_PATH
25 #define OFS_PATH TMPASM_PATH "/OFS"
26 #endif
27
28 #ifndef OFS_DEFAULT
29 #define OFS_DEFAULT "\n"
30 #endif
31
32 typedef struct scc_s {
33 openfiles_t ofl;
34 FILE *fout, *default_fout;
35 const char *cwd;
36 } scc_t;
37
38 static const char *scc_runtime_error_fmts[] = {
39 /* -0 */ "success scc %s",
40 /* -1 */ "\"put\" requires exactly two arguments (got %s)",
41 /* -2 */ "not enough arguments for sub; should be \"sub node pattern str\"%s",
42 /* -3 */ "regex syntax error: %s",
43 /* -4 */ "not enough arguments for uniq; should be \"uniq destnode\" or \"uniq destnode src\"%s",
44 /* -5 */ "redir: too many arguments%s",
45 /* -6 */ "redir: can't open %s",
46 /* -7 */ "exiting due to a previous runtime error occurred in included file %s",
47 /* -8 */ "can't include '%s': can't open file",
48 /* -9 */ "\"put\" requires two or three arguments (got %s)",
49 /* -10 */ "\"order\" requires 4 or 5 arguments: \"order destnode word before|after word\" or \"order destnode src word before|after word\"",
50 /* -11 */ "\"uniq\" got too many grouping regular expressions",
51 NULL
52 };
53
54 static int print_runtime_error(tmpasm_t *ctx, const char *ifn)
55 {
56 if (ctx->runtime_error != 0) {
57 const char *fmt = tmpasm_runtime_error_fmt(ctx);
58 fprintf(stderr, "Runtime error at %s %d:%d: ", ifn, ctx->runtime_error_line, ctx->runtime_error_col);
59 fprintf(stderr, fmt, (ctx->runtime_error_data == NULL ? "" : ctx->runtime_error_data));
60 fprintf(stderr, "\n");
61 return -1;
62 }
63 return 0;
64 }
65
66 /* allocate and build a full path using ud->cwd and fn */
67 static char *scc_path(scc_t *ud, const char *fn)
68 {
69 if (ud->cwd == NULL)
70 return strclone(fn);
71 return str_concat("", ud->cwd, "/", fn, NULL);
72 }
73
74 /******** db binding ********/
75
76 static const char *scc_get(tmpasm_t *ctx, const char *addr)
77 {
78 (void) ctx; /* not used */
79
80 if (*addr == '&') { /* return whether exists */
81 if (get(addr+1) != NULL)
82 return strue;
83 return sfalse;
84 }
85
86 if (*addr == '?') { /* safe get: return "" instead of NULL to avoid runtime error */
87 const char *res = get(addr+1);
88 if (res == NULL)
89 return "";
90 return res;
91 }
92 return get(addr);
93 }
94
95 static void scc_set(tmpasm_t *ctx, const char *addr, const char *data)
96 {
97 (void) ctx; /* not used */
98 put(addr, data);
99 }
100
101 static int scc_is_true(tmpasm_t *ctx, const char *data)
102 {
103 (void) ctx; /* not used */
104 return ((strcmp(data, "1") == 0) || istrue(data));
105 }
106
107 static int scc_match(tmpasm_t *ctx, const char *str, const char *pat)
108 {
109 (void) ctx; /* not used */
110 re_comp(pat);
111 return re_exec(str);
112 }
113
114 static const char *scc_ifs(tmpasm_t *ctx)
115 {
116 const char *ifs = get(IFS_PATH);
117 (void) ctx; /* not used */
118 if (ifs == NULL)
119 return IFS_DEFAULT;
120 return ifs;
121 }
122
123 static const char *scc_ofs(tmpasm_t *ctx)
124 {
125 const char *ofs = get(OFS_PATH);
126 (void) ctx; /* not used */
127 if (ofs == NULL)
128 return OFS_DEFAULT;
129 return ofs;
130 }
131
132 static const char *scc_next(tmpasm_t *ctx, void **state)
133 {
134 char **s = (char **)state;
135 char *start;
136 const char *IFS;
137
138 IFS = scc_ifs(ctx);
139
140 /* strip leading whitespace */
141 while(chr_inset(**s, IFS)) (*s)++;
142
143 /* at the end of the string, no more tokens */
144 if (**s == '\0')
145 return NULL;
146
147 start = *s;
148
149 /* skip non-whitespace */
150 while(!(chr_inset(**s, IFS)) && (**s != '\0')) (*s)++;
151
152 if (**s != '\0') {
153 **s = '\0';
154 (*s)++;
155 }
156 return start;
157 }
158
159
160 static const char *scc_first(tmpasm_t *ctx, void **state, char *list)
161 {
162 *state = list;
163
164 return scc_next(ctx, state);
165 }
166
167
168 /******** instructions ********/
169 static void instr_put(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
170 {
171 char *addr, *val;
172 (void) iname; /* not used */
173 if (argc != 2) {
174 char str[16];
175 sprintf(str, "%d", argc);
176 tmpasm_runtime_error(ctx, -1, str);
177 return;
178 }
179 addr = tmpasm_arg2str(ctx, argv[0], 1);
180 val = tmpasm_arg2str(ctx, argv[1], 0);
181 if (*addr != '\0')
182 put(addr, val);
183 free(addr);
184 free(val);
185 }
186
187
188 static void instr_append(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
189 {
190 char *addr, *val;
191 char *sep;
192 (void) iname; /* not used */
193
194 if ((argc < 2) || (argc > 3)) {
195 char str[16];
196 sprintf(str, "%d", argc);
197 tmpasm_runtime_error(ctx, -9, str);
198 return;
199 }
200 addr = tmpasm_arg2str(ctx, argv[0], 1);
201 val = tmpasm_arg2str(ctx, argv[1], 0);
202 if (argc >= 3)
203 sep = tmpasm_arg2str(ctx, argv[2], 0);
204 else
205 sep = strclone(scc_ofs(ctx));
206 if (*addr != '\0') {
207 append(addr, sep);
208 append(addr, val);
209 }
210 free(addr);
211 free(val);
212 free(sep);
213 }
214
215 static void instr_report(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
216 {
217 int n;
218 (void) iname; /* not used */
219 for(n = 0; n < argc; n++) {
220 char *val;
221 val = tmpasm_arg2str(ctx, argv[n], 0);
222 report("%s", val);
223 free(val);
224 }
225 }
226
227 static void instr_abort(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
228 {
229 scc_t *ud = (scc_t *)ctx->user_data;
230 (void) iname; /* not used */
231 (void) argc; /* not used */
232 (void) argv; /* not used */
233 report("Abort requested by template.\n");
234 if (ud->fout) fflush(ud->fout);
235 fflush(stdout);
236 fflush(stderr);
237 abort();
238 }
239
240 static void instr_halt(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
241 {
242 (void) iname; /* not used */
243 (void) argc; /* not used */
244 (void) argv; /* not used */
245 ctx->halt = 1;
246 }
247
248 static void instr_sub(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
249 {
250 char *node, *pat, *err, *csub, *buff, *end;
251 const char *start;
252 const char *val;
253 int score, slen, global;
254
255 if (argc < 3) {
256 tmpasm_runtime_error(ctx, -2, NULL);
257 return;
258 }
259
260 node = tmpasm_arg2str(ctx, argv[0], 1);
261 pat = tmpasm_arg2str(ctx, argv[1], 0);
262 csub = tmpasm_arg2str(ctx, argv[2], 0);
263 global = (*iname == 'g');
264
265 val = get(node);
266 if (val == NULL)
267 val="";
268 err = re_comp(pat);
269 if (err != NULL) {
270 tmpasm_runtime_error(ctx, -3, err);
271 return;
272 }
273
274 slen = strlen(csub);
275 if (global)
276 buff = malloc(strlen(val)*(slen+3)+32); /* big enough for worst case, when every letter and $ and ^ are replaced with sub */
277 else
278 buff = malloc(strlen(val)+slen+32); /* only one replacement will be done */
279 strcpy(buff, val);
280
281 start = buff;
282 do {
283 score = re_exec(start);
284 if (score == 0)
285 break;
286 end = buff + strlen(buff);
287 if (eopat[0] - bopat[0] != slen) {
288 int mlen = end - eopat[0]+1;
289 if (mlen > 0)
290 memmove((char *)(bopat[0] + slen), eopat[0], mlen);
291 }
292 memcpy((char *)bopat[0], csub, slen);
293 start = bopat[0] + slen;
294 } while(global);
295
296 buff = realloc(buff, strlen(buff)+1);
297 put(node, buff);
298 free(buff);
299 free(node);
300 free(pat);
301 free(csub);
302 }
303
304 #define UNIQ_ERE_MAX 16
305 static char *uniq_eres[UNIQ_ERE_MAX];
306
307 static void instr_uniq(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
308 {
309 char *node, *strlist, *buff;
310 int eres = 0;
311
312 if (argc < 1) {
313 tmpasm_runtime_error(ctx, -4, NULL);
314 return;
315 }
316 node = tmpasm_arg2str(ctx, argv[0], 1);
317 if (argc > 1) {
318 int offs = 2;
319
320 strlist = tmpasm_arg2str(ctx, argv[1], 0);
321 if ((argc-offs) >= UNIQ_ERE_MAX) {
322 tmpasm_runtime_error(ctx, -11, NULL);
323 return;
324 }
325 while(argc > offs)
326 uniq_eres[eres++] = tmpasm_arg2str(ctx, argv[offs++], 0);
327 if (eres > 0)
328 uniq_eres[eres++] = ".*";
329 }
330 else
331 strlist = strclone(get(node));
332 buff = uniq_inc_str(strlist, scc_ifs(ctx), scc_ofs(ctx), (*iname == 's'), eres, uniq_eres);
333 put(node, buff);
334 free(buff);
335 free(strlist);
336 free(node);
337 }
338
339 static void instr_order(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
340 {
341 char *node, *strlist, *buff, *w1, *dirs, *w2;
342 int offs, dir;
343
344 if ((argc != 4) && (argc != 5)) {
345 tmpasm_runtime_error(ctx, -10, NULL);
346 return;
347 }
348 node = tmpasm_arg2str(ctx, argv[0], 1);
349 if (argc > 4) {
350 strlist = tmpasm_arg2str(ctx, argv[1], 0);
351 offs = 2;
352 }
353 else {
354 strlist = strclone(get(node));
355 offs = 1;
356 }
357
358 w1 = tmpasm_arg2str(ctx, argv[offs], 0);
359 dirs = tmpasm_arg2str(ctx, argv[offs+1], 0);
360 w2 = tmpasm_arg2str(ctx, argv[offs+2], 0);
361
362 if (strcmp(dirs, "before") == 0)
363 dir = -1;
364 else if (strcmp(dirs, "after") == 0)
365 dir = +1;
366 else {
367 tmpasm_runtime_error(ctx, -10, NULL);
368 return;
369 }
370
371 buff = order_inc_str(strlist, scc_ifs(ctx), w1, dir, w2);
372 put(node, buff);
373 free(buff);
374 free(strlist);
375 free(node);
376 }
377
378 static void instr_print(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
379 {
380 int n;
381 scc_t *ud = (scc_t *)ctx->user_data;
382 (void) iname; /* not used */
383
384 for(n = 0; n < argc; n++) {
385 char *val;
386 val = tmpasm_arg2str(ctx, argv[n], 0);
387 fprintf(ud->fout, "%s", val);
388 free(val);
389 }
390 }
391
392 static void instr_print_ternary(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
393 {
394 char *s_cond, *s;
395 scc_t *ud = (scc_t *)ctx->user_data;
396 (void) iname; /* not used */
397
398 if ((argc < 2) || (argc > 3)) {
399 char str[16];
400 sprintf(str, "%d", argc);
401 tmpasm_runtime_error(ctx, -1, str);
402 return;
403 }
404
405 s_cond = tmpasm_arg2str(ctx, argv[0], 0);
406
407 if (ctx->cb->is_true(ctx, s_cond))
408 s = tmpasm_arg2str(ctx, argv[1], 0);
409 else
410 s = tmpasm_arg2str(ctx, argv[2], 0);
411
412 fprintf(ud->fout, "%s", s);
413
414 free(s_cond);
415 free(s);
416 }
417
418 static void scc_tmpasm_parse_(tmpasm_t *ctx, const char *cwd, FILE *fin, FILE *default_fout, FILE *fout)
419 {
420 scc_t *ud = malloc(sizeof(scc_t));
421 memset(&ud->ofl, 0, sizeof(ud->ofl));
422 ctx->user_data = ud;
423 ud->default_fout = default_fout;
424 ud->fout = fout;
425 ud->cwd = cwd;
426
427 for(;;) {
428 int c;
429 c = fgetc(fin);
430 if (c == EOF)
431 break;
432 tmpasm_gotchar(ctx, c);
433 }
434
435 }
436
437 void scc_tmpasm_parse(tmpasm_t *ctx, const char *cwd, FILE *fin, FILE *fout)
438 {
439 scc_tmpasm_parse_(ctx, cwd, fin, fout, fout);
440 }
441
442 #ifndef NO_FILE_IO
443 static void instr_include(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
444 {
445 scc_t *ud = (scc_t *)ctx->user_data;
446 int n;
447 (void) iname; /* not used */
448
449 for(n = 0; n < argc; n++) {
450 char *fn, *path;
451 FILE *fin;
452 tmpasm_t *child;
453
454 fn = tmpasm_arg2str(ctx, argv[n], 0);
455 path = scc_path(ud, fn);
456 fin = fopen(path, "r");
457 if (fin == NULL) {
458 tmpasm_runtime_error(ctx, -8, path);
459 free(fn);
460 free(path);
461 return;
462 }
463 child = tmpasm_init(ctx->cb);
464 scc_tmpasm_parse_(child, ud->cwd, fin, ud->default_fout, ud->fout);
465 tmpasm_execute(child);
466 if (print_runtime_error(child, path) != 0)
467 tmpasm_runtime_error(ctx, -7, path);
468 tmpasm_uninit(child);
469 fclose(fin);
470 free(fn);
471 free(path);
472 }
473 }
474
475
476 static void instr_redir(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
477 {
478 char *path, *fn, *mode;
479 scc_t *ud = (scc_t *)ctx->user_data;
480 (void) iname; /* not used */
481 fflush(ud->fout);
482 switch(argc) {
483 case 0: ud->fout = ud->default_fout; return; /* set redirection to default */
484 case 1: mode = strclone("w"); break;
485 case 2: mode = tmpasm_arg2str(ctx, argv[1], 0); break;
486 default:
487 tmpasm_runtime_error(ctx, -5, NULL);
488 return;
489 }
490
491 fn = tmpasm_arg2str(ctx, argv[0], 0);
492 path = scc_path(ud, fn);
493 ud->fout = openfile_open(&ud->ofl, path, mode);
494 if (ud->fout == NULL) {
495 char *err = malloc(strlen(fn) + strlen(path) + strlen(mode) + 16);
496 sprintf(err, "%s (%s) for %s", path, fn, mode);
497 tmpasm_runtime_error(ctx, -6, err);
498 free(err);
499 free(path);
500 return;
501 }
502 free(fn);
503 free(mode);
504 free(path);
505 }
506 #endif
507
508 #ifdef TMPASM_TESTER
509 static void instr_unknown(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[])
510 {
511 printf("ERROR: unknown instruction '%s'\n", iname);
512 }
513 #endif
514
515
516 /******** interface ********/
517
518 tmpasm_instr *scc_resolve(tmpasm_t *ctx, const char *name)
519 {
520 (void) ctx; /* not used */
521 /* TODO: make this a hash */
522 if (strcmp(name, "put") == 0)
523 return instr_put;
524 if (strcmp(name, "append") == 0)
525 return instr_append;
526 if (strcmp(name, "print") == 0)
527 return instr_print;
528 if (strcmp(name, "print_ternary") == 0)
529 return instr_print_ternary;
530 #ifndef TMPASM_NO_FILE_IO
531 if (strcmp(name, "redir") == 0)
532 return instr_redir;
533 if (strcmp(name, "include") == 0)
534 return instr_include;
535 #endif
536 if (strcmp(name, "report") == 0)
537 return instr_report;
538 if (strcmp(name, "abort") == 0)
539 return instr_abort;
540 if (strcmp(name, "halt") == 0)
541 return instr_halt;
542 if (strcmp(name, "uniq") == 0)
543 return instr_uniq;
544 if (strcmp(name, "order") == 0)
545 return instr_order;
546 if (strcmp(name, "sortuniq") == 0)
547 return instr_uniq;
548 if ((strcmp(name, "sub") == 0) || (strcmp(name, "gsub") == 0))
549 return instr_sub;
550
551 #ifndef TMPASM_TESTER
552 return NULL;
553 #else
554 return instr_unknown;
555 #endif
556 }
557
558
559 static const char *scc_err_fmt(tmpasm_t *ctx)
560 {
561 int code;
562 code = -ctx->runtime_error;
563
564 if ((code < 0) || ((size_t)code > (sizeof(scc_runtime_error_fmts)/sizeof(char *))))
565 return NULL;
566 return scc_runtime_error_fmts[code];
567 }
568
569
570 static void scc_preexec(tmpasm_t *ctx)
571 {
572 (void) ctx; /* not used */
573 db_mkdir(TMPASM_PATH);
574 }
575
576 static void scc_postexec(tmpasm_t *ctx)
577 {
578 scc_t *ud = (scc_t *)ctx->user_data;
579 openfile_free(&ud->ofl);
580 free(ud);
581 }
582
583 tmpasm_cb_t scc_cb = {
584 scc_get, scc_set, scc_is_true, scc_match, scc_first, scc_next,
585 scc_resolve, scc_preexec, scc_postexec, scc_err_fmt
586 };
587
588 int tmpasm(const char *wdir, const char *input, const char *output)
589 {
590 tmpasm_t *ctx;
591 FILE *fin, *fout;
592 int ret;
593 scc_t ud_tmp;
594 char *path;
595
596 ud_tmp.cwd = wdir;
597
598 path = scc_path(&ud_tmp, input);
599 fin = fopen(path, "r");
600 if (fin == NULL) {
601 fprintf(stderr, "ERROR: tmpasm: can not open script '%s' (%s in %s)\n", path, input, wdir);
602 free(path);
603 return -1;
604 }
605 free(path);
606
607 path = scc_path(&ud_tmp, output);
608 fout = fopen(path, "w");
609 if (fout == NULL) {
610 fprintf(stderr, "ERROR: tmpasm: can not open output '%s' (%s in %s)\n", path, output, wdir);
611 free(path);
612 return -1;
613 }
614 free(path);
615
616 ctx = tmpasm_init(&scc_cb);
617 scc_tmpasm_parse_(ctx, wdir, fin, fout, fout);
618 if (!ctx->dead)
619 tmpasm_execute(ctx);
620 fclose(fin);
621 fclose(fout);
622
623 ret = print_runtime_error(ctx, input);
624
625 tmpasm_uninit(ctx);
626 return ret;
627 }
628
629 FILE *tmpasm_fout(tmpasm_t *ctx)
630 {
631 scc_t *ud = (scc_t *)ctx->user_data;
632 return ud->fout;
633 }
0 #include <stdio.h>
1 #include "tmpasm.h"
2
3 int tmpasm(const char *wdir, const char *input, const char *output);
4
5 void scc_tmpasm_parse(tmpasm_t *ctx, const char *cwd, FILE *fin, FILE *fout);
6
7 FILE *tmpasm_fout(tmpasm_t *ctx);
8
9 tmpasm_instr *scc_resolve(tmpasm_t *ctx, const char *name);
10
11 extern tmpasm_cb_t scc_cb;
12
13
0 all:
1 cd libmawk && $(MAKE)
2 # cd example_apps && $(MAKE) all
3
4 test:
5 cd libmawk && $(MAKE) test
6
7 install:
8 cd libmawk && $(MAKE) install
9 # cd example_apps && $(MAKE) install
10
11 uninstall:
12 cd libmawk && $(MAKE) uninstall
13 # cd example_apps && $(MAKE) uninstall
14
15 linstall:
16 cd libmawk && $(MAKE) linstall
17 # cd example_apps && $(MAKE) linstall
18
19 clean:
20 # cd example_apps && $(MAKE) clean
21 cd awklib && $(MAKE) clean
22 cd libmawk && $(MAKE) clean
23
24 distclean:
25 # cd example_apps && $(MAKE) distclean
26 cd awklib && $(MAKE) distclean
27 cd libmawk && $(MAKE) distclean
0 put /tmpasm/IFS { }
1 put /local/libs {lib_array lib_ascii lib_rand}
2
3 print [@
4 # Generated by scconfig from Makefile.in
5 LIBPATH=$(install_root)/usr/lib/libmawk
6
7 all:
8
9 install:
10 @fstools/mkdir@ $(LIBPATH)
11 @]
12 foreach /local/n in /local/libs
13 print [@ @fstools/cp@ @/local/n@.awk $(LIBPATH)/@/local/n@.awk
14 @]
15 end
16
17 print [@
18 linstall:
19 @fstools/mkdir@ $(LIBPATH)
20 @]
21 foreach /local/n in /local/libs
22 print [@ @fstools/ln@ @/local/n@.awk $(LIBPATH)/@/local/n@.awk
23 @]
24 end
25
26 print [@
27 uninstall:
28 @]
29 foreach /local/n in /local/libs
30 print [@ @fstools/rm@ $(LIBPATH)/@/local/n@.awk
31 @]
32 end
33
34 print [@
35 test:
36 cd regression && make
37
38 clean:
39
40 distclean: clean
41 -rm Makefile regression/Makefile
42 @]
43
44 put /tmpasm/IFS {}
0 function lib_array_version()
1 {
2 return 1
3 }
4
5 BEGIN {
6 # item open: ASCII "start of text"
7 LIB_ARRAY_SOPEN = "\002"
8 # item close: ASCII "end of text"
9 LIB_ARRAY_SCLOSE = "\003"
10 # index/value separator: ASCII "unit separator"
11 LIB_ARRAY_SSEP = "\036"
12 }
13
14 # print an array; each element in a new line prefixed by prefix
15 function lib_array_print(prefix, A ,n)
16 {
17 for(n in A)
18 print prefix "[" n "] = '" A[n] "'"
19 }
20
21 # Pack an array to a single string. Optionally use Sopen/Sclose/Ssep for
22 # separator characters. Each element of the array is packed in the following
23 # sequence: Sopen <index> Ssep <value> Sclose; index can not contain Ssep,
24 # but value may contain a full packed array using the same separators.
25 # If Sopen/Sclose/Ssep are empty, default separators are used
26 # (LIB_ARRAY_SOPEN/LIB_ARRAY_SCLOSE/LIB_ARRAY_SSEP).
27 function lib_array_pack(A, Sopen, Sclose, Ssep, n,s)
28 {
29 s=""
30 if (Sopen == "") Sopen = LIB_ARRAY_SOPEN
31 if (Sclose == "") Sclose = LIB_ARRAY_SCLOSE
32 if (Ssep == "") Ssep = LIB_ARRAY_SSEP
33
34 for(n in A)
35 s = s Sopen n Ssep A[n] Sclose
36
37 return s
38 }
39
40 # Unpack string to an array. Separator rules are the same as
41 # for lib_array_pack(). Returns number of indices found (>=0) or
42 # -1 on syntax error
43 function lib_array_unpack(ARRAY, str, Sopen, Sclose, Ssep, n,len,lvl,c,idx,val,start,idxs)
44 {
45 if (Sopen == "") Sopen = LIB_ARRAY_SOPEN
46 if (Sclose == "") Sclose = LIB_ARRAY_SCLOSE
47 if (Ssep == "") Ssep = LIB_ARRAY_SSEP
48
49 len = length(str);
50 lvl = 0
51 idxs = 0
52 for(n = 1; n <= len; n++) {
53 c = substr(str, n, 1);
54 if (c == Sopen) {
55 lvl++;
56 if (lvl == 1) {
57 n++
58 start = n;
59 while((substr(str, n, 1) != Ssep) && (n <= len)) n++;
60 idx = substr(str, start, n-start)
61 start = n+1;
62 }
63 }
64 else if (c == Sclose) {
65 lvl--
66 if (lvl == 0) {
67 ARRAY[idx] = substr(str, start, n-start)
68 idxs++
69 }
70 }
71 }
72 if (lvl != 0)
73 return -1;
74 return idxs
75 }
76
0 function lib_ascii_version()
1 {
2 return 1
3 }
4
5 # convert an binary character to ascii code (integer)
6 function lib_ascii_ord(chr)
7 {
8 return lib_ascii_ASCII[chr]
9 }
10
11 # ---- initializing the ASCII table ----
12 # Slowest variant: 10k runs at 2.241 seconds on a machine
13 # for(n = 0; n < 256; n = n+1)
14 # lib_ascii_ASCII[sprintf("%c", n)] = n
15 #
16 # a bit faster: 10k runs at 1.604 on the same machine
17 # split("\001 \002 \003 \004 \005 \006 \007 \010 \011 \012 \013 \014 \015 \016 \017 \020 \021 \022 \023 \024 \025 \026 \027 \030 \031 \032 \033 \034 \035 \036 \037 ! \041 \042 \043 \044 \045 \046 \047 \050 \051 \052 \053 \054 \055 \056 \057 \060 \061 \062 \063 \064 \065 \066 \067 \070 \071 \072 \073 \074 \075 \076 \077 \100 \101 \102 \103 \104 \105 \106 \107 \110 \111 \112 \113 \114 \115 \116 \117 \120 \121 \122 \123 \124 \125 \126 \127 \130 \131 \132 \133 \134 \135 \136 \137 \140 \141 \142 \143 \144 \145 \146 \147 \150 \151 \152 \153 \154 \155 \156 \157 \160 \161 \162 \163 \164 \165 \166 \167 \170 \171 \172 \173 \174 \175 \176 \177 ", A, " ");
18 # for(n = 1; n < 128; n++) {
19 # lib_ascii_ASCII[A[n]] = n;
20 # }
21 # split("\200 \201 \202 \203 \204 \205 \206 \207 \210 \211 \212 \213 \214 \215 \216 \217 \220 \221 \222 \223 \224 \225 \226 \227 \230 \231 \232 \233 \234 \235 \236 \237 \240 \241 \242 \243 \244 \245 \246 \247 \250 \251 \252 \253 \254 \255 \256 \257 \260 \261 \262 \263 \264 \265 \266 \267 \270 \271 \272 \273 \274 \275 \276 \277 \300 \301 \302 \303 \304 \305 \306 \307 \310 \311 \312 \313 \314 \315 \316 \317 \320 \321 \322 \323 \324 \325 \326 \327 \330 \331 \332 \333 \334 \335 \336 \337 \340 \341 \342 \343 \344 \345 \346 \347 \350 \351 \352 \353 \354 \355 \356 \357 \360 \361 \362 \363 \364 \365 \366 \367 \370 \371 \372 \373 \374 \375 \376 \377", A, " ");
22 # for(n = 1; n < 128; n++) {
23 # lib_ascii_ASCII[A[n]] = n+128;
24 # }
25 # lib_ascii_ASCII["\000"] = 0
26 # lib_ascii_ASCII[" "] = 32
27
28 # Fastest version on the same machine: 0.5 seconds
29 BEGIN {
30 lib_ascii_ASCII["\000"] = 0
31 lib_ascii_ASCII["\001"] = 1
32 lib_ascii_ASCII["\002"] = 2
33 lib_ascii_ASCII["\003"] = 3
34 lib_ascii_ASCII["\004"] = 4
35 lib_ascii_ASCII["\005"] = 5
36 lib_ascii_ASCII["\006"] = 6
37 lib_ascii_ASCII["\007"] = 7
38 lib_ascii_ASCII["\010"] = 8
39 lib_ascii_ASCII["\011"] = 9
40 lib_ascii_ASCII["\012"] = 10
41 lib_ascii_ASCII["\013"] = 11
42 lib_ascii_ASCII["\014"] = 12
43 lib_ascii_ASCII["\015"] = 13
44 lib_ascii_ASCII["\016"] = 14
45 lib_ascii_ASCII["\017"] = 15
46 lib_ascii_ASCII["\020"] = 16
47 lib_ascii_ASCII["\021"] = 17
48 lib_ascii_ASCII["\022"] = 18
49 lib_ascii_ASCII["\023"] = 19
50 lib_ascii_ASCII["\024"] = 20
51 lib_ascii_ASCII["\025"] = 21
52 lib_ascii_ASCII["\026"] = 22
53 lib_ascii_ASCII["\027"] = 23
54 lib_ascii_ASCII["\030"] = 24
55 lib_ascii_ASCII["\031"] = 25
56 lib_ascii_ASCII["\032"] = 26
57 lib_ascii_ASCII["\033"] = 27
58 lib_ascii_ASCII["\034"] = 28
59 lib_ascii_ASCII["\035"] = 29
60 lib_ascii_ASCII["\036"] = 30
61 lib_ascii_ASCII["\037"] = 31
62 lib_ascii_ASCII["\040"] = 32
63 lib_ascii_ASCII["\041"] = 33
64 lib_ascii_ASCII["\042"] = 34
65 lib_ascii_ASCII["\043"] = 35
66 lib_ascii_ASCII["\044"] = 36
67 lib_ascii_ASCII["\045"] = 37
68 lib_ascii_ASCII["\046"] = 38
69 lib_ascii_ASCII["\047"] = 39
70 lib_ascii_ASCII["\050"] = 40
71 lib_ascii_ASCII["\051"] = 41
72 lib_ascii_ASCII["\052"] = 42
73 lib_ascii_ASCII["\053"] = 43
74 lib_ascii_ASCII["\054"] = 44
75 lib_ascii_ASCII["\055"] = 45
76 lib_ascii_ASCII["\056"] = 46
77 lib_ascii_ASCII["\057"] = 47
78 lib_ascii_ASCII["\060"] = 48
79 lib_ascii_ASCII["\061"] = 49
80 lib_ascii_ASCII["\062"] = 50
81 lib_ascii_ASCII["\063"] = 51
82 lib_ascii_ASCII["\064"] = 52
83 lib_ascii_ASCII["\065"] = 53
84 lib_ascii_ASCII["\066"] = 54
85 lib_ascii_ASCII["\067"] = 55
86 lib_ascii_ASCII["\070"] = 56
87 lib_ascii_ASCII["\071"] = 57
88 lib_ascii_ASCII["\072"] = 58
89 lib_ascii_ASCII["\073"] = 59
90 lib_ascii_ASCII["\074"] = 60
91 lib_ascii_ASCII["\075"] = 61
92 lib_ascii_ASCII["\076"] = 62
93 lib_ascii_ASCII["\077"] = 63
94 lib_ascii_ASCII["\100"] = 64
95 lib_ascii_ASCII["\101"] = 65
96 lib_ascii_ASCII["\102"] = 66
97 lib_ascii_ASCII["\103"] = 67
98 lib_ascii_ASCII["\104"] = 68
99 lib_ascii_ASCII["\105"] = 69
100 lib_ascii_ASCII["\106"] = 70
101 lib_ascii_ASCII["\107"] = 71
102 lib_ascii_ASCII["\110"] = 72
103 lib_ascii_ASCII["\111"] = 73
104 lib_ascii_ASCII["\112"] = 74
105 lib_ascii_ASCII["\113"] = 75
106 lib_ascii_ASCII["\114"] = 76
107 lib_ascii_ASCII["\115"] = 77
108 lib_ascii_ASCII["\116"] = 78
109 lib_ascii_ASCII["\117"] = 79
110 lib_ascii_ASCII["\120"] = 80
111 lib_ascii_ASCII["\121"] = 81
112 lib_ascii_ASCII["\122"] = 82
113 lib_ascii_ASCII["\123"] = 83
114 lib_ascii_ASCII["\124"] = 84
115 lib_ascii_ASCII["\125"] = 85
116 lib_ascii_ASCII["\126"] = 86
117 lib_ascii_ASCII["\127"] = 87
118 lib_ascii_ASCII["\130"] = 88
119 lib_ascii_ASCII["\131"] = 89
120 lib_ascii_ASCII["\132"] = 90
121 lib_ascii_ASCII["\133"] = 91
122 lib_ascii_ASCII["\134"] = 92
123 lib_ascii_ASCII["\135"] = 93
124 lib_ascii_ASCII["\136"] = 94
125 lib_ascii_ASCII["\137"] = 95
126 lib_ascii_ASCII["\140"] = 96
127 lib_ascii_ASCII["\141"] = 97
128 lib_ascii_ASCII["\142"] = 98
129 lib_ascii_ASCII["\143"] = 99
130 lib_ascii_ASCII["\144"] = 100
131 lib_ascii_ASCII["\145"] = 101
132 lib_ascii_ASCII["\146"] = 102
133 lib_ascii_ASCII["\147"] = 103
134 lib_ascii_ASCII["\150"] = 104
135 lib_ascii_ASCII["\151"] = 105
136 lib_ascii_ASCII["\152"] = 106
137 lib_ascii_ASCII["\153"] = 107
138 lib_ascii_ASCII["\154"] = 108
139 lib_ascii_ASCII["\155"] = 109
140 lib_ascii_ASCII["\156"] = 110
141 lib_ascii_ASCII["\157"] = 111
142 lib_ascii_ASCII["\160"] = 112
143 lib_ascii_ASCII["\161"] = 113
144 lib_ascii_ASCII["\162"] = 114
145 lib_ascii_ASCII["\163"] = 115
146 lib_ascii_ASCII["\164"] = 116
147 lib_ascii_ASCII["\165"] = 117
148 lib_ascii_ASCII["\166"] = 118
149 lib_ascii_ASCII["\167"] = 119
150 lib_ascii_ASCII["\170"] = 120
151 lib_ascii_ASCII["\171"] = 121
152 lib_ascii_ASCII["\172"] = 122
153 lib_ascii_ASCII["\173"] = 123
154 lib_ascii_ASCII["\174"] = 124
155 lib_ascii_ASCII["\175"] = 125
156 lib_ascii_ASCII["\176"] = 126
157 lib_ascii_ASCII["\177"] = 127
158 lib_ascii_ASCII["\200"] = 128
159 lib_ascii_ASCII["\201"] = 129
160 lib_ascii_ASCII["\202"] = 130
161 lib_ascii_ASCII["\203"] = 131
162 lib_ascii_ASCII["\204"] = 132
163 lib_ascii_ASCII["\205"] = 133
164 lib_ascii_ASCII["\206"] = 134
165 lib_ascii_ASCII["\207"] = 135
166 lib_ascii_ASCII["\210"] = 136
167 lib_ascii_ASCII["\211"] = 137
168 lib_ascii_ASCII["\212"] = 138
169 lib_ascii_ASCII["\213"] = 139
170 lib_ascii_ASCII["\214"] = 140
171 lib_ascii_ASCII["\215"] = 141
172 lib_ascii_ASCII["\216"] = 142
173 lib_ascii_ASCII["\217"] = 143
174 lib_ascii_ASCII["\220"] = 144
175 lib_ascii_ASCII["\221"] = 145
176 lib_ascii_ASCII["\222"] = 146
177 lib_ascii_ASCII["\223"] = 147
178 lib_ascii_ASCII["\224"] = 148
179 lib_ascii_ASCII["\225"] = 149
180 lib_ascii_ASCII["\226"] = 150
181 lib_ascii_ASCII["\227"] = 151
182 lib_ascii_ASCII["\230"] = 152
183 lib_ascii_ASCII["\231"] = 153
184 lib_ascii_ASCII["\232"] = 154
185 lib_ascii_ASCII["\233"] = 155
186 lib_ascii_ASCII["\234"] = 156
187 lib_ascii_ASCII["\235"] = 157
188 lib_ascii_ASCII["\236"] = 158
189 lib_ascii_ASCII["\237"] = 159
190 lib_ascii_ASCII["\240"] = 160
191 lib_ascii_ASCII["\241"] = 161
192 lib_ascii_ASCII["\242"] = 162
193 lib_ascii_ASCII["\243"] = 163
194 lib_ascii_ASCII["\244"] = 164
195 lib_ascii_ASCII["\245"] = 165
196 lib_ascii_ASCII["\246"] = 166
197 lib_ascii_ASCII["\247"] = 167
198 lib_ascii_ASCII["\250"] = 168
199 lib_ascii_ASCII["\251"] = 169
200 lib_ascii_ASCII["\252"] = 170
201 lib_ascii_ASCII["\253"] = 171
202 lib_ascii_ASCII["\254"] = 172
203 lib_ascii_ASCII["\255"] = 173
204 lib_ascii_ASCII["\256"] = 174
205 lib_ascii_ASCII["\257"] = 175
206 lib_ascii_ASCII["\260"] = 176
207 lib_ascii_ASCII["\261"] = 177
208 lib_ascii_ASCII["\262"] = 178
209 lib_ascii_ASCII["\263"] = 179
210 lib_ascii_ASCII["\264"] = 180
211 lib_ascii_ASCII["\265"] = 181
212 lib_ascii_ASCII["\266"] = 182
213 lib_ascii_ASCII["\267"] = 183
214 lib_ascii_ASCII["\270"] = 184
215 lib_ascii_ASCII["\271"] = 185
216 lib_ascii_ASCII["\272"] = 186
217 lib_ascii_ASCII["\273"] = 187
218 lib_ascii_ASCII["\274"] = 188
219 lib_ascii_ASCII["\275"] = 189
220 lib_ascii_ASCII["\276"] = 190
221 lib_ascii_ASCII["\277"] = 191
222 lib_ascii_ASCII["\300"] = 192
223 lib_ascii_ASCII["\301"] = 193
224 lib_ascii_ASCII["\302"] = 194
225 lib_ascii_ASCII["\303"] = 195
226 lib_ascii_ASCII["\304"] = 196
227 lib_ascii_ASCII["\305"] = 197
228 lib_ascii_ASCII["\306"] = 198
229 lib_ascii_ASCII["\307"] = 199
230 lib_ascii_ASCII["\310"] = 200
231 lib_ascii_ASCII["\311"] = 201
232 lib_ascii_ASCII["\312"] = 202
233 lib_ascii_ASCII["\313"] = 203
234 lib_ascii_ASCII["\314"] = 204
235 lib_ascii_ASCII["\315"] = 205
236 lib_ascii_ASCII["\316"] = 206
237 lib_ascii_ASCII["\317"] = 207
238 lib_ascii_ASCII["\320"] = 208
239 lib_ascii_ASCII["\321"] = 209
240 lib_ascii_ASCII["\322"] = 210
241 lib_ascii_ASCII["\323"] = 211
242 lib_ascii_ASCII["\324"] = 212
243 lib_ascii_ASCII["\325"] = 213
244 lib_ascii_ASCII["\326"] = 214
245 lib_ascii_ASCII["\327"] = 215
246 lib_ascii_ASCII["\330"] = 216
247 lib_ascii_ASCII["\331"] = 217
248 lib_ascii_ASCII["\332"] = 218
249 lib_ascii_ASCII["\333"] = 219
250 lib_ascii_ASCII["\334"] = 220
251 lib_ascii_ASCII["\335"] = 221
252 lib_ascii_ASCII["\336"] = 222
253 lib_ascii_ASCII["\337"] = 223
254 lib_ascii_ASCII["\340"] = 224
255 lib_ascii_ASCII["\341"] = 225
256 lib_ascii_ASCII["\342"] = 226
257 lib_ascii_ASCII["\343"] = 227
258 lib_ascii_ASCII["\344"] = 228
259 lib_ascii_ASCII["\345"] = 229
260 lib_ascii_ASCII["\346"] = 230
261 lib_ascii_ASCII["\347"] = 231
262 lib_ascii_ASCII["\350"] = 232
263 lib_ascii_ASCII["\351"] = 233
264 lib_ascii_ASCII["\352"] = 234
265 lib_ascii_ASCII["\353"] = 235
266 lib_ascii_ASCII["\354"] = 236
267 lib_ascii_ASCII["\355"] = 237
268 lib_ascii_ASCII["\356"] = 238
269 lib_ascii_ASCII["\357"] = 239
270 lib_ascii_ASCII["\360"] = 240
271 lib_ascii_ASCII["\361"] = 241
272 lib_ascii_ASCII["\362"] = 242
273 lib_ascii_ASCII["\363"] = 243
274 lib_ascii_ASCII["\364"] = 244
275 lib_ascii_ASCII["\365"] = 245
276 lib_ascii_ASCII["\366"] = 246
277 lib_ascii_ASCII["\367"] = 247
278 lib_ascii_ASCII["\370"] = 248
279 lib_ascii_ASCII["\371"] = 249
280 lib_ascii_ASCII["\372"] = 250
281 lib_ascii_ASCII["\373"] = 251
282 lib_ascii_ASCII["\374"] = 252
283 lib_ascii_ASCII["\375"] = 253
284 lib_ascii_ASCII["\376"] = 254
285 lib_ascii_ASCII["\377"] = 255
286 }
287
0 function lib_hex_version()
1 {
2 return 1
3 }
4
5 BEGIN {
6 LIB_HEX["0"] = 0
7 LIB_HEX["1"] = 1
8 LIB_HEX["2"] = 2
9 LIB_HEX["3"] = 3
10 LIB_HEX["4"] = 4
11 LIB_HEX["5"] = 5
12 LIB_HEX["6"] = 6
13 LIB_HEX["7"] = 7
14 LIB_HEX["8"] = 8
15 LIB_HEX["9"] = 9
16 LIB_HEX["A"] = 10
17 LIB_HEX["a"] = 10
18 LIB_HEX["B"] = 11
19 LIB_HEX["b"] = 11
20 LIB_HEX["C"] = 12
21 LIB_HEX["c"] = 12
22 LIB_HEX["D"] = 13
23 LIB_HEX["d"] = 13
24 LIB_HEX["E"] = 14
25 LIB_HEX["e"] = 14
26 LIB_HEX["F"] = 15
27 LIB_HEX["f"] = 15
28 }
29
30 # converts hex number in string to integer; returns "" on error
31 function lib_hex_str2int(s ,v,n,l,c)
32 {
33 sub("^0x", "", s)
34 v = 0;
35 l = length(s)
36 for(n = 1; n <= length(s); n++) {
37 c = substr(s, n, 1)
38 if (!(c in LIB_HEX))
39 return ""
40 v = v * 16 + LIB_HEX[c];
41 }
42 return v
43 }
44
45 function lib_hex_int2str(i)
46 {
47 return sprintf("0x%x", i)
48 }
49
0 function lib_rand_version()
1 {
2 return 1
3 }
4 # core code by nsz
5
6
7 # STATE is an array that stores all states of a random queue
8 # random queues generate pseudo random numbers independently of other queues
9
10 # set random seed on STATE
11 # if seed is not provided, a random number us choosen (use srand() before that)
12 function lib_rand_srand(STATE, seed) {
13 if (seed == "")
14 seed = rand()
15 STATE[lib_rand_state] = lib_rand_mod_2_26(int(seed))
16 }
17
18 # get next random number from queue STATE
19 function lib_rand_rand(STATE) {
20 STATE[lib_rand_state] = lib_rand_mod_2_26(54514969*STATE[lib_rand_state] + 21095981)
21 return STATE[lib_rand_state]/67108864
22 }
23
24 # internal
25 function lib_rand_mod_2_26(n) {
26 n -= int(n/67108864)*67108864
27 return n
28 }
0 put /local/tests {array rand}
1 put /local/tester {../../libmawk/lmawk}
2
3 print [@
4 # Generated by scconfig from Makefile.in
5
6 all:@]
7
8 foreach /local/n in /local/tests
9 print [@@/local/n@.diff@]
10 end
11
12 print {\n @echo "QC passed."}
13
14 foreach /local/n in /local/tests
15 print [^
16 ^/local/n^.out: ^/local/n^.awk ^/local/tester^
17 @^/local/tester^ -f ^/local/n^.awk > ^/local/n^.out
18
19 ^/local/n^.diff: ^/local/n^.OUT ^/local/n^.out
20 @diff ^/local/n^.OUT ^/local/n^.out
21 ^]
22 end
23
24 print [@
25 clean:
26 rm @]
27
28 foreach /local/n in /local/tests
29 print [@ @/local/n@.diff @/local/n@.out@]
30 end
31
32 print { 2>/dev/null; true\n\n}
0 Array:
1 A[1] = 'one'
2 A[2] = 'two'
3 A[3] = 'three'
4 A[4] = 'four'
5 A[5] = 'five'
6 A[6] = 'six'
7 A[7] = 'seven'
8 A[8] = 'eight'
9 Pack/Unpack A:
10 B[10] = '1one2two3three4four5five6six7seven8eight'
11 B[1] = 'one'
12 B[2] = 'two'
13 B[3] = 'three'
14 B[4] = 'four'
15 B[5] = 'five'
16 B[6] = 'six'
17 B[7] = 'seven'
18 B[8] = 'eight'
19 Pack/Unpack A[10]:
20 C[1] = 'one'
21 C[2] = 'two'
22 C[3] = 'three'
23 C[4] = 'four'
24 C[5] = 'five'
25 C[6] = 'six'
26 C[7] = 'seven'
27 C[8] = 'eight'
0 include "../lib_array.awk"
1
2 BEGIN {
3 v = split("one two three four five six seven eight", A, " ");
4 print "Array:"
5 lib_array_print(" A", A);
6
7 str = lib_array_pack(A);
8 A[10] = str
9
10 str = lib_array_pack(A);
11
12 lib_array_unpack(B, str);
13
14 print "Pack/Unpack A:"
15 lib_array_print(" B", B);
16
17
18 print "Pack/Unpack A[10]:"
19 lib_array_unpack(C, A[10]);
20 lib_array_print(" C", C);
21 }
0 591751040
1 430689775
2 43690
3 43690
0 include "../lib_hex.awk"
1 BEGIN {
2 print lib_hex_str2int("23456780")
3 print lib_hex_str2int("19aBcDeF")
4 print lib_hex_str2int("0xaaaa")
5 print lib_hex_str2int("aaaa")
6 }
0 q1 sum: 4.53303
1 q1 sum: 4.53303
2 q2 sum: 5.8163
0 include "../lib_rand.awk"
1 BEGIN {
2 lib_rand_srand(Q1, 1234567)
3 for (i=1; i<=10; i++)
4 q1 += lib_rand_rand(Q1)
5
6 print "q1 sum: " q1
7
8 q1=0
9 lib_rand_srand(Q1, 1234567)
10 lib_rand_srand(Q2, 7654321)
11 for (i=1; i<=10; i++) {
12 q1 += lib_rand_rand(Q1)
13 q2 += lib_rand_rand(Q2)
14 }
15
16 print "q1 sum: " q1
17 print "q2 sum: " q2
18 }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: load and run a script using the command line syntax of mawk but
5 using a virtual stdin buffer instead of the real stdin.
6 Run: ./app -f test.awk
7 */
8
9 int main(int argc, char **argv)
10 {
11 mawk_state_t *m;
12
13 /* init a context, execute BEGIN */
14 m = libmawk_initialize(argc, argv);
15 if (m == NULL) {
16 fprintf(stderr, "libmawk_initialize failed, exiting\n");
17 return 1;
18 }
19
20 /* feed in some data on the virtual stdin */
21 libmawk_append_input(m, "This is a\nmultiline test input\nfor the artificial input buffer.\n");
22
23 /* run the MAIN part of the script as long as there's data in the buffer of
24 the virtual stdin */
25 libmawk_run_main(m);
26
27 /* run END and free the context */
28 libmawk_uninitialize(m);
29
30 return 0;
31 }
32
0 script: BEGIN
1 script: input: "This is a"
2 script: input: "multiline test input"
3 script: input: "for the artificial input buffer."
4 script: END
0 BEGIN { print "script: BEGIN" }
1 { print "script: input: \"" $0 "\"" }
2 END { print "script: END" }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 (this test is broken yet, waiting for vio to be finished)
5 Purpose: demonstrate how virtual stdin works
6 Run: ./app -f test.awk
7 */
8
9 int main(int argc, char **argv)
10 {
11 mawk_state_t *m;
12
13 /* init a context, execute BEGIN */
14 m = libmawk_initialize(argc, argv);
15 if (m == NULL) {
16 fprintf(stderr, "libmawk_initialize failed, exiting\n");
17 return 1;
18 }
19
20 /* run the MAIN part of the script; assume a record is a line
21 (with standard FS in awk this is true). The MAIN part of
22 the script consists of _all_ rules except for BEGINs and ENDs. */
23
24 /* The input buffer of the script is empty at start. Attempting to run
25 MAIN on an empty buffer will return immediately, without any awk
26 code being executed */
27 printf("app: test point 1\n");
28 libmawk_run_main(m);
29
30 /* Load a full record and invoke MAIN; this will run rules once, for this
31 line: */
32 printf("app: test point 2\n");
33 libmawk_append_input(m, "First line.\n");
34 libmawk_run_main(m);
35
36 /* Load a multiple records and invoke MAIN; this will run the rules
37 for all full (terminated) records:
38 */
39 printf("app: test point 3\n");
40 libmawk_append_input(m, "Second line.\nThird line.\nFourth ");
41 libmawk_run_main(m);
42
43 /* At this point we have a partial record ("Fourth ") left in the
44 buffer. Running MAIN without terminating this record will have
45 the same effect as running MAIN on an empty buffer:
46 */
47 printf("app: test point 4\n");
48 libmawk_run_main(m);
49
50 /* Terminate the incomplete record and run: will invoke rules on the
51 now-complete record */
52 printf("app: test point 5\n");
53 libmawk_append_input(m, "line.\n");
54 libmawk_run_main(m);
55
56
57 /* the number of append calls does not matter: */
58 printf("app: test point 6\n");
59 libmawk_append_input(m, "5th line.\n");
60 libmawk_append_input(m, "6th line.\n7th ");
61 libmawk_append_input(m, "line.\n");
62 libmawk_run_main(m);
63
64 /* if there is a partial record at the end of the input stream, that
65 is read and processed as a full record */
66 printf("app: test point 7\n");
67 libmawk_append_input(m, "partial 8th 'line'\n");
68 libmawk_close_input(m);
69 libmawk_run_main(m);
70
71 /* free the context - this won't run END because END had to run already
72 for eof-on-stdin */
73 printf("app: test point 8\n");
74 libmawk_uninitialize(m);
75
76 return 0;
77 }
78
0 script: BEGIN
1 app: test point 1
2 app: test point 2
3 script: input: "First line."
4 app: test point 3
5 script: input: "Second line."
6 script: input: "Third line."
7 app: test point 4
8 app: test point 5
9 script: input: "Fourth line."
10 app: test point 6
11 script: input: "5th line."
12 script: input: "6th line."
13 script: input: "7th line."
14 app: test point 7
15 script: input: "partial 8th 'line'"
16 script: END
17 app: test point 8
0 BEGIN { print "script: BEGIN" }
1 { print "script: input: \"" $0 "\"" }
2 END { print "script: END" }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: load the same script multiple times, running the instances
5 in parallel with different input. There's no race condition on
6 the output: scripts execution is strictly dictated by the
7 (single thread) app and both scripts are writing the same output
8 stream.
9 Run: ./app -f test.awk
10 */
11
12 int main(int argc, char **argv)
13 {
14 mawk_state_t *m1, *m2;
15 int n;
16
17 /* init a context, execute BEGIN */
18 m1 = libmawk_initialize(argc, argv);
19 m2 = libmawk_initialize(argc, argv);
20 if ((m1 == NULL) || (m2 == NULL)) {
21 fprintf(stderr, "libmawk_initialize failed, exiting\n");
22 return 1;
23 }
24
25 /* feed in some data on the virtual stdin */
26 libmawk_append_input(m1, "[1] This is a\n[1] multiline test input\n[1] for the artificial input buffer.\n");
27 libmawk_append_input(m2, "[2] This is a\n[2] multiline test input\n[2] for the artificial input buffer.\n");
28
29 /* run the MAIN part of the script as long as there's data in the buffer of
30 the virtual stdin; this makes m1 process all available input before m2
31 starts processing its input. */
32 libmawk_run_main(m1);
33 libmawk_run_main(m2);
34
35 /* run in parallel, record by record - inject only one record in the input
36 buffer before running the script */
37 for(n = 0; n < 4; n++) {
38 char tmp[32];
39
40 sprintf(tmp, "[1] record %d\n", n);
41 libmawk_append_input(m1, tmp);
42 libmawk_run_main(m1);
43
44 sprintf(tmp, "[2] record %d\n", n);
45 libmawk_append_input(m2, tmp);
46 libmawk_run_main(m2);
47 }
48
49 /* run END and free the context */
50 libmawk_uninitialize(m1);
51 libmawk_uninitialize(m2);
52
53 return 0;
54 }
55
0 script: BEGIN
1 script: BEGIN
2 script: input: "[1] This is a"
3 script: input: "[1] multiline test input"
4 script: input: "[1] for the artificial input buffer."
5 script: input: "[2] This is a"
6 script: input: "[2] multiline test input"
7 script: input: "[2] for the artificial input buffer."
8 script: input: "[1] record 0"
9 script: input: "[2] record 0"
10 script: input: "[1] record 1"
11 script: input: "[2] record 1"
12 script: input: "[1] record 2"
13 script: input: "[2] record 2"
14 script: input: "[1] record 3"
15 script: input: "[2] record 3"
16 script: END
17 script: END
0 BEGIN { print "script: BEGIN" }
1 { print "script: input: \"" $0 "\"" }
2 END { print "script: END" }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
23
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: demonstrate how to call an awk user function from the app
5 Run: ./app -f test.awk
6 */
7
8 int main(int argc, char **argv)
9 {
10 mawk_state_t *m;
11 mawk_cell_t ret = libmawk_empty_cell;
12
13 /* init a context, execute BEGIN */
14 m = libmawk_initialize(argc, argv);
15 if (m == NULL) {
16 fprintf(stderr, "libmawk_initialize failed, exiting\n");
17 return 1;
18 }
19
20 /* call user function foo with 3 arguments; the "format string" is similar
21 to printf's without "%": d (int), f (float) and s (\0 terminated string)
22 The actual arguments are taken as varargs. This function is designed
23 for static calls.
24 NOTE: expect the function to return; that is, the function may not getline
25 from FIFOs, as that may cause them to return as "interrupted waiting
26 for input" in which case the app should fill the FIFO and resume
27 running the function.
28 */
29 if (libmawk_call_function(m, "foo", &ret, "dfs", (int)42, (double)1.234, (char *)"test string1.") == MAWK_EXER_FUNCRET) {
30 char buff[32];
31 printf("app: return value of foo is '%s'\n", libmawk_print_cell(m, &ret, buff, sizeof(buff)));
32 libmawk_cell_destroy(m, &ret);
33 }
34 else {
35 printf("app: error: function foo didn't return\n");
36 goto quit;
37 }
38
39 /* this is the same function call with a syntax more suitable for dynamic
40 calls. Same limitation on getline applies. */
41 {
42 int i = 42;
43 double d = 1.234;
44 char *s = "test string2.";
45 void *args[] = {&i, &d, s};
46 if (libmawk_call_functionp(m, "foo", &ret, "dfs", args) == MAWK_EXER_FUNCRET) {
47 char buff[32];
48 printf("app: return value of func foo '%s'\n", libmawk_print_cell(m, &ret, buff, sizeof(buff)));
49 libmawk_cell_destroy(m, &ret);
50 }
51 else {
52 printf("app: error: function foo didn't return\n");
53 goto quit;
54 }
55 }
56
57
58 quit:;
59 /* run END and free the context */
60 libmawk_uninitialize(m);
61
62 return 0;
63 }
64
0 script: BEGIN
1 script: foo(42,1.234,test string1.)
2 app: return value of foo is '43.234000'
3 script: foo(42,1.234,test string2.)
4 app: return value of func foo '43.234000'
5 script: END
0 function foo(a, b, c)
1 {
2 print "script: foo(" a "," b "," c ")"
3 return a+b
4 }
5
6 BEGIN { print "script: BEGIN" }
7 { print "script: input: \"" $0 "\"" }
8 END { print "script: END" }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: demonstrate how to get the current value of an existing array index;
5 Run: ./app -f test.awk
6 */
7
8 void print_bar(mawk_state_t *m)
9 {
10 mawk_cell_t c = libmawk_empty_cell;
11 char buff[32];
12
13 /* get the value of bar["wow"] into &c; the last 0 in the call means
14 the index should not be created in the array if it does not exist.
15 The array is not created if it didn't exist but -1 is returned.
16 NOTE: c must be initialized empty because it gets destroyed in
17 the call. */
18 switch(libmawk_get_array_at(m, "bar", "wow", &c, 0)) {
19 case -1:
20 printf("No such array \"bar[]\"\n");
21 break;
22 case 0:
23 printf("No \"wow\" in array \"bar[]\"\n");
24 break;
25 case 1:
26 printf("app: bar = '%s'\n", libmawk_print_cell(m, &c, buff, sizeof(buff)));
27 libmawk_cell_destroy(m, &c);
28 }
29 }
30
31 int main(int argc, char **argv)
32 {
33 mawk_state_t *m;
34
35 /* init a context, execute BEGIN */
36 m = libmawk_initialize(argc, argv);
37 if (m == NULL) {
38 fprintf(stderr, "libmawk_initialize failed, exiting\n");
39 return 1;
40 }
41
42 /* print value of bar right after BEGIN */
43 print_bar(m);
44
45 /* feed in some data on the virtual stdin */
46 libmawk_append_input(m, "This is a\nmultiline test input\nfor the artificial input buffer.\n");
47
48 /* run the MAIN part of the script as long as there's data in the buffer of
49 the virtual stdin */
50 libmawk_run_main(m);
51
52 /* print value of bar after running the script on a few records */
53 print_bar(m);
54
55
56 /* run END and free the context */
57 libmawk_uninitialize(m);
58
59 return 0;
60 }
61
0 script: BEGIN
1 app: bar = '42'
2 script: input: "This is a"
3 script: input: "multiline test input"
4 script: input: "for the artificial input buffer."
5 app: bar = '45'
6 script: END
0 BEGIN {
1 print "script: BEGIN"
2 bar["wow"] = 42
3 }
4
5 {
6 print "script: input: \"" $0 "\""
7 bar["wow"]++
8 }
9
10 END {
11 print "script: END"
12 }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: demonstrate how to get the current value of a variable;
5 this basic example does not cover how to efficiently use
6 the value (the cell of the variable), only converts it to
7 string for printing. Please refer to examples TODO for
8 more details on cell conversions.
9 Run: ./app -f test.awk
10 */
11
12 void print_bar(mawk_state_t *m)
13 {
14 const mawk_cell_t *c;
15 char buff[32];
16
17 c = libmawk_get_var(m, "bar");
18
19 if (c != NULL)
20 printf("app: bar = '%s'\n", libmawk_print_cell(m, c, buff, sizeof(buff)));
21 else
22 printf("No such variable \"bar\"\n");
23 }
24
25 int main(int argc, char **argv)
26 {
27 mawk_state_t *m;
28
29 /* init a context, execute BEGIN */
30 m = libmawk_initialize(argc, argv);
31 if (m == NULL) {
32 fprintf(stderr, "libmawk_initialize failed, exiting\n");
33 return 1;
34 }
35
36 /* print value of bar right after BEGIN */
37 print_bar(m);
38
39 /* feed in some data on the virtual stdin */
40 libmawk_append_input(m, "This is a\nmultiline test input\nfor the artificial input buffer.\n");
41
42 /* run the MAIN part of the script as long as there's data in the buffer of
43 the virtual stdin */
44 libmawk_run_main(m);
45
46 /* print value of bar after running the script on a few records */
47 print_bar(m);
48
49
50 /* run END and free the context */
51 libmawk_uninitialize(m);
52
53 return 0;
54 }
55
0 script: BEGIN
1 app: bar = '42'
2 script: input: "This is a"
3 script: input: "multiline test input"
4 script: input: "for the artificial input buffer."
5 app: bar = '45'
6 script: END
0 BEGIN {
1 print "script: BEGIN"
2 bar = 42
3 }
4
5 {
6 print "script: input: \"" $0 "\""
7 bar++
8 }
9
10 END {
11 print "script: END"
12 }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: ignore command line args and load a script from a hardwired path
5 Run: ./app
6 */
7
8 int main(int argc, char **argv)
9 {
10 mawk_state_t *m;
11
12 /* init a context in stages */
13 m = libmawk_initialize_stage1(); /* alloc context */
14 libmawk_initialize_stdio(m, 0, 1, 1); /* set up default stdio: stdin is a pipe, stdout and stderr are bound to the app's stdout and stderr with no-close-on-exit */
15 mawk_append_input_file(m, "test.awk", 0); /* force load test.awk */
16 m = libmawk_initialize_stage2(m, 0, NULL); /* set up with no arguments */
17 m = libmawk_initialize_stage3(m); /* execute BEGIN */
18
19
20 if (m == NULL) {
21 fprintf(stderr, "libmawk_initialize failed, exiting\n");
22 return 1;
23 }
24
25 /* run END and free the context */
26 libmawk_uninitialize(m);
27
28 return 0;
29 }
30
0 script: BEGIN test.awk
1 script: END test.awk
0 BEGIN { print "script: BEGIN test.awk" }
1 END { print "script: END test.awk" }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: multi-stage uninit: collect results calculated in the END {} block
5 Run: ./app -f test.awk
6 */
7
8 int main(int argc, char **argv)
9 {
10 mawk_state_t *m;
11
12 /* init a context, execute BEGIN */
13 m = libmawk_initialize(argc, argv);
14 if (m == NULL) {
15 fprintf(stderr, "libmawk_initialize failed, exiting\n");
16 return 1;
17 }
18
19 if (m == NULL) {
20 fprintf(stderr, "libmawk_initialize failed, exiting\n");
21 return 1;
22 }
23
24 /* run END */
25 libmawk_uninitialize_stage1(m);
26
27 /* print variable "script_state" */
28 {
29 const mawk_cell_t *c;
30 char buff[32];
31 c = libmawk_get_var(m, "script_state");
32 if (c != NULL)
33 printf("app: script_state = '%s'\n", libmawk_print_cell(m, c, buff, sizeof(buff)));
34 else
35 printf("No such variable \"script_state\"\n");
36 }
37
38 /* free the context */
39 libmawk_uninitialize_stage2(m);
40
41 return 0;
42 }
43
0 script: BEGIN test.awk
1 script: END test.awk
2 app: script_state = 'begin+end'
0 BEGIN { print "script: BEGIN test.awk"; script_state = "begin" }
1 { print "script: input"; script_state = script_state "+input" }
2 END { print "script: END test.awk"; script_state = script_state "+end" }
3
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk | sort
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: demonstrate how to change the value of an existing array
5 Run: ./app -f test.awk | sort
6 */
7
8 int main(int argc, char **argv)
9 {
10 mawk_state_t *m;
11 double dbl;
12
13 /* init a context, execute BEGIN */
14 m = libmawk_initialize(argc, argv);
15 if (m == NULL) {
16 fprintf(stderr, "libmawk_initialize failed, exiting\n");
17 return 1;
18 }
19
20 /* setting an index in an array means existing data is overwritten
21 or new data is allocated/registered. There are calls with different
22 conventions doing the same, to make the app developer's life easier. */
23
24 /* Vararg version, for static/hardwired data: */
25 libmawk_set_array_at(m, "bar", "one", 'd', 42);
26
27 /* Similar version with a void * pointer as value: */
28 dbl=3.141592654;
29 libmawk_set_array_atp(m, "bar", "two", 'f', &dbl);
30
31 /* The above two were creating new indixes in the array; the below call
32 will overwrite an existing one created by the script */
33 libmawk_set_array_at(m, "bar", "wow", 's', "no way!");
34
35 /* run END and free the context */
36 libmawk_uninitialize(m);
37
38 return 0;
39 }
40
0 script: one 42
1 script: two 3.14159
2 script: wow no way!
0 BEGIN {
1 bar["wow"] = 42
2 }
3
4 END {
5 for(idx in bar)
6 print "script:", idx, bar[idx]
7 }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: wire stdout to a pipe and process the output of the script;
5 simple setup
6 Run: ./app -f test.awk
7 */
8
9 void print_pipe_pending(mawk_state_t *m, mawk_vio_t *vf, char *sep)
10 {
11 for(;;) {
12 int len;
13 char buf[1024];
14 len = mawk_vio_fifo_read_app(m, vf, buf, sizeof(buf)-1);
15 if (len <= 0)
16 return;
17 buf[len] = '\0';
18 printf("<%s>\n%s</%s>\n", sep, buf, sep);
19 }
20 }
21
22 int main(int argc, char **argv)
23 {
24 mawk_state_t *m;
25 mawk_vio_t *vf_stdin, *vf_stdout, *vf_log;
26
27 /* init a context in stages */
28 m = libmawk_initialize_stage1(); /* alloc context */
29
30 /* set up pipes: stdin is a fifo, stdout is a fifo, stderr is app's stderr */
31 libmawk_initialize_stdio(m, 0, 0, 1);
32
33 m = libmawk_initialize_stage2(m, argc, argv); /* set up with CLI arguments */
34 m = libmawk_initialize_stage3(m); /* execute BEGIN */
35
36 if (m == NULL) {
37 fprintf(stderr, "libmawk_initialize failed, exiting\n");
38 return 1;
39 }
40
41 /* libmawk_append_input() operates on "/dev/stdin" as registered, if it is
42 a pipe, so it is compatible with manual setup */
43 libmawk_append_input(m, "Hello world!\n");
44 libmawk_run_main(m);
45
46
47 /* print all the stdout the script produced so far */
48 print_pipe_pending(m, m->fnode_stdout->vf, "stdout");
49
50 /* run END and free the context */
51 libmawk_uninitialize(m);
52
53 return 0;
54 }
55
0 <stdout>
1 BEGIN test.awk
2 stdin=Hello world!
3 </stdout>
0 BEGIN {
1 print "BEGIN test.awk"
2 print "this is the initial log entry." > "log"
3 print "foobar" > "real_file"
4 }
5
6 {
7 print "stdin=" $0
8 }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: wire stdout to a pipe and process the output of the script and
5 hijack output file "log". Manual setup.
6 Run: ./app -f test.awk
7 */
8
9 void print_pipe_pending(mawk_state_t *m, mawk_vio_t *vf, char *sep)
10 {
11 for(;;) {
12 int len;
13 char buf[1024];
14 len = mawk_vio_fifo_read_app(m, vf, buf, sizeof(buf)-1);
15 if (len <= 0)
16 return;
17 buf[len] = '\0';
18 printf("<%s>\n%s</%s>\n", sep, buf, sep);
19 }
20 }
21
22 int main(int argc, char **argv)
23 {
24 mawk_state_t *m;
25 mawk_vio_t *vf_stdin, *vf_stdout, *vf_log;
26
27 /* init a context in stages */
28 m = libmawk_initialize_stage1(); /* alloc context */
29
30 /* set up all pipes */
31 mawk_vio_orig_setup_stdio(m, 0, 0, 1); /* whether bind to the app's stdio: 0,0,1=stdin,stdout,stderr; let stderr bind */
32 vf_stdin = mawk_vio_fifo_open(m, NULL, MAWK_VIO_I); /* create a pipe for stdin */
33 vf_stdout = mawk_vio_fifo_open(m, NULL, MAWK_VIO_O_APPEND); /* create a pipe for stdout */
34 vf_log = mawk_vio_fifo_open(m, NULL, MAWK_VIO_O_APPEND); /* create a pipe for logging */
35 mawk_file_register(m, "/dev/stdin", F_IN, vf_stdin); /* register /dev/stdin */
36 mawk_file_register(m, "/dev/stdout", F_APPEND, vf_stdout); /* register /dev/stdout */
37 mawk_file_register(m, "log", F_APPEND, vf_log); /* register a regular open file named "log" */
38 m->vio_init = mawk_vio_orig_init; /* file operation is handled by the orig vio */
39
40 m = libmawk_initialize_stage2(m, argc, argv); /* set up with CLI arguments */
41 m = libmawk_initialize_stage3(m); /* execute BEGIN */
42
43 if (m == NULL) {
44 fprintf(stderr, "libmawk_initialize failed, exiting\n");
45 return 1;
46 }
47
48 /* libmawk_append_input() operates on "/dev/stdin" as registered, if it is
49 a pipe, so it is compatible with manual setup */
50 libmawk_append_input(m, "Hello world!\n");
51 libmawk_run_main(m);
52
53
54 /* print all the stdout the script produced so far */
55 print_pipe_pending(m, vf_stdout, "stdout");
56 print_pipe_pending(m, vf_log, "log");
57
58 /* run END and free the context */
59 libmawk_uninitialize(m);
60
61 return 0;
62 }
63
0 <stdout>
1 BEGIN test.awk
2 stdin=Hello world!
3 </stdout>
4 <log>
5 this is the initial log entry.
6 </log>
0 BEGIN {
1 print "BEGIN test.awk"
2 print "this is the initial log entry." > "log"
3 print "foobar" > "real_file"
4 }
5
6 {
7 print "stdin=" $0
8 }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: run the script in small portions, only a few instruction at a time
5 using runlimit
6 Run: ./app
7 */
8
9 int main(int argc, char **argv)
10 {
11 mawk_state_t *m;
12 int n;
13
14 /* init a context in stages */
15 m = libmawk_initialize_stage1(); /* alloc context */
16 libmawk_initialize_stdio(m, 0, 1, 1); /* set up default stdio: stdin is a pipe, stdout and stderr are bound to the app's stdout and stderr with no-close-on-exit */
17 mawk_append_input_file(m, "test.awk", 0); /* force load test.awk */
18 m = libmawk_initialize_stage2(m, 0, NULL); /* set up with no arguments */
19 m->runlimit = 32; /* run 32 instructions at a time */
20 m = libmawk_initialize_stage3(m); /* start executing BEGIN */
21
22
23 if (m == NULL) {
24 fprintf(stderr, "libmawk_initialize failed, exiting\n");
25 return 1;
26 }
27
28 /* resume a few times */
29 for(n = 0; n < 8; n++) {
30 printf("app: interrupt\n");
31 mawk_resume(m);
32 }
33
34 /* run END and free the context */
35 libmawk_uninitialize(m);
36
37 return 0;
38 }
39
0 script begin: 1
1 script begin: 2
2 app: interrupt
3 script begin: 3
4 app: interrupt
5 script func ENTER
6 script func: 1 0.333333
7 script func: 2 0.666667
8 script func: 3 1
9 app: interrupt
10 script func LEAVE
11 script begin: 4
12 app: interrupt
13 script begin: 5
14 script begin: 6
15 app: interrupt
16 script func ENTER
17 script func: 1 0.333333
18 script func: 2 0.666667
19 script func: 3 1
20 app: interrupt
21 script func: 4 1.33333
22 script func: 5 1.66667
23 script func: 6 2
24 script func LEAVE
25 app: interrupt
26 script begin: 7
27 script begin: 8
28 app: interrupt
29 script begin: 9
30 script func ENTER
31 script func: 1 0.333333
32 script func: 2 0.666667
33 script func: 3 1
0 function fnc()
1 {
2 print "script func ENTER"
3 for(i in A)
4 print "script func:", i, A[i]
5 print "script func LEAVE"
6 }
7
8 BEGIN {
9 while(1) {
10 n++
11 print "script begin: " n
12 A[n] = n/3
13 if ((n % 3) == 0)
14 fnc()
15 }
16 }
17
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -g -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: run the script in small portions and:
5 1. starve stdin: the script will not be able to proceed
6 2. resume record by record to test if getline in main works
7 Run: ./app
8 */
9
10 int main(int argc, char **argv)
11 {
12 mawk_state_t *m;
13 int n;
14
15 /* init a context in stages */
16 m = libmawk_initialize_stage1(); /* alloc context */
17 libmawk_initialize_stdio(m, 0, 1, 1); /* set up default stdio: stdin is a pipe, stdout and stderr are bound to the app's stdout and stderr with no-close-on-exit */
18 mawk_append_input_file(m, "test.awk", 0); /* force load test.awk */
19 m = libmawk_initialize_stage2(m, 0, NULL); /* set up with no arguments */
20 m->runlimit = 32; /* run 32 instructions at a time */
21 m = libmawk_initialize_stage3(m); /* start executing BEGIN */
22
23
24 if (m == NULL) {
25 fprintf(stderr, "libmawk_initialize failed, exiting\n");
26 return 1;
27 }
28
29 printf("app: 1. starving: resume a few times without new input\n");
30 for(n = 0; n < 8; n++) {
31 printf("app: interrupt\n");
32 mawk_resume(m);
33 }
34
35 printf("app: 2. resume a few times with one input record each time\n");
36 for(n = 0; n < 16; n++) {
37 char s[32];
38 printf("app: interrupt\n");
39 sprintf(s, "rec %d\n", n);
40 libmawk_append_input(m, s);
41 mawk_resume(m);
42 }
43
44 /* run END and free the context */
45 libmawk_uninitialize(m);
46
47 return 0;
48 }
49
0 app: 1. starving: resume a few times without new input
1 app: interrupt
2 app: interrupt
3 app: interrupt
4 app: interrupt
5 app: interrupt
6 app: interrupt
7 app: interrupt
8 app: interrupt
9 app: 2. resume a few times with one input record each time
10 app: interrupt
11 script begin: 0 rec 0
12 app: interrupt
13 script begin: 1 rec 1
14 app: interrupt
15 script begin: 2 rec 2
16 app: interrupt
17 script begin: 3 rec 3
18 app: interrupt
19 script main: 5 rec 4
20 app: interrupt
21 script main: 6 rec 5
22 app: interrupt
23 script func: 0 rec 0 rec 6
24 app: interrupt
25 script func: 1 rec 1 rec 7
26 app: interrupt
27 script func: 2 rec 2 rec 8
28 app: interrupt
29 script func: 3 rec 3 rec 9
30 app: interrupt
31 script func: 5 rec 4 rec 10
32 app: interrupt
33 script func: 6 rec 5 rec 11
34 app: interrupt
35 script main: 7 rec 12
36 app: interrupt
37 script main: 8 rec 13
38 app: interrupt
39 script main: 9 rec 14
40 app: interrupt
41 script main2: 9 rec 15
0 function fnc( i,line)
1 {
2 for(i in A) {
3 getline line
4 print "script func:", i, A[i], line
5 }
6 }
7
8 BEGIN {
9 for(n = 0; n < 4; n++) {
10 getline line
11 print "script begin: ", n, line
12 A[n] = line
13 }
14 }
15
16 {
17 n++
18 print "script main: ", n, $0
19 A[n] = $0
20 if (n == 6)
21 fnc()
22 else if (n > 8) {
23 getline line
24 print "script main2: ", n, line
25 }
26 }
27
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: implement a C function that can be called from the script.
5 Run: ./app -f test.awk
6 */
7
8 /* sp is the stack pointer, a_args is the number of arguments on the stack */
9 mawk_cell_t *blobb(mawk_state_t *context, mawk_cell_t *sp, int num_args)
10 {
11 int n;
12 char buff[64];
13
14 /* do something - print BLOBB and all arguments */
15 printf("BLOBB! ");
16 for(n = 0; n < num_args; n++)
17 printf("arg%d='%s' ", n, libmawk_print_cell(context, libmawk_cfunc_arg(sp, num_args, n), buff, sizeof(buff)));
18 printf("\n");
19
20 /* set a return value (find out where the return value is on the stack,
21 using libmawk_cfunc_ret()) */
22 libmawk_set_cell(context, libmawk_cfunc_ret(sp, num_args), 'f', (double)1234);
23
24 /* return the new stack pointer - should be the one that was before
25 arguments had been pushed on the stack */
26 return sp - num_args;
27 }
28
29
30 int main(int argc, char **argv)
31 {
32 mawk_state_t *m;
33
34 /* init a context, execute BEGIN */
35 m = libmawk_initialize(argc, argv);
36 if (m == NULL) {
37 fprintf(stderr, "libmawk_initialize failed, exiting\n");
38 return 1;
39 }
40
41 /* The function is registered after BEGIN is run by libmawk_initialize;
42 this means the script can not call the function from BEGIN. If calling
43 from BEGIN is required, the 3-stage initialization shall be implemented,
44 the function registered between stage1 and stage2. */
45
46 /* register a C function (resolved runtime) */
47 if (libmawk_register_function(m, "blobb", blobb) != 0) {
48 fprintf(stderr, "app: ERROR: Unable to register function blobb\n");
49 return 1;
50 }
51
52
53 /* run END and free the context */
54 libmawk_uninitialize(m);
55
56 return 0;
57 }
58
0 script: BEGIN
1 BLOBB! arg0='42.434445' arg1='oops'
2 script: END: 1234
0 BEGIN { print "script: BEGIN" }
1 END { print "script: END: " blobb(42.434445, "oops") }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: implement a C function that could be called from the script then
5 call it from C using the awk function call entry, as if it was an
6 awk function - this should work as there is no difference between
7 functions implemented in C and awk once they are properly registered
8 Run: ./app -f test.awk
9 */
10
11 /* sp is the stack pointer, a_args is the number of arguments on the stack */
12 mawk_cell_t *blobb(mawk_state_t *context, mawk_cell_t *sp, int num_args)
13 {
14 int n;
15 char buff[64];
16
17 /* do something - print BLOBB and all arguments */
18 printf("BLOBB! ");
19 for(n = 0; n < num_args; n++)
20 printf("arg%d='%s' ", n, libmawk_print_cell(context, libmawk_cfunc_arg(sp, num_args, n), buff, sizeof(buff)));
21 printf("\n");
22
23 /* set a return value (find out where the return value is on the stack,
24 using libmawk_cfunc_ret()) */
25 libmawk_set_cell(context, libmawk_cfunc_ret(sp, num_args), 'f', (double)1234);
26
27 /* return the new stack pointer - should be the one that was before
28 arguments had been pushed on the stack */
29 return sp - num_args;
30 }
31
32
33 int main(int argc, char **argv)
34 {
35 mawk_state_t *m;
36 mawk_cell_t ret = libmawk_empty_cell;
37
38 /* init a context, execute BEGIN */
39 m = libmawk_initialize(argc, argv);
40 if (m == NULL) {
41 fprintf(stderr, "libmawk_initialize failed, exiting\n");
42 return 1;
43 }
44
45 /* The function is registered after BEGIN is run by libmawk_initialize;
46 this means the script can not call the function from BEGIN. If calling
47 from BEGIN is required, the 3-stage initialization shall be implemented,
48 the function registered between stage1 and stage2. */
49
50 /* register a C function (resolved runtime) */
51 if (libmawk_register_function(m, "blobb", blobb) != 0) {
52 fprintf(stderr, "app: ERROR: Unable to register function blobb\n");
53 return 1;
54 }
55
56 if (libmawk_call_function(m, "blobb", &ret, "fs", 42.42, "hello") == MAWK_EXER_FUNCRET) {
57 char buff[32];
58 printf("app: return value of func blobb '%s'\n", libmawk_print_cell(m, &ret, buff, sizeof(buff)));
59 libmawk_cell_destroy(m, &ret);
60 }
61 else
62 printf("app: error: function blobb didn't return\n");
63
64
65 /* run END and free the context */
66 libmawk_uninitialize(m);
67
68 return 0;
69 }
70
0 script: BEGIN
1 BLOBB! arg0='42.420000' arg1='hello'
2 app: return value of func blobb '1234'
3 BLOBB! arg0='42.434445' arg1='oops'
4 script: END: 1234
0 BEGIN { print "script: BEGIN" }
1 END { print "script: END: " blobb(42.434445, "oops") }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o carr.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2 #include "carr.h"
3
4 /*
5 Purpose: create a virtual array that directly manipulates a C char[] without
6 any backing awk array. The actual array implementation is in carr.c
7 Run: ./app -f test.awk
8 */
9
10 int main(int argc, char **argv)
11 {
12 mawk_state_t *m;
13 int n;
14
15 m = libmawk_initialize_stage1(); /* set up m */
16
17 /* set up all pipes */
18 libmawk_initialize_stdio(m, 0, 1, 1);
19
20 /* set up a new builtin array with side effects, before parsing scripts
21 so that it works from BEGIN */
22 custom_array_init(m);
23
24 m = libmawk_initialize_stage2(m, argc, argv); /* parse args loads the script(s) */
25 m = libmawk_initialize_stage3(m); /* execute BEGIN {} */
26
27 /* Print the current state of the array */
28 printf("app: CARR[]=\n");
29 for(n = 0; n < CARR_SIZE; n++)
30 printf("app: [%d]=%d '%c'\n", n, carr[n], carr[n]);
31
32
33 /* run END and free the context */
34 libmawk_uninitialize(m);
35
36 return 0;
37 }
38
0 #include "carr.h"
1
2 /* this example code demonstrates how to implement a virtual array that
3 manipulates a C array. The code aims for simplicity so there's no
4 locking of the C array, which is obviously common for any mawk instance:
5 the code assumes a single thread.
6
7 Index is integer between 0 and CARR_SIZE-1. Delete only sets value to 0.
8 The iterator always goes between 0 and CARR_SIZE-1.
9
10 */
11
12 char carr[CARR_SIZE];
13
14 /* lookup: copy a cell of a member if res != NULL; if create_flag is non-zero,
15 the index should be created. If result is non-NULL, it must be destroyed.
16 Result can be the same as cidx!
17 return:
18 -1 on error
19 0 if index does not exist
20 1 if it does exist
21 Because we have a static array, we won't ever return 0; also ignore the
22 create flag. Return -1 for boundary error.
23 */
24 int carr_find(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *cidx, mawk_cell_t *res, int create_flag)
25 {
26 int idx;
27 idx = libmawk_cell2int(MAWK, cidx);
28 if ((idx < 0) || (idx >= CARR_SIZE))
29 return -1;
30
31 if (res != NULL) {
32 mawk_cell_destroy(MAWK, res);
33 res->type = C_NUM;
34 res->d.dval = carr[idx];
35 }
36 return 1;
37 }
38
39
40 /* set the value of an element of the array. The val cell may have any type! */
41 void carr_set(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *cidx, mawk_cell_t *val)
42 {
43 int idx;
44 char cval;
45
46 idx = libmawk_cell2int(MAWK, cidx);
47 if ((idx < 0) || (idx >= CARR_SIZE))
48 return;
49 switch(val->type) {
50 case C_NUM:
51 case C_STRNUM:
52 case C_MBSTRN:
53 carr[idx] = libmawk_cell2int(MAWK, val);
54 break;
55 case C_STRING:
56 {
57 char buff[2];
58 libmawk_print_cell(MAWK, val, buff, 2);
59 carr[idx] = buff[0];
60 }
61 break;
62 default:
63 carr[idx] = 0;
64 }
65 }
66
67
68 /* delete a cell (since our array is static, set the value to 0) */
69 static void carr_delete(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *idx)
70 {
71 mawk_cell_t zero;
72 zero.type = C_NUM;
73 zero.d.dval = 0;
74 carr_set(MAWK, A, idx, &zero);
75 }
76
77 /* set up an iterator; the iterator state is just an integer index */
78 typedef struct {
79 int idx;
80 mawk_cell_t cidx;
81 } carr_it_t;
82
83 void *carr_it_start(mawk_state_t *MAWK, mawk_array_t A)
84 {
85 carr_it_t *i;
86 i = malloc(sizeof(carr_it_t));
87 i->idx = -1;
88 i->cidx.type = C_NUM;
89 return i;
90 }
91
92 /* return next element using an iterator (thread safe) */
93 const mawk_cell_t *carr_it_next(mawk_state_t *MAWK, mawk_array_t A, void *iterator)
94 {
95 carr_it_t *i = iterator;
96 i->idx++;
97 if (i->idx >= CARR_SIZE)
98 return NULL;
99 i->cidx.d.dval = i->idx;
100 return &i->cidx;
101 }
102
103 /* finish iteration */
104 void carr_it_stop(mawk_state_t *MAWK, mawk_array_t A, void *iterator)
105 {
106 /* no need to destroy iterator->cidx as it was a number all the time */
107 free(iterator);
108 }
109
110 /* NOTE: the above code tries to be readable, thus there's a separate
111 integer index an a cell for sotring the return-cell are in the iterator.
112 The code could be shorter taking less ram if the iterator was a cell
113 whose (int)d.dval stored the index. */
114
115 /* the implementation struct that describes how the array is implemented */
116 array_imp_t carr_imp = {
117 /* low level access: find an index, set and delete members */
118 carr_find,
119 carr_set,
120 carr_delete,
121
122 /* use the generic implementation for high level calls, because... */
123 mawk_array_clear_generic,
124 mawk_array_loop_vector_generic,
125 mawk_array_load_generic,
126
127 /* ... the low level iterator is implemented: */
128 carr_it_start,
129 carr_it_next,
130 carr_it_stop
131 };
132
133 /* set up the array as a built-in */
134 void custom_array_init(mawk_state_t *m)
135 {
136 /* register the new array */
137 libmawk_register_array(m, "CARR", &carr_imp);
138
139 /* globals should be zero'd, but to make it absolutely clear: */
140 memset(carr, 0, sizeof(carr));
141 }
142
143
0 #include <libmawk.h>
1
2 #define CARR_SIZE 32
3 extern char carr[CARR_SIZE];
4 void custom_array_init(mawk_state_t *m);
0 BEGIN {
1 # fill in the array with "HELLO WORLD" from index 1; split() tries to fill
2 # the array with each word, but the virtual array set code will consider only
3 # the first character of each word
4 split("Haha Error Light Lungs Old Water Opponent Riot Long Diode !", CARR, " ")
5
6 # use numbers to fill in some more, leaving a gap between the end of the
7 # last index used by split() and the first used by this call
8 for(n = 14; n < 32; n++)
9 CARR[n] = 65+n-14
10
11 # delete [4], which is the second "L"; deletion means setting to 0
12 # with this custom implementation since there is no way to really
13 # remove items from a static array
14 delete CARR[4]
15 }
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o vio_hash.o
8 CFLAGS = -I$(ROOT) -g
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: register "/dev/foo" to a custion vio that does calculates some
5 sort of hash from all data written to it.
6 The hash files are set up in a static manner: once the script
7 closes them or the files get eof from the app, they can not
8 be reopened to be the same virtual files (instead a reopen
9 would call the normal file open procedure)
10 Run: ./app -f test.awk
11 */
12
13 int main(int argc, char **argv)
14 {
15 mawk_state_t *m;
16 mawk_vio_t *vf;
17
18 /* init a context in stages */
19 m = libmawk_initialize_stage1(); /* alloc context */
20
21 /* set up all pipes */
22 libmawk_initialize_stdio(m, 0, 1, 1);
23
24 vf = mawk_vio_hash_open(m, NULL, MAWK_VIO_O_APPEND); /* create a pipe for stdout */
25 mawk_file_register(m, "/dev/hash", F_APPEND, vf); /* register for write */
26 mawk_file_register(m, "/dev/hash", F_IN, vf); /* register for read */
27
28 printf("app: hash before begin: %d\n", mawk_vio_hash_val(m, vf));
29
30 m = libmawk_initialize_stage2(m, argc, argv); /* set up with CLI arguments */
31 m = libmawk_initialize_stage3(m); /* execute BEGIN */
32
33 if (m == NULL) {
34 fprintf(stderr, "libmawk_initialize failed, exiting\n");
35 return 1;
36 }
37
38 printf("app: hash after begin: %d\n", mawk_vio_hash_val(m, vf));
39
40 /* run END */
41 libmawk_uninitialize_stage1(m);
42
43 printf("app: hash after end: %d\n", mawk_vio_hash_val(m, vf));
44
45 /* need to release the app end of the deal to get everything free'd */
46 mawk_vio_hash_eof_from_app(m, vf);
47
48 /* free things */
49 libmawk_uninitialize_stage2(m);
50
51 return 0;
52 }
53
0 app: hash before begin: 0
1 script: BEGIN test.awk
2 app: hash after begin: 47330
3 script: END: 2070754
4 app: hash after end: 2070754
0 BEGIN {
1 print "script: BEGIN test.awk"
2 print "Hello world!" > "/dev/hash"
3 }
4
5 END {
6 print "end." > "/dev/hash"
7 getline val < "/dev/hash"
8 print "script: END: " val
9 }
0 /********************************************
1 libmawk (C) 2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9 #include <stdio.h>
10 #include <libmawk.h>
11 #include "vio_hash.h"
12 #include "memory.h"
13
14 typedef struct mawk_vio_hash_s {
15 /* this field is mandatory and must be the first*/
16 mawk_vio_t vio_common_head;
17
18 /* vio implementation-specific fields */
19 mawk_zfifo_t fifo;
20 int eof_from_awk; /* 1 if there won't be more from awk or awk won't accept more data (close()) */
21 int eof_from_app; /* 1 if there won't be more from the app or the app won't accept more data */
22 unsigned long int seed, value;
23 } mawk_vio_hash_t;
24
25 /* create a new hash vio */
26 mawk_vio_t *mawk_vio_hash_open(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode)
27 {
28 mawk_vio_hash_t *v;
29
30 if ((mode != MAWK_VIO_O_APPEND) && (mode != MAWK_VIO_O_TRUNC))
31 return NULL;
32
33 v = mawk_zmalloc(MAWK, sizeof(mawk_vio_hash_t));
34 v->vio_common_head.imp = &mawk_vio_hash_imp;
35 v->vio_common_head.refco = 0;
36 v->eof_from_awk = 0;
37 v->eof_from_app = 0;
38 v->seed = 0;
39 v->value = 0;
40 return (mawk_vio_t *)v;
41 }
42
43 /* add a chatacter to the hash */
44 static void hash_putc(mawk_vio_hash_t *v, int val)
45 {
46 val <<= v->seed % 32;
47 v->value ^= val;
48 v->seed++;
49 }
50
51 /* putchar from awk */
52 int mawk_vio_hash_putc(mawk_state_t *MAWK, mawk_vio_t *vf, char c)
53 {
54 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
55
56 if (v->eof_from_app)
57 return -1;
58
59 hash_putc(v, c);
60 return 1;
61 }
62
63 /* write string from awk */
64 int mawk_vio_hash_write_str(mawk_state_t *MAWK, mawk_vio_t *vf, const char *str)
65 {
66 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
67 int len;
68
69 if (v->eof_from_app)
70 return -1;
71
72 for(len = 0; *str != '\0'; str++, len++)
73 hash_putc(v, *str);
74 return len;
75 }
76
77 /* write bin from awk */
78 int mawk_vio_hash_write(mawk_state_t *MAWK, mawk_vio_t *vf, const char *data, int len)
79 {
80 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
81 int n;
82
83 if (v->eof_from_app)
84 return -1;
85
86 for(n = 0; n < len; n++)
87 hash_putc(v, data[n]);
88 return len;
89 }
90
91 /* do not implement printf as there's no clever way doing it; let libmawk
92 do the sprintf() thing */
93 int mawk_vio_hash_printf(mawk_state_t *MAWK, mawk_vio_t *vf, const char *fmt, ...)
94 {
95 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
96 abort();
97 }
98
99 /* in case the file is read in awk, it should return the current hash value
100 and an eof (one-shot file). Sending eof is done by putting the file in
101 eof state in the first call and returning eof in the second.
102
103 NOTE: this simple implementation won't allow the script to open the same
104 file again; mawk state's vio_init.open should be hooked for that
105 and a manual vf reopen shall be done.
106 */
107 int mawk_vio_hash_read(mawk_state_t *MAWK, mawk_vio_t *vf, char *dst, long int size)
108 {
109 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
110 char buff[64];
111 int l;
112
113 if (v->eof_from_app)
114 return 0;
115
116 l = sprintf(buff, "%d\n", v->value);
117 if (l <= size) {
118 memcpy(dst, buff, l);
119 v->eof_from_app = 1;
120 return l;
121 }
122 return -1;
123 }
124
125 static void close_on_eof(mawk_state_t *MAWK, mawk_vio_hash_t *v)
126 {
127 /* free the struct only if both sides closed it */
128 if ((v->eof_from_app) && (v->eof_from_awk))
129 mawk_zfree(MAWK, v, sizeof(mawk_vio_hash_t));
130 }
131
132 /* the script closes the file */
133 int mawk_vio_hash_close(mawk_state_t *MAWK, mawk_vio_t *vf)
134 {
135 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
136
137 v->eof_from_awk = 1;
138 close_on_eof(MAWK, v);
139 return 0;
140 }
141
142 int mawk_vio_hash_flush(mawk_state_t *MAWK, mawk_vio_t *vf)
143 {
144 /* nothing to do on flush */
145 }
146
147 int mawk_vio_hash_error(mawk_state_t *MAWK, mawk_vio_t *vf)
148 {
149 return (vf == NULL);
150 }
151
152 void mawk_vio_hash_mark_no_close(mawk_state_t *MAWK, mawk_vio_t *vf)
153 {
154 /* fifos are always closed when both awk and the app closes them and
155 there are no inherited pipes anyway */
156 }
157
158 const mawk_vio_imp_t mawk_vio_hash_imp = {
159 mawk_vio_hash_putc,
160 mawk_vio_hash_write_str,
161 mawk_vio_hash_write,
162 mawk_vio_hash_printf,
163 mawk_vio_hash_read,
164 mawk_vio_hash_close,
165 mawk_vio_hash_flush,
166 mawk_vio_hash_error,
167 mawk_vio_hash_mark_no_close
168 };
169
170
171 /* helper calls for the app */
172 unsigned long int mawk_vio_hash_val(mawk_state_t *MAWK, mawk_vio_t *vf)
173 {
174 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
175 return v->value;
176 }
177
178 /* the app wanted to close the file */
179 int mawk_vio_hash_eof_from_app(mawk_state_t *MAWK, mawk_vio_t *vf)
180 {
181 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
182
183 v->eof_from_app = 1;
184 close_on_eof(MAWK, v);
185 return 0;
186 }
0 extern const mawk_vio_imp_t mawk_vio_hash_imp;
1
2 mawk_vio_t *mawk_vio_hash_open(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode);
3
4 /* retrieve current value of the hash */
5 unsigned long int mawk_vio_hash_val(mawk_state_t *MAWK, mawk_vio_t *vf);
6
7 /* the application wants to signal eof to the script */
8 int mawk_vio_hash_eof_from_app(mawk_state_t *MAWK, mawk_vio_t *vf);
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 /*
4 Purpose: manipulate or deny opening specific files and commands
5 Run: ./app -f test.awk
6 */
7
8 /* called any time the script wants to open a new file or command
9 (print redirection or getline);
10 return:
11 - orig_name of OK as is
12 - buff after filling in a new file name or command there
13 - another string const (won't be freed)
14 - NULL to deny opening the file/running the command */
15
16 const char *fn_rewrite(const char *orig_name, char *buff, int buff_size, int type)
17 {
18 switch (type) {
19 case F_IN:
20 /* wants to read - allow any read-only op */
21 return orig_name;
22
23 case F_TRUNC:
24 case F_APPEND:
25 /* wants to write a file - redirect to out.txt */
26 return "out.txt";
27
28 case PIPE_OUT:
29 case PIPE_IN:
30 {
31 static const char *wrapper = "echo '%s'"; /* unsafe: %s may contain '. */
32
33 /* run command - rewrite to use echo instead */
34 if (sizeof(orig_name) > buff_size - strlen(wrapper) - 2)
35 return NULL; /* too long, we can't easily wrap, deny */
36
37 sprintf(buff, wrapper, orig_name);
38 return buff;
39 }
40 default:
41 /* ...if the API changes in the future: deny! */
42 return NULL;
43 }
44 }
45
46 int main(int argc, char **argv)
47 {
48 mawk_state_t *m;
49
50 /* init a context in stages */
51 m = libmawk_initialize_stage1(); /* alloc context */
52 libmawk_initialize_stdio(m, 1, 1, 1);
53 m->file_name_rewrite = fn_rewrite; /* hook file name for rewriting */
54 m = libmawk_initialize_stage2(m, argc, argv); /* set up with no arguments */
55 m = libmawk_initialize_stage3(m); /* execute BEGIN */
56
57
58 if (m == NULL) {
59 fprintf(stderr, "libmawk_initialize failed, exiting\n");
60 return 1;
61 }
62
63 /* run END and free the context */
64 libmawk_uninitialize(m);
65
66 return 0;
67 }
68
0 script: BEGIN test.awk
1 script: read=BEGIN {
2 script: date=date +%s
0 BEGIN {
1 print "script: BEGIN test.awk"
2
3 # this will work with as expected
4 getline line < "test.awk"
5 print "script: read=" line
6
7 # this will be redirected to out.txt instead of "some_file"
8 print "hello" > "some_file"
9
10 # this won't read the date because it's wrapper in an echo
11 "date +%s" | getline line
12 print "script: date=" line
13 }
14
0 ROOT=../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 include ../Makefile.common
6
7 OBJS = app.o vio_hash.o
8 CFLAGS = -I$(ROOT)
9
10 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
11 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
12
13 app.o: app.c
14
15 run: app
16 ./app -f test.awk
17
18 clean:
19 rm -f $(OBJS) app
20
21 distclean: clean
22
0 #include <stdio.h>
1 #include <libmawk.h>
2 #include "vio_hash.h"
3
4
5 /*
6 Purpose: register "/dev/foo" to a custion vio that does calculates some
7 sort of hash from all data written to it.
8 The hash files are set up in a dynamic manner: a hash is created
9 when the script opens it. It is possible to have at most 16 hashes.
10 Run: ./app -f test.awk
11 */
12
13 /* any hash ever existed will get into this array and won't be freed until
14 the end of the app. This means if the script writes /dev/hash/3, the value
15 is preserved even after close("/dev/hash/3"), to allow multiple reads.
16 The hash value/seed is reset when the file is open for writing. */
17 mawk_vio_t *vf_hash[16];
18
19 mawk_vio_t *dispatch_open(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode)
20 {
21 /* hijack /dev/hash/* for the hash vio */
22 if (strncmp(name, "/dev/hash/", 10) == 0) {
23 int idx;
24 char *end;
25 idx = strtol(name+10, &end, 10);
26 if (*end != '\0') {
27 fprintf(stderr, "Warning: invalid hash %s: hash id not an integer\n", name);
28 return NULL;
29 }
30 if ((idx < 0) || (idx >= 16)) {
31 fprintf(stderr, "Warning: invalid hash %s: hash id out of range\n", name);
32 return NULL;
33 }
34
35 /* allocate non-existing hashes or reopen existing ones */
36 if (vf_hash[idx] == NULL)
37 vf_hash[idx] = mawk_vio_hash_open(MAWK, name, mode);
38 else
39 mawk_vio_hash_reopen(MAWK, vf_hash[idx], mode);
40
41 return vf_hash[idx];
42 }
43
44 /* call the original open function for any other name */
45 return mawk_vio_orig_init.vopen(MAWK, name, mode);
46 }
47
48
49 void print_all_hashes(mawk_state_t *m, char *banner)
50 {
51 int n;
52 printf("app: %s\n", banner);
53 for(n = 0; n < 16; n++) {
54 if (vf_hash[n] != NULL)
55 printf(" /dev/hash/%d=%d\n", n, mawk_vio_hash_val(m, vf_hash[n]));
56 }
57 }
58
59 int main(int argc, char **argv)
60 {
61 mawk_state_t *m;
62
63
64 /* init a context in stages */
65 m = libmawk_initialize_stage1(); /* alloc context */
66
67 m->vio_init.vopen = dispatch_open;
68
69 /* set up all pipes */
70 mawk_vio_orig_setup_stdio(m, 0, 1, 1); /* whether bind to the app's stdio: 0,1,1=stdin,stdout,stderr */
71
72 m = libmawk_initialize_stage2(m, argc, argv); /* set up with CLI arguments */
73 m = libmawk_initialize_stage3(m); /* execute BEGIN */
74
75 if (m == NULL) {
76 fprintf(stderr, "libmawk_initialize failed, exiting\n");
77 return 1;
78 }
79
80 print_all_hashes(m, "hash after begin");
81
82 /* run END */
83 libmawk_uninitialize_stage1(m);
84
85 print_all_hashes(m, "hash after end");
86
87 /* free things */
88 libmawk_uninitialize_stage2(m);
89
90 /* no need to free vf_hash[]:
91 - uninitialize_stage2 will close all existing files
92 - final destruction of m will free any allocation left
93 */
94 return 0;
95 }
96
0 script: BEGIN test.awk
1 app: hash after begin
2 /dev/hash/4=47330
3 /dev/hash/6=293858
4 script: END: 2070754 6650850
5 script: END: second time 6:6650850
6 script: END: third time 6:-1889174558
7 app: hash after end
8 /dev/hash/4=2070754
9 /dev/hash/6=-1889174558
0 BEGIN {
1 print "script: BEGIN test.awk"
2 print "Hello world!" > "/dev/hash/4"
3 print "Hello universe!" > "/dev/hash/6"
4 }
5
6 END {
7 print "end." > "/dev/hash/4"
8 print "END!" > "/dev/hash/6"
9 getline val4 < "/dev/hash/4"
10 getline val6 < "/dev/hash/6"
11 print "script: END: " val4, val6
12
13 # works even after reopeninig:
14 close("/dev/hash/6")
15 getline val6 < "/dev/hash/6"
16 print "script: END: second time 6:" val6
17
18 # reopen
19 close("/dev/hash/6")
20 print "new thing" > "/dev/hash/6"
21 getline val6 < "/dev/hash/6"
22 print "script: END: third time 6:" val6
23 }
0 /********************************************
1 libmawk (C) 2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9 #include <stdio.h>
10 #include <libmawk.h>
11 #include "vio_hash.h"
12 #include "memory.h"
13
14 typedef struct mawk_vio_hash_s {
15 const mawk_vio_imp_t *imp;
16 mawk_zfifo_t fifo;
17 int eof_from_awk; /* 1 if there won't be more from awk or awk won't accept more data (close()) */
18 int eof_from_app; /* 1 if there won't be more from the app or the app won't accept more data */
19 unsigned long int seed, value;
20 } mawk_vio_hash_t;
21
22 /* create a new hash vio */
23 mawk_vio_t *mawk_vio_hash_open(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode)
24 {
25 mawk_vio_hash_t *v;
26
27 if ((mode != MAWK_VIO_O_APPEND) && (mode != MAWK_VIO_O_TRUNC))
28 return NULL;
29
30 v = mawk_zmalloc(MAWK, sizeof(mawk_vio_hash_t));
31 v->imp = &mawk_vio_hash_imp;
32 v->eof_from_awk = 0;
33 v->eof_from_app = 0;
34 v->seed = 0;
35 v->value = 0;
36 return (mawk_vio_t *)v;
37 }
38
39 /* add a chatacter to the hash */
40 static void hash_putc(mawk_vio_hash_t *v, int val)
41 {
42 val <<= v->seed % 32;
43 v->value ^= val;
44 v->seed++;
45 }
46
47 /* putchar from awk */
48 int mawk_vio_hash_putc(mawk_state_t *MAWK, mawk_vio_t *vf, char c)
49 {
50 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
51
52 if (v->eof_from_app)
53 return -1;
54
55 hash_putc(v, c);
56 return 1;
57 }
58
59 /* write string from awk */
60 int mawk_vio_hash_write_str(mawk_state_t *MAWK, mawk_vio_t *vf, const char *str)
61 {
62 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
63 int len;
64
65 if (v->eof_from_app)
66 return -1;
67
68 for(len = 0; *str != '\0'; str++, len++)
69 hash_putc(v, *str);
70 return len;
71 }
72
73 /* write bin from awk */
74 int mawk_vio_hash_write(mawk_state_t *MAWK, mawk_vio_t *vf, const char *data, int len)
75 {
76 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
77 int n;
78
79 if (v->eof_from_app)
80 return -1;
81
82 for(n = 0; n < len; n++)
83 hash_putc(v, data[n]);
84 return len;
85 }
86
87 /* do not implement printf as there's no clever way doing it; let libmawk
88 do the sprintf() thing */
89 int mawk_vio_hash_printf(mawk_state_t *MAWK, mawk_vio_t *vf, const char *fmt, ...)
90 {
91 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
92 abort();
93 }
94
95 /* in case the file is read in awk, it should return the current hash value
96 and an eof (one-shot file). Sending eof is done by putting the file in
97 eof state in the first call and returning eof in the second.
98
99 NOTE: this simple implementation won't allow the script to open the same
100 file again; mawk state's vio_init.open should be hooked for that
101 and a manual vf reopen shall be done.
102 */
103 int mawk_vio_hash_read(mawk_state_t *MAWK, mawk_vio_t *vf, char *dst, long int size)
104 {
105 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
106 char buff[64];
107 int l;
108
109 if (v->eof_from_app)
110 return 0;
111
112 l = sprintf(buff, "%d\n", v->value);
113 if (l <= size) {
114 memcpy(dst, buff, l);
115 v->eof_from_app = 1;
116 return l;
117 }
118 return -1;
119 }
120
121 static void close_on_eof(mawk_state_t *MAWK, mawk_vio_hash_t *v)
122 {
123 /* never free the struct - once open, it may be reopen and the host app
124 keeps a copy. Reset instead. */
125 }
126
127 /* the script closes the file */
128 int mawk_vio_hash_close(mawk_state_t *MAWK, mawk_vio_t *vf)
129 {
130 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
131
132 v->eof_from_awk = 1;
133 close_on_eof(MAWK, v);
134 return 0;
135 }
136
137 int mawk_vio_hash_flush(mawk_state_t *MAWK, mawk_vio_t *vf)
138 {
139 /* nothing to do on flush */
140 }
141
142 int mawk_vio_hash_error(mawk_state_t *MAWK, mawk_vio_t *vf)
143 {
144 return (vf == NULL);
145 }
146
147 void mawk_vio_hash_mark_no_close(mawk_state_t *MAWK, mawk_vio_t *vf)
148 {
149 /* fifos are always closed when both awk and the app closes them and
150 there are no inherited pipes anyway */
151 }
152
153 const mawk_vio_imp_t mawk_vio_hash_imp = {
154 mawk_vio_hash_putc,
155 mawk_vio_hash_write_str,
156 mawk_vio_hash_write,
157 mawk_vio_hash_printf,
158 mawk_vio_hash_read,
159 mawk_vio_hash_close,
160 mawk_vio_hash_flush,
161 mawk_vio_hash_error,
162 mawk_vio_hash_mark_no_close
163 };
164
165
166 /* helper calls for the app */
167 unsigned long int mawk_vio_hash_val(mawk_state_t *MAWK, mawk_vio_t *vf)
168 {
169 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
170 return v->value;
171 }
172
173 /* the app wanted to close the file */
174 int mawk_vio_hash_eof_from_app(mawk_state_t *MAWK, mawk_vio_t *vf)
175 {
176 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
177
178 v->eof_from_app = 1;
179 close_on_eof(MAWK, v);
180 return 0;
181 }
182
183 void mawk_vio_hash_reopen(mawk_state_t *MAWK, mawk_vio_t *vf, mawk_vio_open_mode_t mode)
184 {
185 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
186 v->eof_from_awk = 0;
187 v->eof_from_app = 0;
188
189 /* reopen for write means a new hash, make it clean! */
190 if ((mode == MAWK_VIO_O_APPEND) && (mode == MAWK_VIO_O_TRUNC)) {
191 v->value = 0;
192 v->seed = 0;
193 }
194 }
195
196 void mawk_vio_hash_free(mawk_state_t *MAWK, mawk_vio_t *vf)
197 {
198 mawk_vio_hash_t *v = (mawk_vio_hash_t *)vf;
199 mawk_zfree(MAWK, v, sizeof(mawk_vio_hash_t));
200 }
0 extern const mawk_vio_imp_t mawk_vio_hash_imp;
1
2
3 mawk_vio_t *mawk_vio_hash_open(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode);
4
5 /* reopen an existing vf: reset eof states */
6 void mawk_vio_hash_reopen(mawk_state_t *MAWK, mawk_vio_t *vf, mawk_vio_open_mode_t mode);
7
8 /* free a hash struct */
9 void mawk_vio_hash_free(mawk_state_t *MAWK, mawk_vio_t *vf);
10
11 /* retrieve current value of the hash */
12 unsigned long int mawk_vio_hash_val(mawk_state_t *MAWK, mawk_vio_t *vf);
13
14 /* the application wants to signal eof to the script */
15 int mawk_vio_hash_eof_from_app(mawk_state_t *MAWK, mawk_vio_t *vf);
16
0 APPS= \
1 10_run \
2 12_input \
3 12_multi \
4 15_call \
5 15_get_array \
6 15_get_scalar \
7 20_init_wired \
8 20_uninit_staged \
9 25_set_array \
10 30_out_pipes \
11 31_out_pipes_manual \
12 50_runlimit \
13 51_blocking_fifo \
14 70_c_func \
15 71_c_func_call \
16 90_custom_array \
17 90_custom_vio \
18 90_fn_validation \
19 91_custom_vio_re
20
21 all:
22 for n in $(APPS); do cd $$n && make all && cd ..; done
23
24 clean:
25 for n in $(APPS); do cd $$n && make clean && cd ..; done
26
27 test:
28 for n in $(APPS); do cd $$n && make -s test; cd ..; done
0 $(ROOT)/libmawk/libmawk.a: FORCE
1 cd $(ROOT)/libmawk && make libmawk.a
2
3 test:
4 @make -s run > out.curr
5 @diff -u out.ref out.curr && rm out.curr
6 @awk -v "name=`basename $(PWD)`" 'BEGIN { printf("%-20s QC PASS\n", name)}'
7
8 FORCE:
0 This directory hosts a set of minimalistic example applications and
1 example scripts to try them on. Each example shall demonstrate a single
2 feature, the reader is expected to be able to combine these features when
3 building a large application.
4
5 Directories are prefixed with a number to keep examples in order of
6 complexity. Starting at lower numbers helps understanding the basics
7 before examples start to deal with the more complex features. Examples
8 prefixed with the same number are on the same level of complexity and
9 may depend on familiarity with lower numbered examples only.
10
11 Each directory is a single host application (with main() implemented in
12 app.c, being the starting point) usually accompanied by an awk script
13 (test.awk). There's always a comment explaining the purpose and invocation
14 of the example on top of app.c. Furthermore "make run" will run the example
15 with the standard invocation; the expected output is in out.ref; "make test"
16 runs the app and compares the output to the reference.
17
18
0 Version 1.2
1 ===========
2
3 Thanks for help with beta test to Bill Davidsen, Tom Dickey, Ed
4 Ferguson, Jack Fitts, Onno van der Linden, Carl Mascott, Jean-Pierre
5 Radley, John Roll, Ian Searle, Bob Stockler.
6
7 The calendar program examples/hical was written by Bob Stockler.
8
9 Darrel Hankerson ported versions 1.2.x to DOS/OS2.
10
11 Version 1.0 and 1.1
12 ===================
13
14 Carl Mascott ported mawk to V7 and in the process rooted out
15 some subtle (and not so subtle) bugs.
16
17 Ian Searle ported mawk to System V and put up with my insane
18 attempts to get fpe exception trapping off.
19
20 An anonymous reviewer for comp.sources.reviewed did the
21 MSC and Mac ports and wrote .bat files for the tests.
22 Another or maybe the same reviewer did the Dynix port.
23
24 Ports to new systems:
25 Ed Ferguson MIPS M2000 C2.20 OS4.52
26 Jwahar R. Bammi Atari ST
27 Berry Kercheval SGI IRIX 4.0.1
28 Andy Newman Next 2.1
29 Mike Carlton Next 2.1
30 Elliot Jaffe AIX 3.1
31 Jeremy Martin Convex 9.1
32 Scott Hunziker Coherent 4.0
33 Ken Poulton Hpux
34 Onno van der Linden 386bsd 0.1
35 Bob Hutchinson Linux 0.98p14
36
37 The DOS version is a lot better thanks to suggestions and testing
38 from Ed Ferguson, Jack Fitts, Nadav Horesh, Michael Golan and
39 Conny Ohstrom. The DOS additions for 1.1.2d are all ideas of
40 Ben Myers; much of the code is his too.
41
42 Arnold Robbins kept me current on POSIX standards for AWK, and
43 explained some of the "dark corners".
44
45 Thank you to everyone who reported bugs or offered encouragement,
46 suggestions or criticism. (At least the bugs got fixed).
0 1.3.1 -> 1.3.2 Sep 1996
1
2 1) Numeric but not integer indices caused core dump in new array scheme.
3 Fixed bug and fired test division.
4
5 2) Added ferror() checks on writes.
6
7 3) Added some static storage specs to array.c to keep non-ansi
8 compilers happy.
9
10 1.3 -> 1.3.1 Sep 1996
11 Release to new ftp site ftp://ftp.whidbey.net.
12
13 1) Workaround for overflow exception in strtod, sunos5.5 solaris.
14
15 2) []...] and [^]...] put ] in a class (or not in a class) without
16 having to use back-slash escape.
17
18 1.2.2 -> 1.3 Jul 1996
19 Extensive redesign of array data structures to support large arrays and
20 fast access to arrays created with split. Many of the ideas in the
21 new design were inspired by reading "The Design and Implementation of
22 Dynamic Hashing Sets and Tables in Icon" by William Griswold and
23 Gregg Townsend, SPE 23,351-367.
24
25 1.2.1 -> 1.2.2 Jan 1996
26
27 1) Improved autoconfig, in particular, fpe tests. This is far from
28 perfect and never will be until C standardizes an interface to ieee754.
29
30 2) Removed automatic error message on open failure for getline.
31
32 3) Flush all output before system(). Previous behavior was to only
33 flush std{out,err}.
34
35 4) Explicitly fclose() all output on exit to work around AIX4.1 bug.
36
37 5) Fixed random number generator to work with longs larger than
38 32bits.
39
40 6) Added a type Int which is int on real machines and long on dos machines.
41 Believe that all implicit assumptions that int=32bits are now gone.
0 GNU GENERAL PUBLIC LICENSE
1 Version 2, June 1991
2
3 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
4 675 Mass Ave, Cambridge, MA 02139, USA
5 Everyone is permitted to copy and distribute verbatim copies
6 of this license document, but changing it is not allowed.
7
8 Preamble
9
10 The licenses for most software are designed to take away your
11 freedom to share and change it. By contrast, the GNU General Public
12 License is intended to guarantee your freedom to share and change free
13 software--to make sure the software is free for all its users. This
14 General Public License applies to most of the Free Software
15 Foundation's software and to any other program whose authors commit to
16 using it. (Some other Free Software Foundation software is covered by
17 the GNU Library General Public License instead.) You can apply it to
18 your programs, too.
19
20 When we speak of free software, we are referring to freedom, not
21 price. Our General Public Licenses are designed to make sure that you
22 have the freedom to distribute copies of free software (and charge for
23 this service if you wish), that you receive source code or can get it
24 if you want it, that you can change the software or use pieces of it
25 in new free programs; and that you know you can do these things.
26
27 To protect your rights, we need to make restrictions that forbid
28 anyone to deny you these rights or to ask you to surrender the rights.
29 These restrictions translate to certain responsibilities for you if you
30 distribute copies of the software, or if you modify it.
31
32 For example, if you distribute copies of such a program, whether
33 gratis or for a fee, you must give the recipients all the rights that
34 you have. You must make sure that they, too, receive or can get the
35 source code. And you must show them these terms so they know their
36 rights.
37
38 We protect your rights with two steps: (1) copyright the software, and
39 (2) offer you this license which gives you legal permission to copy,
40 distribute and/or modify the software.
41
42 Also, for each author's protection and ours, we want to make certain
43 that everyone understands that there is no warranty for this free
44 software. If the software is modified by someone else and passed on, we
45 want its recipients to know that what they have is not the original, so
46 that any problems introduced by others will not reflect on the original
47 authors' reputations.
48
49 Finally, any free program is threatened constantly by software
50 patents. We wish to avoid the danger that redistributors of a free
51 program will individually obtain patent licenses, in effect making the
52 program proprietary. To prevent this, we have made it clear that any
53 patent must be licensed for everyone's free use or not licensed at all.
54
55 The precise terms and conditions for copying, distribution and
56 modification follow.
57
58 GNU GENERAL PUBLIC LICENSE
59 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
60
61 0. This License applies to any program or other work which contains
62 a notice placed by the copyright holder saying it may be distributed
63 under the terms of this General Public License. The "Program", below,
64 refers to any such program or work, and a "work based on the Program"
65 means either the Program or any derivative work under copyright law:
66 that is to say, a work containing the Program or a portion of it,
67 either verbatim or with modifications and/or translated into another
68 language. (Hereinafter, translation is included without limitation in
69 the term "modification".) Each licensee is addressed as "you".
70
71 Activities other than copying, distribution and modification are not
72 covered by this License; they are outside its scope. The act of
73 running the Program is not restricted, and the output from the Program
74 is covered only if its contents constitute a work based on the
75 Program (independent of having been made by running the Program).
76 Whether that is true depends on what the Program does.
77
78 1. You may copy and distribute verbatim copies of the Program's
79 source code as you receive it, in any medium, provided that you
80 conspicuously and appropriately publish on each copy an appropriate
81 copyright notice and disclaimer of warranty; keep intact all the
82 notices that refer to this License and to the absence of any warranty;
83 and give any other recipients of the Program a copy of this License
84 along with the Program.
85
86 You may charge a fee for the physical act of transferring a copy, and
87 you may at your option offer warranty protection in exchange for a fee.
88
89 2. You may modify your copy or copies of the Program or any portion
90 of it, thus forming a work based on the Program, and copy and
91 distribute such modifications or work under the terms of Section 1
92 above, provided that you also meet all of these conditions:
93
94 a) You must cause the modified files to carry prominent notices
95 stating that you changed the files and the date of any change.
96
97 b) You must cause any work that you distribute or publish, that in
98 whole or in part contains or is derived from the Program or any
99 part thereof, to be licensed as a whole at no charge to all third
100 parties under the terms of this License.
101
102 c) If the modified program normally reads commands interactively
103 when run, you must cause it, when started running for such
104 interactive use in the most ordinary way, to print or display an
105 announcement including an appropriate copyright notice and a
106 notice that there is no warranty (or else, saying that you provide
107 a warranty) and that users may redistribute the program under
108 these conditions, and telling the user how to view a copy of this
109 License. (Exception: if the Program itself is interactive but
110 does not normally print such an announcement, your work based on
111 the Program is not required to print an announcement.)
112
113 These requirements apply to the modified work as a whole. If
114 identifiable sections of that work are not derived from the Program,
115 and can be reasonably considered independent and separate works in
116 themselves, then this License, and its terms, do not apply to those
117 sections when you distribute them as separate works. But when you
118 distribute the same sections as part of a whole which is a work based
119 on the Program, the distribution of the whole must be on the terms of
120 this License, whose permissions for other licensees extend to the
121 entire whole, and thus to each and every part regardless of who wrote it.
122
123 Thus, it is not the intent of this section to claim rights or contest
124 your rights to work written entirely by you; rather, the intent is to
125 exercise the right to control the distribution of derivative or
126 collective works based on the Program.
127
128 In addition, mere aggregation of another work not based on the Program
129 with the Program (or with a work based on the Program) on a volume of
130 a storage or distribution medium does not bring the other work under
131 the scope of this License.
132
133 3. You may copy and distribute the Program (or a work based on it,
134 under Section 2) in object code or executable form under the terms of
135 Sections 1 and 2 above provided that you also do one of the following:
136
137 a) Accompany it with the complete corresponding machine-readable
138 source code, which must be distributed under the terms of Sections
139 1 and 2 above on a medium customarily used for software interchange; or,
140
141 b) Accompany it with a written offer, valid for at least three
142 years, to give any third party, for a charge no more than your
143 cost of physically performing source distribution, a complete
144 machine-readable copy of the corresponding source code, to be
145 distributed under the terms of Sections 1 and 2 above on a medium
146 customarily used for software interchange; or,
147
148 c) Accompany it with the information you received as to the offer
149 to distribute corresponding source code. (This alternative is
150 allowed only for noncommercial distribution and only if you
151 received the program in object code or executable form with such
152 an offer, in accord with Subsection b above.)
153
154 The source code for a work means the preferred form of the work for
155 making modifications to it. For an executable work, complete source
156 code means all the source code for all modules it contains, plus any
157 associated interface definition files, plus the scripts used to
158 control compilation and installation of the executable. However, as a
159 special exception, the source code distributed need not include
160 anything that is normally distributed (in either source or binary
161 form) with the major components (compiler, kernel, and so on) of the
162 operating system on which the executable runs, unless that component
163 itself accompanies the executable.
164
165 If distribution of executable or object code is made by offering
166 access to copy from a designated place, then offering equivalent
167 access to copy the source code from the same place counts as
168 distribution of the source code, even though third parties are not
169 compelled to copy the source along with the object code.
170
171 4. You may not copy, modify, sublicense, or distribute the Program
172 except as expressly provided under this License. Any attempt
173 otherwise to copy, modify, sublicense or distribute the Program is
174 void, and will automatically terminate your rights under this License.
175 However, parties who have received copies, or rights, from you under
176 this License will not have their licenses terminated so long as such
177 parties remain in full compliance.
178
179 5. You are not required to accept this License, since you have not
180 signed it. However, nothing else grants you permission to modify or
181 distribute the Program or its derivative works. These actions are
182 prohibited by law if you do not accept this License. Therefore, by
183 modifying or distributing the Program (or any work based on the
184 Program), you indicate your acceptance of this License to do so, and
185 all its terms and conditions for copying, distributing or modifying
186 the Program or works based on it.
187
188 6. Each time you redistribute the Program (or any work based on the
189 Program), the recipient automatically receives a license from the
190 original licensor to copy, distribute or modify the Program subject to
191 these terms and conditions. You may not impose any further
192 restrictions on the recipients' exercise of the rights granted herein.
193 You are not responsible for enforcing compliance by third parties to
194 this License.
195
196 7. If, as a consequence of a court judgment or allegation of patent
197 infringement or for any other reason (not limited to patent issues),
198 conditions are imposed on you (whether by court order, agreement or
199 otherwise) that contradict the conditions of this License, they do not
200 excuse you from the conditions of this License. If you cannot
201 distribute so as to satisfy simultaneously your obligations under this
202 License and any other pertinent obligations, then as a consequence you
203 may not distribute the Program at all. For example, if a patent
204 license would not permit royalty-free redistribution of the Program by
205 all those who receive copies directly or indirectly through you, then
206 the only way you could satisfy both it and this License would be to
207 refrain entirely from distribution of the Program.
208
209 If any portion of this section is held invalid or unenforceable under
210 any particular circumstance, the balance of the section is intended to
211 apply and the section as a whole is intended to apply in other
212 circumstances.
213
214 It is not the purpose of this section to induce you to infringe any
215 patents or other property right claims or to contest validity of any
216 such claims; this section has the sole purpose of protecting the
217 integrity of the free software distribution system, which is
218 implemented by public license practices. Many people have made
219 generous contributions to the wide range of software distributed
220 through that system in reliance on consistent application of that
221 system; it is up to the author/donor to decide if he or she is willing
222 to distribute software through any other system and a licensee cannot
223 impose that choice.
224
225 This section is intended to make thoroughly clear what is believed to
226 be a consequence of the rest of this License.
227
228 8. If the distribution and/or use of the Program is restricted in
229 certain countries either by patents or by copyrighted interfaces, the
230 original copyright holder who places the Program under this License
231 may add an explicit geographical distribution limitation excluding
232 those countries, so that distribution is permitted only in or among
233 countries not thus excluded. In such case, this License incorporates
234 the limitation as if written in the body of this License.
235
236 9. The Free Software Foundation may publish revised and/or new versions
237 of the General Public License from time to time. Such new versions will
238 be similar in spirit to the present version, but may differ in detail to
239 address new problems or concerns.
240
241 Each version is given a distinguishing version number. If the Program
242 specifies a version number of this License which applies to it and "any
243 later version", you have the option of following the terms and conditions
244 either of that version or of any later version published by the Free
245 Software Foundation. If the Program does not specify a version number of
246 this License, you may choose any version ever published by the Free Software
247 Foundation.
248
249 10. If you wish to incorporate parts of the Program into other free
250 programs whose distribution conditions are different, write to the author
251 to ask for permission. For software which is copyrighted by the Free
252 Software Foundation, write to the Free Software Foundation; we sometimes
253 make exceptions for this. Our decision will be guided by the two goals
254 of preserving the free status of all derivatives of our free software and
255 of promoting the sharing and reuse of software generally.
256
257 NO WARRANTY
258
259 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
260 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
261 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
262 PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
263 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
264 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
265 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
266 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
267 REPAIR OR CORRECTION.
268
269 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
270 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
271 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
272 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
273 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
274 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
275 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
276 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
277 POSSIBILITY OF SUCH DAMAGES.
278
279 END OF TERMS AND CONDITIONS
280
281 Appendix: How to Apply These Terms to Your New Programs
282
283 If you develop a new program, and you want it to be of the greatest
284 possible use to the public, the best way to achieve this is to make it
285 free software which everyone can redistribute and change under these terms.
286
287 To do so, attach the following notices to the program. It is safest
288 to attach them to the start of each source file to most effectively
289 convey the exclusion of warranty; and each file should have at least
290 the "copyright" line and a pointer to where the full notice is found.
291
292 <one line to give the program's name and a brief idea of what it does.>
293 Copyright (C) 19yy <name of author>
294
295 This program is free software; you can redistribute it and/or modify
296 it under the terms of the GNU General Public License as published by
297 the Free Software Foundation; either version 2 of the License, or
298 (at your option) any later version.
299
300 This program is distributed in the hope that it will be useful,
301 but WITHOUT ANY WARRANTY; without even the implied warranty of
302 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
303 GNU General Public License for more details.
304
305 You should have received a copy of the GNU General Public License
306 along with this program; if not, write to the Free Software
307 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
308
309 Also add information on how to contact you by electronic and paper mail.
310
311 If the program is interactive, make it output a short notice like this
312 when it starts in an interactive mode:
313
314 Gnomovision version 69, Copyright (C) 19yy name of author
315 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
316 This is free software, and you are welcome to redistribute it
317 under certain conditions; type `show c' for details.
318
319 The hypothetical commands `show w' and `show c' should show the appropriate
320 parts of the General Public License. Of course, the commands you use may
321 be called something other than `show w' and `show c'; they could even be
322 mouse-clicks or menu items--whatever suits your program.
323
324 You should also get your employer (if you work as a programmer) or your
325 school, if any, to sign a "copyright disclaimer" for the program, if
326 necessary. Here is a sample; alter the names:
327
328 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
329 `Gnomovision' (which makes passes at compilers) written by James Hacker.
330
331 <signature of Ty Coon>, 1 April 1989
332 Ty Coon, President of Vice
333
334 This General Public License does not permit incorporating your program into
335 proprietary programs. If your program is a subroutine library, you may
336 consider it more useful to permit linking proprietary applications with the
337 library. If this is what you want to do, use the GNU Library General
338 Public License instead of this License.
0 Look at the file config.user and edit to set user defines.
1
2 if your system is one of
3 apollo
4 convex
5 mips
6 sgi
7 ultrix-mips
8 cray
9 hpux (read below)
10 unixware (read below)
11
12 and you don't have gcc or prefer to use cc, then you may want to
13 copy config-user/your_system to config.user and edit that.
14
15 run
16
17 configure
18 make
19
20
21 If you have problems, please report it. If you can fix the problem, by
22 changing config.user, please send the results. Else send output from
23 configure, make and config.h. Send to brennan@whidbey.com.
24
25
26
27 DOS:
28 Look at the file msdos/INSTALL
29
30
31 HPUX:
32 Evidently there is more than one compiler and/or math library. Some
33 configurations work out of the box (configure/make). Others need
34 CFLAGS='+O2 +FPZO'. On HPUX 9.05 with the ansi compiler HP92453-01
35 A.09.77 set CFLAGS='-Ae +O2 +FPZO'. Thanks to Dr. Rafael R.
36 Pappalardo<rafapa@mozart.us.es> for this info.
37
38
39
40 UNIXWARE:
41 On some but not all versions, configure might decide you don't have
42 memcpy. Remove #define NO_MEMCPY 1 from config.h.
43 If the fpe_test check fails, change the definition of TURN_ON_FPE_TRAPS
44 to
45
46 #define TURN_ON_FPE_TRAPS() fpsetmask(fpgetmask()|FP_X_DZ|FP_X_OFL|FP_X_INV)
0 # select alternative zmalloc schemes
1 # commented out: use the slab-like original zmalloc (default)
2 # _native: use malloc()/free() - useful for memory leak hunting
3 # _safemalloc: use auto-cleanup malloc - useful if malloc() is preferred over slabs but the context should be cleaned up
4 #ZMALLOC_FLAVOR = _native
5
6 # install these headers in $(INCDIR)/libmawk/
7 IHEADERS=libmawk.h mawk.h init.h code.h files.h memory.h zmalloc.h \
8 symtype.h nstd.h types.h array.h sizes.h num.h num_int.h \
9 num_double.h conf.h bi_vars.h vio.h cell.h repl.h array_orig.h \
10 array_environ.h array_generic.h vio_orig.h vio_fifo.h zfifo.h \
11 execute.h
12
13 MAWKMAN = $(MANDIR)/lmawk.$(MANEXT)
14
15 VIO_OBJ = files_children.o vio_orig.o
16
17 # common objects
18 CO=memory.o hash.o code.o vars.o da_bin.o da_common.o da_bin_helper.o error.o \
19 bi_vars.o bi_funct_common.o array.o array_orig.o array_generic.o \
20 field_common.o re_cmpl.o zmalloc$(ZMALLOC_FLAVOR).o fin_common.o files.o matherr.o fcall.o \
21 version.o missing.o math_wrap.o cast.o cell.o scancode.o str.o \
22 array_environ.o \
23 $(VIO_OBJ) $(NUM_OBJ)
24
25 # parser objects
26 PO=parse.o scan.o da_text.o code_dump.o kw.o jmp.o
27
28 # execute objects
29 EO=execute.o bi_funct.o print.o debug.o field_exec.o split.o
30
31 REXP_O=rexp/rexp.o rexp/rexp0.o rexp/rexp1.o rexp/rexp2.o\
32 rexp/rexp3.o
33
34 REXP_C=rexp/rexp.c rexp/rexp0.c rexp/rexp1.c rexp/rexp2.c\
35 rexp/rexp3.c
36
37 # objects required for the buffer-vio
38 O_VIO_BUF=zfifo.o vio_fifo.o
39
40 # lib object
41 LO_ALL=$(CO) $(EO) $(PO) init.o libmawk.o fin_exec.o $(REXP_O) $(O_VIO_BUF)
42
43 # original all-in-one lmawk executable objects
44 O = main.o $(CO) $(EO) $(PO) init.o fin_exec.o viohack.o $(REXP_O)
45
46 # split shared object
47 O_COMP = bi_funct_dummy.o init.o print_dummy.o fin_comp.o $(PO) $(REXP_O)
48 O_EXEC = init_nocomp.o fin_exec.o $(O_VIO_BUF) $(EO) $(REXP_O)
49
50 # split executables
51 OBJ_COMP = main-comp.o viohack.o $(O_COMP) $(CO)
52 OBJ_EXEC = main-exec.o viohack.o $(O_EXEC) $(CO)
53
54 all: mawk_and_test
55
56 include Makefile.conf
57
58 BINS = lmawk lmawk-comp lmawk-exec \
59 libmawk.so libmawk.a \
60 libmawk_common.so libmawk_comp.so libmawk_exec.so \
61 regression/re_test/re_test
62
63 mawk_and_test : $(BINS)
64
65 libmawk.so: $(LO_ALL)
66 $(CC) -shared $(LDFLAGS_RDYNAMIC) $(LDFLAGS) $(LDFLAGS_SO) -o libmawk.so $(LO_ALL) $(MATHLIB)
67
68 libmawk_comp.so: $(O_COMP)
69 $(CC) -shared $(LDFLAGS_RDYNAMIC) $(LDFLAGS) -o libmawk_comp.so $(O_COMP) $(MATHLIB)
70
71 libmawk_exec.so: $(O_EXEC)
72 $(CC) -shared $(LDFLAGS_RDYNAMIC) $(LDFLAGS) -o libmawk_exec.so $(O_EXEC) $(MATHLIB)
73
74 libmawk_common.so: $(CO)
75 $(CC) -shared $(LDFLAGS_RDYNAMIC) $(LDFLAGS) -o libmawk_common.so $(CO) $(MATHLIB)
76
77 libmawk.a: $(LO_ALL)
78 ar rvu $@ $(LO_ALL)
79 ranlib $@
80
81 lmawk : $(O)
82 $(CC) $(CFLAGS) -o lmawk $(O) $(MATHLIB)
83
84 lmawk-comp : $(OBJ_COMP)
85 $(CC) $(CFLAGS) -o lmawk-comp $(OBJ_COMP) $(MATHLIB)
86
87 lmawk-exec : $(OBJ_EXEC)
88 $(CC) $(CFLAGS) -o lmawk-exec $(OBJ_EXEC) $(MATHLIB)
89
90 main-comp.o: main.c
91 $(CC) -c $(CFLAGS) -DMAWK_NO_EXEC=1 main.c -o main-comp.o
92
93 main-exec.o: main.c
94 $(CC) -c $(CFLAGS) -DMAWK_NO_COMP=1 main.c -o main-exec.o
95
96
97 scancode.c : makescan.c scan.h
98 $(CC) $(CFLAGS) -o makescan.exe makescan.c
99 rm -f scancode.c
100 ./makescan.exe > scancode.c
101 rm makescan.exe
102
103
104 # compile regression tests implemented in C
105 # these rules are not in Makefiles under regression/, so
106 # all the $(CC) and $(CFLAGS) work without any extra hassle
107 RE_TEST_O = regression/re_test/re_test.o rexp/rexp.o rexp/rexp0.o rexp/rexp1.o rexp/rexp2.o rexp/rexp3.o zmalloc$(ZMALLOC_FLAVOR).o memory.o
108 regression/re_test/re_test: $(RE_TEST_O)
109 $(CC) -o regression/re_test//re_test $(RE_TEST_O)
110
111 regression/re_test/re_test.o: regression/re_test/re_test.c
112 $(CC) -c $(CFLAGS) regression/re_test/re_test.c -o regression/re_test/re_test.o
113
114 ### misc: installation, clean, etc. ###
115
116 test: all
117 cd regression && make
118
119 PWD=`pwd`
120
121 install_ : lmawk libmawk.so
122 $(MKDIR) $(BINDIR)
123 $(MKDIR) $(MANDIR)
124 $(MKDIR) $(INCDIR)
125 $(MKDIR) $(LIBDIR)
126 $(CP) $(PWD)/lmawk $(BINDIR)
127 $(CHMODX) $(BINDIR)/lmawk
128 $(CP) $(PWD)/man/lmawk.1 $(MAWKMAN)
129 $(CHMOD) 0644 $(MAWKMAN)
130 $(CP) $(PWD)/libmawk.so $(LIBDIR)/libmawk.so.$(SOVER1).$(SOVER2).$(SOVER3)
131 rm $(LIBDIR)/libmawk.so.$(SOVER1).$(SOVER2) $(LIBDIR)/libmawk.so.$(SOVER1) 2>/dev/null ; true
132 ln -s libmawk.so.$(SOVER1).$(SOVER2).$(SOVER3) $(LIBDIR)/libmawk.so.$(SOVER1).$(SOVER2)
133 ln -s libmawk.so.$(SOVER1).$(SOVER2) $(LIBDIR)/libmawk.so.$(SOVER1)
134 ln -s libmawk.so.$(SOVER1) $(LIBDIR)/libmawk.so
135 for h in $(IHEADERS); do $(CP) $(PWD)/$$h $(INCDIR)/$$h; done
136 $(CP) $(PWD)/../libmawk.h $(INCDIR)/../libmawk.h
137
138 install:
139 make install_ CP="cp"
140
141 linstall:
142 make install_ CP="ln -s"
143
144
145 rexp/rexp.o: rexp/rexp.c
146 $(CC) -c $(CFLAGS) -o rexp/rexp.o rexp/rexp.c
147
148 rexp/rexp0.o: rexp/rexp0.c
149 $(CC) -c $(CFLAGS) -o rexp/rexp0.o rexp/rexp0.c
150
151 rexp/rexp1.o: rexp/rexp1.c
152 $(CC) -c $(CFLAGS) -o rexp/rexp1.o rexp/rexp1.c
153
154 rexp/rexp2.o: rexp/rexp2.c
155 $(CC) -c $(CFLAGS) -o rexp/rexp2.o rexp/rexp2.c
156
157 rexp/rexp3.o: rexp/rexp3.c
158 $(CC) -c $(CFLAGS) -o rexp/rexp3.o rexp/rexp3.c
159
160 $(NUM_OBJ): $(NUM_SRC) num.h
161
162 linstall: install
163
164 init_nocomp.o: init_nocomp.c
165 $(CC) -c $(CFLAGS) -o init_nocomp.o init_nocomp.c
166
167 init_nocomp.o: init.c
168
169
170 clean :
171 rm -f *.o rexp/*.o $(BINS)
172 cd regression && make clean
173
174 distclean : clean
175 rm -f defines.out maxint.out conf.h Makefile.conf
176
177 include Makefile.dep
178
179 depend:
180 @echo "# Generated by \"make depend\"" > Makefile.dep
181 gcc $(CFLAGS) -MM `echo $(LO_ALL) | sed "s/\.o/.c/g"` >> Makefile.dep
182
183 FORCE:
0 switch cc/soname
1 case {}
2 put /local/soname {}
3 end
4 default
5 put /local/soname [@@cc/soname@libmawk.so.@/local/version/1@@]
6 end
7 end
8
9 print [@
10 # version of the .so file is SOVER1.SOVER2.SOVER3
11 SOVER1=@/local/version/1@
12 SOVER2=@/local/version/2@
13 SOVER3=@/local/version/3@
14
15 PREFIX=@/local/prefix@
16
17 #--------------------- hand tweak values ---------------------------------
18 # TODO: scconfig
19 SHELL=/bin/sh
20
21 # where to put mawk
22 BINDIR = $(DESTDIR)$(install_root)$(PREFIX)/bin
23 # where to put libraries
24 LIBDIR = $(DESTDIR)$(install_root)$(PREFIX)/lib
25 # where to put include files
26 INCDIR = $(DESTDIR)$(install_root)$(PREFIX)/include/libmawk
27 # where to put the man pages
28 MANDIR = $(DESTDIR)$(install_root)$(PREFIX)/share/man/man1
29 # where to put the doc
30 DOCDIR = $(DESTDIR)$(install_root)$(PREFIX)/share/doc/libmawk
31 MANEXT = 1
32
33
34 #----------------- scconfig detected ----------------------------------
35 CC = @cc/cc@
36 CFLAGS = @cc/cflags@ @cc/fpic@ -I.. -I. $(CFLAGS_APP)
37 LDFLAGS = @cc/ldflags@
38 LDFLAGS_SO = @/local/soname@
39 LDFLAGS_RDYNAMIC = @cc/rdynamic@
40
41 CHMODX = @fstools/chmodx@
42 CHMOD = chmod
43 MKDIR = @fstools/mkdir@
44 CP=@fstools/cp@
45 SYMLINK=@fstools/ln@
46 @]
47
48 switch /local/numeric
49
50 case {double} print [@
51 # Numeric format is double (float enabled)
52 NUM_OBJ = num_double.o
53 NUM_SRC = num_double.c
54 MATHLIB = -lm
55 @]
56 end
57
58 case {int} print [@
59 # Numeric format is int (float disabled)
60 NUM_OBJ = num_int.o
61 NUM_SRC = num_int.c
62 MATHLIB =
63 @]
64 end
65 end
66
67 print [@
68 #--- parser generator ---
69 @]
70
71 if ?parsgen/bison/presents then
72 print [^
73 # bison found, can generate parse.c
74 YACC = ^parsgen/bison^ -y --name-prefix=Mawk_
75
76 parse.c : parse.y
77 @echo expect 4 shift/reduce conflicts
78 $(YACC) -d parse.y
79 mv y.tab.c parse.c
80 -if cmp -s y.tab.h parse.h ;\
81 then rm y.tab.h ;\
82 else mv y.tab.h parse.h ; fi
83 ^]
84 else
85 print [^
86 parse.c: parse.y
87 @echo WARNING: Can not generate parse.c from parse.y because bison was not found.
88 ^]
89 end
90
0 # Generated by "make depend"
1 memory.o: memory.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
2 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
3 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
4 ../libmawk/bi_vars.h ../libmawk/vio.h memory.h ../libmawk/zmalloc.h
5 hash.o: hash.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
6 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
7 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
8 ../libmawk/bi_vars.h ../libmawk/vio.h memory.h ../libmawk/zmalloc.h \
9 symtype.h ../libmawk/array.h ../libmawk/cell.h ../libmawk/repl.h \
10 ../libmawk/array_orig.h cell.h repl.h
11 code.o: code.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
12 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
13 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
14 ../libmawk/bi_vars.h ../libmawk/vio.h code.h ../libmawk/memory.h \
15 ../libmawk/zmalloc.h init.h ../libmawk/symtype.h ../libmawk/array.h \
16 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h jmp.h \
17 field.h
18 vars.o: vars.c vars.h mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
19 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
20 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
21 ../libmawk/bi_vars.h ../libmawk/vio.h symtype.h ../libmawk/array.h \
22 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h zmalloc.h \
23 cell.h repl.h
24 da_bin.o: da_bin.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
25 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
26 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
27 ../libmawk/bi_vars.h ../libmawk/vio.h code.h ../libmawk/memory.h \
28 ../libmawk/zmalloc.h bi_funct.h ../libmawk/symtype.h ../libmawk/array.h \
29 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h repl.h \
30 field.h num.h fin.h vars.h f2d.h
31 da_common.o: da_common.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
32 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
33 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
34 ../libmawk/bi_vars.h ../libmawk/vio.h code.h ../libmawk/memory.h \
35 ../libmawk/zmalloc.h bi_funct.h ../libmawk/symtype.h ../libmawk/array.h \
36 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h repl.h \
37 field.h num.h
38 da_bin_helper.o: da_bin_helper.c da_bin.h mawk.h ../libmawk/conf.h \
39 ../libmawk/nstd.h ../libmawk/conf.h ../libmawk/types.h \
40 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
41 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
42 ../libmawk/vio.h
43 error.o: error.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
44 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
45 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
46 ../libmawk/bi_vars.h ../libmawk/vio.h scan.h ../libmawk/symtype.h \
47 ../libmawk/array.h ../libmawk/cell.h ../libmawk/repl.h \
48 ../libmawk/array_orig.h ../libmawk/parse.h bi_vars.h vargs.h zmalloc.h \
49 memory.h ../libmawk/zmalloc.h cell.h repl.h
50 bi_vars.o: bi_vars.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
51 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
52 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
53 ../libmawk/bi_vars.h ../libmawk/vio.h symtype.h ../libmawk/array.h \
54 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h bi_vars.h \
55 field.h init.h ../libmawk/symtype.h memory.h ../libmawk/zmalloc.h num.h \
56 cell.h repl.h array_environ.h
57 bi_funct_common.o: bi_funct_common.c mawk.h ../libmawk/conf.h \
58 ../libmawk/nstd.h ../libmawk/conf.h ../libmawk/types.h \
59 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
60 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
61 ../libmawk/vio.h bi_funct.h ../libmawk/symtype.h ../libmawk/array.h \
62 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h bi_vars.h
63 array.o: array.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
64 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
65 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
66 ../libmawk/bi_vars.h ../libmawk/vio.h array.h cell.h repl.h array_orig.h \
67 memory.h ../libmawk/zmalloc.h zmalloc.h
68 array_orig.o: array_orig.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
69 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
70 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
71 ../libmawk/bi_vars.h ../libmawk/vio.h symtype.h ../libmawk/array.h \
72 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h memory.h \
73 ../libmawk/zmalloc.h zmalloc.h field.h bi_vars.h num.h array_orig.h \
74 cell.h repl.h split.h
75 array_generic.o: array_generic.c mawk.h ../libmawk/conf.h \
76 ../libmawk/nstd.h ../libmawk/conf.h ../libmawk/types.h \
77 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
78 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
79 ../libmawk/vio.h zmalloc.h memory.h ../libmawk/zmalloc.h split.h
80 field_common.o: field_common.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
81 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
82 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
83 ../libmawk/bi_vars.h ../libmawk/vio.h field.h init.h \
84 ../libmawk/symtype.h ../libmawk/array.h ../libmawk/cell.h \
85 ../libmawk/repl.h ../libmawk/array_orig.h memory.h ../libmawk/zmalloc.h \
86 scan.h ../libmawk/parse.h bi_vars.h repl.h regexp.h
87 re_cmpl.o: re_cmpl.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
88 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
89 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
90 ../libmawk/bi_vars.h ../libmawk/vio.h memory.h ../libmawk/zmalloc.h \
91 scan.h ../libmawk/symtype.h ../libmawk/array.h ../libmawk/cell.h \
92 ../libmawk/repl.h ../libmawk/array_orig.h ../libmawk/parse.h regexp.h \
93 repl.h
94 zmalloc.o: zmalloc.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
95 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
96 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
97 ../libmawk/bi_vars.h ../libmawk/vio.h zmalloc.h memory.h \
98 ../libmawk/zmalloc.h
99 fin_common.o: fin_common.c conf.h mawk.h ../libmawk/conf.h \
100 ../libmawk/nstd.h ../libmawk/conf.h ../libmawk/types.h \
101 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
102 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
103 ../libmawk/vio.h fin.h memory.h ../libmawk/zmalloc.h bi_vars.h field.h \
104 symtype.h ../libmawk/array.h ../libmawk/cell.h ../libmawk/repl.h \
105 ../libmawk/array_orig.h scan.h ../libmawk/symtype.h ../libmawk/parse.h \
106 vio.h
107 files.o: files.c conf.h mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
108 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
109 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
110 ../libmawk/bi_vars.h ../libmawk/vio.h files.h memory.h \
111 ../libmawk/zmalloc.h fin.h vio.h
112 matherr.o: matherr.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
113 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
114 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
115 ../libmawk/bi_vars.h ../libmawk/vio.h num.h
116 fcall.o: fcall.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
117 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
118 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
119 ../libmawk/bi_vars.h ../libmawk/vio.h symtype.h ../libmawk/array.h \
120 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h code.h \
121 ../libmawk/memory.h ../libmawk/zmalloc.h
122 version.o: version.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
123 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
124 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
125 ../libmawk/bi_vars.h ../libmawk/vio.h vio_orig.h
126 missing.o: missing.c nstd.h conf.h
127 math_wrap.o: math_wrap.c math_wrap.h num.h conf.h sizes.h \
128 ../libmawk/num_double.h
129 cast.o: cast.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
130 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
131 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
132 ../libmawk/bi_vars.h ../libmawk/vio.h field.h memory.h \
133 ../libmawk/zmalloc.h scan.h ../libmawk/symtype.h ../libmawk/array.h \
134 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h \
135 ../libmawk/parse.h repl.h num.h cell.h
136 cell.o: cell.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
137 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
138 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
139 ../libmawk/bi_vars.h ../libmawk/vio.h repl.h cell.h
140 scancode.o: scancode.c
141 str.o: str.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h ../libmawk/conf.h \
142 ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
143 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
144 ../libmawk/bi_vars.h ../libmawk/vio.h scan.h ../libmawk/symtype.h \
145 ../libmawk/array.h ../libmawk/cell.h ../libmawk/repl.h \
146 ../libmawk/array_orig.h ../libmawk/parse.h
147 array_environ.o: array_environ.c mawk.h ../libmawk/conf.h \
148 ../libmawk/nstd.h ../libmawk/conf.h ../libmawk/types.h \
149 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
150 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
151 ../libmawk/vio.h symtype.h ../libmawk/array.h ../libmawk/cell.h \
152 ../libmawk/repl.h ../libmawk/array_orig.h memory.h ../libmawk/zmalloc.h \
153 field.h bi_vars.h num.h array_orig.h array_generic.h cell.h repl.h
154 files_children.o: files_children.c conf.h mawk.h ../libmawk/conf.h \
155 ../libmawk/nstd.h ../libmawk/conf.h ../libmawk/types.h \
156 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
157 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
158 ../libmawk/vio.h files.h memory.h ../libmawk/zmalloc.h fin.h
159 vio_orig.o: vio_orig.c conf.h mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
160 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
161 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
162 ../libmawk/bi_vars.h ../libmawk/vio.h files.h memory.h \
163 ../libmawk/zmalloc.h fin.h field.h vio.h array_environ.h
164 num_double.o: num_double.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
165 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
166 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
167 ../libmawk/bi_vars.h ../libmawk/vio.h num.h math_wrap.h
168 execute.o: execute.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
169 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
170 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
171 ../libmawk/bi_vars.h ../libmawk/vio.h code.h ../libmawk/memory.h \
172 ../libmawk/zmalloc.h memory.h symtype.h ../libmawk/array.h \
173 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h field.h \
174 bi_funct.h ../libmawk/symtype.h bi_vars.h regexp.h repl.h fin.h debug.h \
175 num.h math_wrap.h cell.h execute.h f2d.h execute_debug.h
176 bi_funct.o: bi_funct.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
177 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
178 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
179 ../libmawk/bi_vars.h ../libmawk/vio.h bi_funct.h ../libmawk/symtype.h \
180 ../libmawk/array.h ../libmawk/cell.h ../libmawk/repl.h \
181 ../libmawk/array_orig.h bi_vars.h memory.h ../libmawk/zmalloc.h init.h \
182 files.h fin.h field.h regexp.h repl.h num.h math_wrap.h vio.h cell.h
183 print.o: print.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
184 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
185 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
186 ../libmawk/bi_vars.h ../libmawk/vio.h bi_vars.h bi_funct.h \
187 ../libmawk/symtype.h ../libmawk/array.h ../libmawk/cell.h \
188 ../libmawk/repl.h ../libmawk/array_orig.h memory.h ../libmawk/zmalloc.h \
189 field.h scan.h ../libmawk/parse.h files.h vio.h cell.h repl.h
190 debug.o: debug.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
191 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
192 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
193 ../libmawk/bi_vars.h ../libmawk/vio.h
194 field_exec.o: field_exec.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
195 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
196 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
197 ../libmawk/bi_vars.h ../libmawk/vio.h field.h init.h \
198 ../libmawk/symtype.h ../libmawk/array.h ../libmawk/cell.h \
199 ../libmawk/repl.h ../libmawk/array_orig.h memory.h ../libmawk/zmalloc.h \
200 scan.h ../libmawk/parse.h bi_vars.h repl.h regexp.h cell.h
201 split.o: split.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
202 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
203 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
204 ../libmawk/bi_vars.h ../libmawk/vio.h symtype.h ../libmawk/array.h \
205 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h bi_vars.h \
206 bi_funct.h ../libmawk/symtype.h memory.h ../libmawk/zmalloc.h scan.h \
207 ../libmawk/parse.h regexp.h field.h
208 parse.o: parse.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
209 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
210 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
211 ../libmawk/bi_vars.h ../libmawk/vio.h types.h symtype.h \
212 ../libmawk/array.h ../libmawk/cell.h ../libmawk/repl.h \
213 ../libmawk/array_orig.h code.h ../libmawk/memory.h ../libmawk/zmalloc.h \
214 memory.h bi_funct.h ../libmawk/symtype.h bi_vars.h jmp.h field.h files.h \
215 scan.h ../libmawk/parse.h zmalloc.h f2d.h
216 scan.o: scan.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
217 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
218 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
219 ../libmawk/bi_vars.h ../libmawk/vio.h scan.h ../libmawk/symtype.h \
220 ../libmawk/array.h ../libmawk/cell.h ../libmawk/repl.h \
221 ../libmawk/array_orig.h ../libmawk/parse.h memory.h ../libmawk/zmalloc.h \
222 field.h init.h fin.h repl.h code.h ../libmawk/memory.h bi_vars.h vio.h \
223 da_bin_helper.h files.h
224 da_text.o: da_text.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
225 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
226 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
227 ../libmawk/bi_vars.h ../libmawk/vio.h code.h ../libmawk/memory.h \
228 ../libmawk/zmalloc.h bi_funct.h ../libmawk/symtype.h ../libmawk/array.h \
229 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h repl.h \
230 field.h num.h f2d.h
231 code_dump.o: code_dump.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
232 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
233 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
234 ../libmawk/bi_vars.h ../libmawk/vio.h code.h ../libmawk/memory.h \
235 ../libmawk/zmalloc.h init.h ../libmawk/symtype.h ../libmawk/array.h \
236 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h jmp.h \
237 field.h da_bin_helper.h
238 kw.o: kw.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h ../libmawk/conf.h \
239 ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
240 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
241 ../libmawk/bi_vars.h ../libmawk/vio.h symtype.h ../libmawk/array.h \
242 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h parse.h \
243 init.h ../libmawk/symtype.h
244 jmp.o: jmp.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h ../libmawk/conf.h \
245 ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
246 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
247 ../libmawk/bi_vars.h ../libmawk/vio.h symtype.h ../libmawk/array.h \
248 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h jmp.h code.h \
249 ../libmawk/memory.h ../libmawk/zmalloc.h sizes.h init.h \
250 ../libmawk/symtype.h memory.h
251 init.o: init.c conf.h mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
252 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
253 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
254 ../libmawk/bi_vars.h ../libmawk/vio.h code.h ../libmawk/memory.h \
255 ../libmawk/zmalloc.h memory.h symtype.h ../libmawk/array.h \
256 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h init.h \
257 ../libmawk/symtype.h scan.h ../libmawk/parse.h bi_vars.h field.h \
258 zmalloc.h vio.h version.h da_bin_helper.h cell.h repl.h files.h
259 libmawk.o: libmawk.c libmawk.h ../libmawk/mawk.h ../libmawk/conf.h \
260 ../libmawk/nstd.h ../libmawk/conf.h ../libmawk/types.h \
261 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
262 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
263 ../libmawk/vio.h ../libmawk/init.h ../libmawk/symtype.h \
264 ../libmawk/array.h ../libmawk/cell.h ../libmawk/repl.h \
265 ../libmawk/array_orig.h ../libmawk/code.h ../libmawk/memory.h \
266 ../libmawk/zmalloc.h ../libmawk/files.h ../libmawk/array_generic.h \
267 ../libmawk/vio_orig.h ../libmawk/vio_fifo.h ../libmawk/vio.h \
268 ../libmawk/zfifo.h ../libmawk/execute.h debug.h mawk.h memory.h sizes.h \
269 array.h fin.h num.h vio.h vars.h vio_fifo.h vio_orig.h
270 fin_exec.o: fin_exec.c conf.h mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
271 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
272 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
273 ../libmawk/bi_vars.h ../libmawk/vio.h fin.h memory.h \
274 ../libmawk/zmalloc.h bi_vars.h field.h symtype.h ../libmawk/array.h \
275 ../libmawk/cell.h ../libmawk/repl.h ../libmawk/array_orig.h scan.h \
276 ../libmawk/symtype.h ../libmawk/parse.h vio.h init.h vars.h cell.h \
277 repl.h files.h
278 rexp.o: rexp/rexp.c rexp/rexp.h ../libmawk/nstd.h ../libmawk/conf.h \
279 ../libmawk/mawk.h ../libmawk/conf.h ../libmawk/types.h \
280 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
281 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
282 ../libmawk/vio.h
283 rexp0.o: rexp/rexp0.c rexp/rexp.h ../libmawk/nstd.h ../libmawk/conf.h \
284 ../libmawk/mawk.h ../libmawk/conf.h ../libmawk/types.h \
285 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
286 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
287 ../libmawk/vio.h ../libmawk/zmalloc.h
288 rexp1.o: rexp/rexp1.c rexp/rexp.h ../libmawk/nstd.h ../libmawk/conf.h \
289 ../libmawk/mawk.h ../libmawk/conf.h ../libmawk/types.h \
290 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
291 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
292 ../libmawk/vio.h ../libmawk/zmalloc.h
293 rexp2.o: rexp/rexp2.c rexp/rexp.h ../libmawk/nstd.h ../libmawk/conf.h \
294 ../libmawk/mawk.h ../libmawk/conf.h ../libmawk/types.h \
295 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
296 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
297 ../libmawk/vio.h
298 rexp3.o: rexp/rexp3.c rexp/rexp.h ../libmawk/nstd.h ../libmawk/conf.h \
299 ../libmawk/mawk.h ../libmawk/conf.h ../libmawk/types.h \
300 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
301 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
302 ../libmawk/vio.h
303 zfifo.o: zfifo.c mawk.h ../libmawk/conf.h ../libmawk/nstd.h \
304 ../libmawk/conf.h ../libmawk/types.h ../libmawk/sizes.h ../libmawk/num.h \
305 ../libmawk/sizes.h ../libmawk/num_double.h ../libmawk/mawk.h \
306 ../libmawk/bi_vars.h ../libmawk/vio.h zfifo.h zmalloc.h
307 vio_fifo.o: vio_fifo.c vio_fifo.h mawk.h ../libmawk/conf.h \
308 ../libmawk/nstd.h ../libmawk/conf.h ../libmawk/types.h \
309 ../libmawk/sizes.h ../libmawk/num.h ../libmawk/sizes.h \
310 ../libmawk/num_double.h ../libmawk/mawk.h ../libmawk/bi_vars.h \
311 ../libmawk/vio.h vio.h zfifo.h memory.h ../libmawk/zmalloc.h
0 Mawk -- an implementation of new/posix awk
1 version 1.3.2
2
3 Installation instructions in file INSTALL.
4
5 Bug reports, comments, questions, etc. to
6 Mike Brennan, brennan@whidbey.com.
7 ftp site: ftp.whidbey.net in ~/pub/brennan
8
9 Version 1.3 implements a new internal design for arrays. See file
10 CHANGES.
11
12 Version 1.2.2 is best for MsDOS
13 ---------------------------------------------------------
14
15 Changes from version 1.1.4 to 1.2:
16
17 1) Limit on code size set by #define in sizes.h is gone.
18
19 2) A number of obscure bugs have been fixed such as,
20 you can now make a recursive function call inside a for( i in A) loop.
21 Function calls with array parameters in loop expressions sometimes
22 generated erroneous internal code.
23
24 See RCS log comments in code for details.
25
26 Reported bugs are fixed.
27
28 3) new -W options
29
30
31 -We file : reads commands from file and next argument, regardless
32 of form, is ARGV[1]. Useful for passing -v , -f etc to
33 an awk program started with #!/.../mawk
34
35
36 #!/usr/local/bin/mawk -We
37
38 myprogram -v works, while
39
40 #!/usr/local/bin/mawk -f
41
42 myprogram -v gives error message
43 mawk: option -v lacks argument
44
45 This is really a posix bozo. Posix says you end arguments with
46 -- , but this doesn't work with the #! convention.
47
48
49
50 -W interactive : forces stdout to be unbuffered and stdin to
51 be line buffered. Records from stdin are lines regardless of
52 the value of RS. Useful for interaction with a mawk on a pipe.
53
54 -W dump, -Wd : disassembles internal code to stdout (used to be
55 stderr) and exits 0.
56
57 4) FS = "" causes each record to be broken into characters and placed
58 into $1,$2 ...
59
60 same with split(x,A,"") and split(x,A,//)
61
62
63 5) print > "/dev/stdout" writes to stdout, exactly the same as
64 print
65
66 This is useful for passing stdout to
67
68 function my_special_output_routine(s, file)
69 {
70 # do something fancy with s
71 print s > file
72 }
73
74
75 6) New built-in function fflush() -- copied from the lastest att awk.
76
77 fflush() : flushes stdout and returns 0
78 fflush(file) flushes file and returns 0; if file was not an
79 open output file then returns -1.
80
81 7) delete A ; -- removes all elements of the array A
82
83 intended to replace:
84
85 for( i in A) delete A[i]
86
87 8) mawk errors such as compilation failure, file open failure, etc.
88 now exit 2 which reserves exit 1 for the user.
89
90 9) No program now silently exits 0, prior behavior was to exit 2 with
91 an error message
0 /*
1 libmawk (C) 2014, Tibor 'Igor2' Palinkas;
2
3 libMawk is distributed without warranty under the terms of
4 the GNU General Public License, version 2, 1991.
5 */
6 #include <stdlib.h>
7 #include <string.h>
8 #include "mawk.h"
9 #include "array.h"
10 #include "memory.h"
11 #include "zmalloc.h"
12 #include "cell.h"
13
14 /* -- generic array implementation -- */
15
16 /* - creating a new array does not depend on the implementation - */
17 mawk_array_t mawk_array_new(mawk_state_t *MAWK, const array_imp_t *imp)
18 {
19 mawk_array_t a;
20 a = MAWK_ZMALLOC(MAWK, struct array);
21 memset(a, 0, sizeof(struct array));
22 if (imp == NULL)
23 a->imp = mawk_array_orig_imp;
24 else
25 a->imp = *imp;
26 return a;
27 }
28
29 void mawk_array_destroy(mawk_state_t *MAWK, mawk_array_t ARR)
30 {
31 mawk_array_clear(MAWK, ARR);
32 mawk_zfree(MAWK, ARR, sizeof(struct array));
33 }
34
35 /* catting the indices together doesn't depend on implementation */
36 mawk_cell_t *mawk_array_cat(mawk_state_t *MAWK, mawk_cell_t *sp, int cnt)
37 {
38 mawk_cell_t *p; /* walks the eval stack */
39 mawk_cell_t subsep; /* local copy of SUBSEP */
40 unsigned subsep_len; /* string length of subsep_str */
41 char *subsep_str;
42
43 unsigned total_len; /* length of cat'ed expression */
44 mawk_cell_t *top; /* value of sp at entry */
45 char *target; /* build cat'ed char* here */
46 mawk_string_t *sval; /* build cat'ed mawk_string_t here */
47 mawk_cellcpy(MAWK, &subsep, SUBSEP);
48 if (subsep.type < C_STRING)
49 mawk_cast1_to_str(MAWK, &subsep);
50 subsep_len = string(&subsep)->len;
51 subsep_str = string(&subsep)->str;
52
53 top = sp;
54 sp -= (cnt - 1);
55
56 total_len = (cnt - 1) * subsep_len;
57 for (p = sp; p <= top; p++) {
58 if (p->type < C_STRING)
59 mawk_cast1_to_str(MAWK, p);
60 total_len += string(p)->len;
61 }
62
63 sval = mawk_new_STRING0(MAWK, total_len);
64 target = sval->str;
65 for (p = sp; p < top; p++) {
66 memcpy(target, string(p)->str, string(p)->len);
67 target += string(p)->len;
68 memcpy(target, subsep_str, subsep_len);
69 target += subsep_len;
70 }
71 /* now p == top */
72 memcpy(target, string(p)->str, string(p)->len);
73
74 for (p = sp; p <= top; p++)
75 free_STRING(string(p));
76 free_STRING(string(&subsep));
77 /* set contents of sp , sp->type > C_STRING is possible so reset */
78 sp->type = C_STRING;
79 sp->ptr = (PTR) sval;
80 return sp;
81 }
82
83 void mawk_array_clear_common(mawk_state_t *MAWK, mawk_array_t A)
84 {
85 A->ptr = NULL;
86 A->size = 0;
87 A->limit = 0;
88 A->hmask = 0;
89 A->type = 0;
90
91 }
92
93 /* - naive implementation for the complex queries -
94 these assume the most basic operations (set/get/find/delet) to be implemented
95 and provide a slow, but generic implementation for the higher level
96 calls */
97
98 /* TODO */
0 /*
1 array.h
2
3 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991-96, Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 */
14
15 /*
16 This file originally had been generated with the command
17
18 notangle -R'"array.h"' array.w > array.h
19
20 but is maintained as .h in libmawk.
21
22 (Notangle is part of Norman Ramsey's noweb literate programming package
23 available from CTAN(ftp.shsu.edu)).
24 */
25
26 #ifndef ARRAY_H
27 #define ARRAY_H 1
28
29 #define AY_NULL 0
30 #define AY_INT 1
31 #define AY_STR 2
32 #define AY_SPLIT 4
33
34 #define NO_MAWK_CREATE 0
35 #define MAWK_CREATE 1
36
37 #include "cell.h"
38 #include "array_orig.h"
39
40 /* create a new, empty array, copying implementation from imp; if imp is NULL,
41 use the default (original) implementation. */
42 mawk_array_t mawk_array_new(mawk_state_t *MAWK, const array_imp_t *imp);
43
44 /* free all memory used by ARR */
45 void mawk_array_destroy(mawk_state_t *MAWK, mawk_array_t ARR);
46
47 /* concat multiple expressions separated by SUBSEP to be an array index */
48 mawk_cell_t *mawk_array_cat(mawk_state_t *MAWK, mawk_cell_t *sp, int cnt);
49
50 /* clear the common administrative part of the array, leaving imp alone;
51 this must be used instead of memsetting the mawk_array_t */
52 void mawk_array_clear_common(mawk_state_t *MAWK, mawk_array_t A);
53
54
55 /* wrappers for accessing the implementations; a layer of macros is introduced
56 here to guarantee future flexibility */
57 /* **** WARNING: these macros will ecaluate ARR_ at least twice! **** */
58 #define mawk_array_find(MAWK_, ARR_, idx_, result_, create_) (ARR_)->imp.find((MAWK_), (ARR_), (idx_), (result_), (create_))
59 #define mawk_array_set(MAWK_, ARR_, idx_, val_) (ARR_)->imp.set((MAWK_), (ARR_), (idx_), (val_))
60 #define mawk_array_delete(MAWK_, ARR_, cell_) (ARR_)->imp.delet((MAWK_), (ARR_), (cell_))
61 #define mawk_array_clear(MAWK_, ARR_) (ARR_)->imp.clear((MAWK_), (ARR_))
62 #define mawk_array_loop_vector(MAWK_, ARR_, sizep_) (ARR_)->imp.loop_vect((MAWK_), (ARR_), (sizep_))
63 #define mawk_array_load(MAWK_, ARR_, cnt_) (ARR_)->imp.load((MAWK_), (ARR_), (cnt_))
64
65
66
67
68
69 /* The following macros are used in execute.c for fast and convenient access
70 to cells on SP */
71
72 /* check whether an array is pure (no side effects, aka orig implementation) for
73 read or read+write */
74 #define mawk_array_pure4wr(MAWK, ARR_) (ARR_)->imp.set == mawk_array_orig_imp.set
75 #define mawk_array_pure4del(MAWK, ARR_) (ARR_)->imp.delet == mawk_array_orig_imp.delet
76 #define mawk_array_pure4rd(MAWK, ARR_) (ARR_)->imp.find == mawk_array_orig_imp.find
77 #define mawk_array_pure4rdwr(MAWK, ARR_) ((mawk_array_pure4wr((MAWK), (ARR_))) && (mawk_array_pure4del((MAWK), (ARR_))) && (mawk_array_pure4rd((MAWK), (ARR_))))
78
79 #define mawk_array_pure(MAWK, ARR_REF_, for_write) ((for_write) ? (mawk_array_pure4rdwr((MAWK), (mawk_array_t)(ARR_REF_)->ptr)) : (mawk_array_pure4rd((MAWK), (mawk_array_t)(ARR_REF_)->ptr)))
80
81 /* change the value of an array pointed to by ARR_REF_ (typer C_ARR_REF).
82 This wrapper is useful from execute.c where multiple assignments
83 to array elemts will have to do the same:
84 - look up the index in the array
85 - modify the content of the array element
86 - destroy the index and the rvalue
87 - put the value of the expr in res_
88
89 Note: mawk_cell_destroy(MAWK, (mawk_cell_t *)(ARR_REF_)) is not required: destroy of C_ARR_REF is a nop
90 */
91 #define mawk_array_set_execute_(MAWK, res_, ARR_REF_, IDX_, rvalue_) \
92 do { \
93 mawk_array_set(MAWK, (mawk_array_t)((ARR_REF_)->ptr), (IDX_), rvalue_); \
94 mawk_cell_destroy(MAWK, (mawk_cell_t *)(IDX_)); \
95 if (IDX_ != res_) \
96 mawk_cell_destroy(MAWK, res_); \
97 mawk_cellcpy(MAWK, res_, rvalue_); \
98 mawk_cell_destroy(MAWK, rvalue_); \
99 } while(0)
100
101 /* look up an array element; place the resulting cell in res_
102
103 Does not destroy IDX_.
104
105 Note: mawk_cell_destroy(MAWK, (mawk_cell_t *)(ARR_REF_)) is not required: destroy of C_ARR_REF is a nop
106 */
107 #define mawk_array_get_execute_(MAWK, res_, ARR_REF_, IDX_) \
108 do { \
109 mawk_array_find(MAWK, (mawk_array_t)((ARR_REF_)->ptr), (IDX_), (res_), MAWK_CREATE); \
110 } while(0)
111
112
113 /* this must not be used on arrays with side effects */
114 mawk_cell_t *mawk_array_find_orig_(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *cp, int create_flag);
115 #define mawk_array_getptr_execute_(MAWK, res_, ARR_REF_, IDX_) \
116 do { \
117 res_ = mawk_array_find_orig_(MAWK, (mawk_array_t)((ARR_REF_)->ptr), (IDX_), MAWK_CREATE); \
118 } while(0)
119
120
121 /* same as mawk_arra_get_execute plus cast the result to number if it is not
122 a number already
123 does not destroy IDX
124 */
125 #define mawk_array_getnum_execute_(MAWK, res_, ARR_REF_, IDX_) \
126 do { \
127 mawk_array_get_execute(MAWK, (res_), (ARR_REF_), (IDX_)); \
128 if ((res_)->type != C_NUM) \
129 mawk_cast1_to_num(MAWK, (res_)); \
130 } while(0)
131
132 #ifdef DEBUG
133 /* in debug mode use static inlines for easier debugging */
134 static inline void mawk_array_get_execute(mawk_state_t *MAWK, mawk_cell_t *res, mawk_cell_t *arr_ref, mawk_cell_t *idx)
135 {
136 mawk_array_get_execute_(MAWK, res, arr_ref, idx);
137 }
138
139 static inline void mawk_array_getptr_execute(mawk_state_t *MAWK, mawk_cell_t *res, mawk_cell_t *arr_ref, mawk_cell_t *idx)
140 {
141 mawk_array_getptr_execute_(MAWK, res, arr_ref, idx);
142 }
143
144 static inline void mawk_array_getnum_execute(mawk_state_t *MAWK, mawk_cell_t *res, mawk_cell_t *arr_ref, mawk_cell_t *idx)
145 {
146 mawk_array_getnum_execute_(MAWK, res, arr_ref, idx);
147 }
148
149 static inline void mawk_array_set_execute(mawk_state_t *MAWK, mawk_cell_t *res, mawk_cell_t *arr_ref, mawk_cell_t *idx, mawk_cell_t *rvalue)
150 {
151 mawk_array_set_execute_(MAWK, res, arr_ref, idx, rvalue);
152 }
153 #else
154 #define mawk_array_getnum_execute mawk_array_getnum_execute_
155 #define mawk_array_getptr_execute mawk_array_getptr_execute_
156 #define mawk_array_get_execute mawk_array_get_execute_
157 #define mawk_array_set_execute mawk_array_set_execute_
158 #endif
159
160
161
162 #endif /* ARRAY_H */
163
164
165
0 /*
1 libmawk changes (C) 2009-2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for mawk, an implementation of
4 the AWK programming language.
5
6 Mawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 */
9
10 /*
11
12 ENVIRON[] implementation
13 ~~~~~~~~~~~~~~~~~~~~~~~~
14 Although POSIX doesn't require this, in libmawk ENVIRON[] should affect
15 any exec'd child process (getline and system()). Since there may be multiple
16 mawk_state_t instances, ENVIRON[] can not directly manipulate the global
17 char **environ. Instead each context has its own array.
18
19 Unlike in the original code, the ENVIRON[] array is not initialized
20 before the first runtime reference to it. This saves some memory and
21 some time, but more importantly it makes libmawk able to run in
22 situations where there's no standard environment (e.g. the Linux kernel).
23
24 */
25
26 #include <stdio.h>
27 #include <string.h>
28 #include "mawk.h"
29 #include "symtype.h"
30 #include "memory.h"
31 #include "field.h"
32 #include "bi_vars.h"
33 #include "num.h"
34 #include "array_orig.h"
35 #include "array_generic.h"
36 #include "cell.h"
37
38 /* bits of array state */
39 enum {
40 ST_LOADED = 1,
41 ST_MODIFIED = 2
42 };
43
44 /* copy the process' environ to ENVIRON */
45 static void mawk_load_environ(mawk_state_t *MAWK, mawk_array_t ENV)
46 {
47 mawk_cell_t ci, cv;
48 extern char **environ;
49 register char **p = environ; /* walks environ */
50 char *s; /* looks for the '=' */
51
52 ci.type = C_STRING;
53 cv.type = C_MBSTRN;
54
55 while (*p) {
56 if ((s = strchr(*p, '='))) { /* shouldn't fail */
57 int len = s - *p;
58 ci.ptr = (PTR) mawk_new_STRING0(MAWK, len);
59 memcpy(string(&ci)->str, *p, len);
60 s++;
61
62 cv.ptr = (PTR) mawk_new_STRING(MAWK, s);
63 mawk_array_orig_imp.set(MAWK, ENV, &ci, &cv);
64
65 free_STRING(string(&ci));
66 }
67 p++;
68 }
69 }
70
71 static void chkenv(mawk_state_t *MAWK, mawk_array_t A)
72 {
73 if ((A->state.i & ST_LOADED) == 0) {
74 A->state.i |= ST_LOADED;
75 mawk_load_environ(MAWK, A);
76 }
77 }
78
79
80 int mawk_array_find_environ(mawk_state_t *MAWK, mawk_array_t arr, const mawk_cell_t *idx, mawk_cell_t *result, int create)
81 {
82 chkenv(MAWK, arr);
83 if ((create) && ((arr->state.i & ST_MODIFIED) == 0)) {
84 /* we are allowed to create the item in a so-far-unmodofied ENVIRON[]:
85 check if the item exists and mark the array modified only if it
86 really would be created - this keeps the array un-modified after
87 read-only operations
88 NOTE: maybe idx == result, so we don't want result to be destroyed
89 in this call, thus result is NULL.
90 */
91 if (mawk_array_orig_imp.find(MAWK, arr, idx, NULL, 0) < 1)
92 arr->state.i |= ST_MODIFIED;
93 }
94 return mawk_array_orig_imp.find(MAWK, arr, idx, result, create);
95 }
96
97
98 void mawk_array_set_environ(mawk_state_t *MAWK, mawk_array_t arr, const mawk_cell_t *idx, mawk_cell_t *val)
99 {
100 chkenv(MAWK, arr);
101 arr->state.i |= ST_MODIFIED;
102 mawk_array_orig_imp.set(MAWK, arr, idx, val);
103 }
104
105
106 static void mawk_array_delete_environ(mawk_state_t *MAWK, mawk_array_t arr, const mawk_cell_t *idx)
107 {
108 chkenv(MAWK, arr);
109 arr->state.i |= ST_MODIFIED;
110 mawk_array_orig_imp.delet(MAWK, arr, idx);
111 }
112
113 static mawk_string_t **mawk_array_loop_vector_environ(mawk_state_t *MAWK, mawk_array_t A, unsigned *size)
114 {
115 chkenv(MAWK, A);
116 /* could use the _generic() as well, but that'd be a tiny bit slower and
117 there's no side effect other than chkenv() */
118 /* return mawk_array_loop_vector_generic(MAWK, A, size);*/
119 return mawk_array_orig_imp.loop_vect(MAWK, A, size);
120 }
121
122 /* mark array initialized before clearning, so if a delete ENVIRON
123 precedes any other call, the environment is not loaded at all. */
124 void mawk_array_clear_environ(mawk_state_t *MAWK, mawk_array_t arr)
125 {
126 arr->state.i |= ST_LOADED | ST_MODIFIED;
127 mawk_array_clear_generic(MAWK, arr);
128 }
129
130 array_imp_t mawk_array_environ_imp = {
131 mawk_array_find_environ,
132 mawk_array_set_environ,
133 mawk_array_delete_environ,
134
135 mawk_array_clear_environ,
136 mawk_array_loop_vector_environ,
137 mawk_array_load_generic,
138
139 mawk_array_it_start_orig,
140 mawk_array_it_next_orig,
141 mawk_array_it_stop_orig
142 };
143
144
145 void mawk_environ_init(mawk_state_t *MAWK)
146 {
147 SYMTAB *s;
148 s = mawk_insert(MAWK, "ENVIRON");
149 s->type = ST_ARRAY;
150 s->stval.array = mawk_array_new(MAWK, &mawk_array_environ_imp);
151 }
152
153 #ifdef MAWK_MEM_PEDANTIC
154 void mawk_environ_uninit(mawk_state_t *MAWK)
155 {
156 SYMTAB *s;
157 s = mawk_find(MAWK, "ENVIRON", 0);
158 if (s != NULL) {
159 if (s->type == ST_ARRAY)
160 mawk_array_destroy(MAWK, s->stval.array);
161 mawk_delete(MAWK, "ENVIRON", 0);
162 }
163 }
164 #endif
165
166 extern char **environ;
167 #define grow() \
168 do { \
169 if (used >= alloced) { \
170 alloced += 128; \
171 ret = mawk_realloc(MAWK, ret, sizeof(char *) * alloced); \
172 } \
173 } while(0)
174
175 char **mawk_environ_extract(mawk_state_t *MAWK)
176 {
177 void *it;
178 const mawk_cell_t *idx;
179 char **ret = NULL;
180 unsigned used = 0, alloced = 0;
181 mawk_array_t arr;
182 SYMTAB *s;
183
184 s = mawk_find(MAWK, "ENVIRON", 0);
185 /* ENVIRON[] is not set up - use the global environ[] */
186 if (s == NULL)
187 return environ;
188
189 arr = s->stval.array;
190
191 /* ENVIRON[] is not loaded - use the global environ[] */
192 if ((arr->state.i & ST_LOADED) == 0)
193 return environ;
194
195 /* ENVIRON[] is not modified - use the global environ[], cheaper than to copy */
196 if ((arr->state.i & ST_MODIFIED) == 0)
197 return environ;
198
199
200 it = arr->imp.it_start(MAWK, arr);
201 for(;;) {
202 char *si, *sv;
203 mawk_cell_t cv;
204 int sil, svl;
205
206 idx = arr->imp.it_next(MAWK, arr, it);
207 if (idx == NULL)
208 break;
209 si = string(idx)->str;
210 if (mawk_array_find_environ(MAWK, arr, idx, &cv, 0) <= 0)
211 sv = "";
212 else
213 sv = string(&cv)->str;
214
215 grow();
216 sil = strlen(si);
217 svl = strlen(sv);
218 ret[used] = mawk_malloc(MAWK, sil+svl+2);
219 memcpy(ret[used], si, sil);
220 ret[used][sil] = '=';
221 memcpy(ret[used]+sil+1, sv, svl+1);
222 used++;
223 }
224
225 grow();
226 ret[used] = NULL;
227 used++;
228
229 arr->imp.it_stop(MAWK, arr, it);
230 return ret;
231 }
232
0 /* create a blank array reserved for ENVIRON[] */
1 void mawk_environ_init(mawk_state_t *MAWK);
2
3 #ifdef MAWK_MEM_PEDANTIC
4 void mawk_environ_uninit(mawk_state_t *MAWK);
5 #endif
6
7 /* allocate memory and return an array suitable for env arg of execle();
8 allocation is done using mawk_malloc() to ensure a large ENVIRON[] doesn't
9 cause excess memory allocation (ram limit!). However, this allocation
10 is not to be free'd ever, since an exec() or exit() follows the call.
11 Thus if there's no change to the ENVIRON[] array, a pointer to
12 environ is returned and no allocation is done.
13
14 Returns NULL on error
15 */
16 char **mawk_environ_extract(mawk_state_t *MAWK);
0 #include "mawk.h"
1 void mawk_environ_init(mawk_state_t *MAWK)
2 {
3 }
0 /*
1 libmawk changes (C) 2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for mawk, an implementation of
4 the AWK programming language.
5
6 This file implements generic virtual array calls clear, loop_vector and load.
7 These calls rely on the low level find/set/iterator implementation of the
8 custom array and saves the time for the implementor writing these functions.
9 In return these functions are not fast at all.
10 */
11
12 #include "mawk.h"
13 #include "zmalloc.h"
14 #include "memory.h"
15 #include "split.h"
16
17 void mawk_array_clear_generic(mawk_state_t *MAWK, mawk_array_t arr)
18 {
19 void *it;
20 const mawk_cell_t *idx;
21
22 if (arr->imp.it_start == NULL)
23 mawk_bozo(MAWK, "mawk_array_clear_generic() on an array without iterator");
24 if (arr->imp.delet == NULL)
25 mawk_bozo(MAWK, "mawk_array_clear_generic() on an array without delet");
26
27 it = arr->imp.it_start(MAWK, arr);
28 for(;;) {
29 idx = arr->imp.it_next(MAWK, arr, it);
30 if (idx == NULL)
31 break;
32 arr->imp.delet(MAWK, arr, idx);
33 }
34 arr->imp.it_stop(MAWK, arr, it);
35 }
36
37 mawk_string_t **mawk_array_loop_vector_generic(mawk_state_t *MAWK, mawk_array_t arr, unsigned *size)
38 {
39 void *it;
40 const mawk_cell_t *idx;
41 mawk_string_t **ret = NULL;
42 unsigned used = 0, alloced = 0;
43
44 if (arr->imp.it_start == NULL)
45 mawk_bozo(MAWK, "mawk_array_loop_vector_generic() on an array without iterator");
46
47 it = arr->imp.it_start(MAWK, arr);
48 for(;;) {
49 idx = arr->imp.it_next(MAWK, arr, it);
50 if (idx == NULL)
51 break;
52 if (used >= alloced) {
53 alloced += 128;
54 ret = mawk_realloc(MAWK, ret, sizeof(mawk_string_t *) * alloced);
55 }
56 ret[used] = idx->ptr;
57 ret[used]->ref_cnt++;
58 used++;
59 }
60 arr->imp.it_stop(MAWK, arr, it);
61 *size = used;
62 return ret;
63 }
64
65 void mawk_array_load_generic(mawk_state_t *MAWK, mawk_array_t arr, int cnt)
66 {
67 mawk_cell_t cidx, cval;
68
69 if (arr->imp.set == NULL)
70 mawk_bozo(MAWK, "mawk_array_load_generic() on an array without set");
71
72 if (arr->imp.clear != NULL)
73 arr->imp.clear(MAWK, arr);
74 else
75 mawk_array_clear_generic(MAWK, arr);
76
77 cidx.type = C_NUM;
78 cval.type = C_STRING;
79
80 #define action(idx, sval) \
81 cidx.d.dval = idx+1; \
82 cval.ptr = (PTR) sval; \
83 arr->imp.set(MAWK, arr, &cidx, &cval);
84
85 mawk_split_walk(MAWK, cnt, 1, action);
86
87 #undef action
88
89 }
0 void mawk_array_clear_generic(mawk_state_t *, mawk_array_t);
1 mawk_string_t **mawk_array_loop_vector_generic(mawk_state_t *, mawk_array_t, unsigned *vsize);
2 void mawk_array_load_generic(mawk_state_t *, mawk_array_t, int cnt);
3
0 /*
1 libmawk changes (C) 2009-2014, Tibor 'Igor2' Palinkas;
2 based on mawk code coming with the below copyright:
3
4 copyright 1991-96, Michael D. Brennan
5
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
8
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 */
12
13 /*
14 This file had been originally generated with the command
15
16 notangle -R'"array.c"' array.w > array.c
17
18 but is maintained as .c in libmawk.
19
20 (Notangle is part of Norman Ramsey's noweb literate programming package
21 available from CTAN(ftp.shsu.edu)).
22 */
23 #include <stdio.h>
24 #include <string.h>
25 #include "mawk.h"
26 #include "symtype.h"
27 #include "memory.h"
28 #include "zmalloc.h"
29 #include "field.h"
30 #include "bi_vars.h"
31 #include "num.h"
32 #include "array_orig.h"
33 #include "cell.h"
34 #include "split.h"
35
36 struct anode;
37 typedef struct {
38 struct anode *slink, *ilink;
39 } DUAL_LINK;
40
41 typedef struct anode {
42 struct anode *slink;
43 struct anode *ilink;
44 mawk_string_t *sval;
45 unsigned hval;
46 Int ival;
47 mawk_cell_t cell;
48 } ANODE;
49
50
51 #define NOT_AN_IVALUE (-Max_Int-1) /* usually 0x80000000 */
52
53 #define STARTING_HMASK 63 /* 2^6-1, must have form 2^n-1 */
54 #define MAX_AVE_LIST_LENGTH 12
55 #define hmask_to_limit(x) (((x)+1)*MAX_AVE_LIST_LENGTH)
56
57 static ANODE *mawk_find_by_ival(mawk_state_t *, mawk_array_t, Int, int);
58 static ANODE *mawk_find_by_sval(mawk_state_t *, mawk_array_t, mawk_string_t *, int);
59 static void add_string_associations(mawk_state_t *, mawk_array_t);
60 static void make_empty_table(mawk_state_t *, mawk_array_t, int);
61 static void convert_split_array_to_table(mawk_state_t *, mawk_array_t);
62 static void double_the_hash_table(mawk_state_t *, mawk_array_t);
63 static unsigned ahash(mawk_string_t *);
64
65
66 mawk_cell_t *mawk_array_find_orig_(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *cp, int create_flag)
67 {
68 ANODE *ap;
69 if (A->size == 0 && !create_flag)
70 /* eliminating this trivial case early avoids unnecessary conversions later */
71 return (mawk_cell_t *) 0;
72 switch (cp->type) {
73 case C_NUM:
74 {
75 mawk_num_t d = cp->d.dval;
76 Int ival = mawk_d_to_I(d);
77 if ((mawk_num_t) ival == d) {
78 if (A->type == AY_SPLIT) {
79 if (ival >= 1 && ival <= A->size)
80 return (mawk_cell_t *) A->ptr + (ival - 1);
81 if (!create_flag)
82 return (mawk_cell_t *) 0;
83 convert_split_array_to_table(MAWK, A);
84 }
85 else if (A->type == AY_NULL) {
86 make_empty_table(MAWK, A, AY_INT);
87 if (A->ptr == NULL)
88 return NULL;
89 }
90 ap = mawk_find_by_ival(MAWK, A, ival, create_flag);
91 }
92 else {
93 /* convert to string */
94 char buff[260];
95 mawk_string_t *sval;
96 sprintf(buff, string(MAWK_CONVFMT)->str, d);
97 sval = mawk_new_STRING(MAWK, buff);
98 ap = mawk_find_by_sval(MAWK, A, sval, create_flag);
99 free_STRING(sval);
100 }
101 }
102
103 break;
104 case C_NOINIT:
105 ap = mawk_find_by_sval(MAWK, A, &(MAWK->null_str), create_flag);
106 break;
107 default:
108 ap = mawk_find_by_sval(MAWK, A, string(cp), create_flag);
109 break;
110 }
111 return ap ? &ap->cell : (mawk_cell_t *) 0;
112 }
113
114 static int mawk_array_find_orig(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *idx, mawk_cell_t *result, int create)
115 {
116 mawk_cell_t *member;
117
118 member = mawk_array_find_orig_(MAWK, A, idx, create);
119 if (result != NULL) {
120 mawk_cell_destroy(MAWK, result);
121 result->type = C_NOINIT;
122 }
123 if (member == NULL)
124 return 0;
125 if (result != NULL)
126 mawk_cellcpy(MAWK, result, member);
127 return 1;
128 }
129
130 void mawk_array_set_orig(mawk_state_t *MAWK, mawk_array_t arr, const mawk_cell_t *idx, mawk_cell_t *val)
131 {
132 mawk_cell_t *member;
133 member = mawk_array_find_orig_(MAWK, arr, idx, MAWK_CREATE);
134 mawk_cell_destroy(MAWK, member);
135 mawk_cellcpy(MAWK, member, val);
136 }
137
138
139 static void mawk_array_delete_orig(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *cp)
140 {
141 ANODE *ap;
142 if (A->size == 0)
143 return;
144 switch (cp->type) {
145 case C_NUM:
146 {
147 mawk_num_t d = cp->d.dval;
148 Int ival = mawk_d_to_I(d);
149 if ((mawk_num_t) ival == d) {
150 if (A->type == AY_SPLIT) {
151 if (ival >= 1 && ival <= A->size) {
152 convert_split_array_to_table(MAWK, A);
153 }
154 else
155 return; /* ival not in range */
156 }
157 ap = mawk_find_by_ival(MAWK, A, ival, NO_MAWK_CREATE);
158 if (ap) { /* remove from the front of the ilist */
159 DUAL_LINK *table = (DUAL_LINK *) A->ptr;
160 table[ap->ival & A->hmask].ilink = ap->ilink;
161 if (ap->sval) {
162 ANODE *p, *q = 0;
163 int index = ap->hval & A->hmask;
164 p = table[index].slink;
165 while (p != ap) {
166 q = p;
167 p = q->slink;
168 }
169 if (q)
170 q->slink = p->slink;
171 else
172 table[index].slink = p->slink;
173 free_STRING(ap->sval);
174 }
175
176 mawk_cell_destroy(MAWK, &ap->cell);
177 MAWK_ZFREE(MAWK, ap);
178 if (--A->size == 0)
179 mawk_array_clear(MAWK, A);
180
181
182 }
183 return;
184 }
185
186 else { /* get the string value */
187 char buff[260];
188 mawk_string_t *sval;
189 sprintf(buff, string(MAWK_CONVFMT)->str, d);
190 sval = mawk_new_STRING(MAWK, buff);
191 ap = mawk_find_by_sval(MAWK, A, sval, NO_MAWK_CREATE);
192 free_STRING(sval);
193 }
194 }
195 break;
196 case C_NOINIT:
197 ap = mawk_find_by_sval(MAWK, A, &(MAWK->null_str), NO_MAWK_CREATE);
198 break;
199 default:
200 ap = mawk_find_by_sval(MAWK, A, string(cp), NO_MAWK_CREATE);
201 break;
202 }
203 if (ap) { /* remove from the front of the slist */
204 DUAL_LINK *table = (DUAL_LINK *) A->ptr;
205 table[ap->hval & A->hmask].slink = ap->slink;
206 if (ap->ival != NOT_AN_IVALUE) {
207 ANODE *p, *q = 0;
208 int index = ap->ival & A->hmask;
209 p = table[index].ilink;
210 while (p != ap) {
211 q = p;
212 p = q->ilink;
213 }
214 if (q)
215 q->ilink = p->ilink;
216 else
217 table[index].ilink = p->ilink;
218 }
219
220 free_STRING(ap->sval);
221 mawk_cell_destroy(MAWK, &ap->cell);
222 MAWK_ZFREE(MAWK, ap);
223 if (--A->size == 0)
224 mawk_array_clear(MAWK, A);
225 }
226 }
227
228
229 static void mawk_array_load_orig(mawk_state_t *MAWK, mawk_array_t A, int cnt)
230 {
231 mawk_cell_t *cells; /* storage for A[1..cnt] */
232 int i; /* index into cells[] */
233
234 /* destroy the original array and set up the new */
235 if (A->type != AY_SPLIT || A->limit < cnt) {
236 mawk_array_clear(MAWK, A);
237 A->limit = (cnt & ~3) + 4;
238 A->ptr = mawk_zmalloc(MAWK, A->limit * sizeof(mawk_cell_t));
239 A->type = AY_SPLIT;
240 }
241 else
242 for (i = 0; i < A->size; i++)
243 mawk_cell_destroy(MAWK, (mawk_cell_t *) A->ptr + i);
244
245 cells = (mawk_cell_t *) A->ptr;
246 A->size = cnt;
247
248 #define action(idx, sval) \
249 cells[idx].type = C_MBSTRN; \
250 cells[idx].ptr = (PTR) sval;
251
252 mawk_split_walk(MAWK, cnt, 1, action);
253
254 #undef action
255 }
256
257 static void mawk_array_clear_orig(mawk_state_t *MAWK, mawk_array_t A)
258 {
259 int i;
260 ANODE *p, *q;
261 if (A->type == AY_SPLIT) {
262 for (i = 0; i < A->size; i++)
263 mawk_cell_destroy(MAWK, (mawk_cell_t *) A->ptr + i);
264 mawk_zfree(MAWK, A->ptr, A->limit * sizeof(mawk_cell_t));
265 }
266 else if (A->type & AY_STR) {
267 DUAL_LINK *table = (DUAL_LINK *) A->ptr;
268 for (i = 0; i <= A->hmask; i++) {
269 p = table[i].slink;
270 while (p) {
271 q = p;
272 p = q->slink;
273 free_STRING(q->sval);
274 mawk_cell_destroy(MAWK, &q->cell);
275 MAWK_ZFREE(MAWK, q);
276 }
277 }
278 mawk_zfree(MAWK, A->ptr, (A->hmask + 1) * sizeof(DUAL_LINK));
279 }
280 else if (A->type & AY_INT) {
281 DUAL_LINK *table = (DUAL_LINK *) A->ptr;
282 for (i = 0; i <= A->hmask; i++) {
283 p = table[i].ilink;
284 while (p) {
285 q = p;
286 p = q->ilink;
287 mawk_cell_destroy(MAWK, &q->cell);
288 MAWK_ZFREE(MAWK, q);
289 }
290 }
291 mawk_zfree(MAWK, A->ptr, (A->hmask + 1) * sizeof(DUAL_LINK));
292 }
293 mawk_array_clear_common(MAWK, A);
294 }
295
296
297
298 static mawk_string_t **mawk_array_loop_vector_orig(mawk_state_t *MAWK, mawk_array_t A, unsigned *sizep)
299 {
300 mawk_string_t **ret;
301 *sizep = A->size;
302 if (A->size > 0) {
303 if (!(A->type & AY_STR))
304 add_string_associations(MAWK, A);
305 ret = (mawk_string_t **) mawk_malloc(MAWK, A->size * sizeof(mawk_string_t *));
306 {
307 int r = 0; /* indexes ret */
308 DUAL_LINK *table = (DUAL_LINK *) A->ptr;
309 int i; /* indexes table */
310 ANODE *p; /* walks slists */
311 for (i = 0; i <= A->hmask; i++) {
312 for (p = table[i].slink; p; p = p->slink) {
313 ret[r++] = p->sval;
314 p->sval->ref_cnt++;
315 }
316 }
317 }
318
319 return ret;
320 }
321 else
322 return (mawk_string_t **) 0;
323 }
324
325 static ANODE *mawk_find_by_ival(mawk_state_t *MAWK, mawk_array_t A, Int ival, int create_flag)
326 {
327 DUAL_LINK *table = (DUAL_LINK *) A->ptr;
328 unsigned index = ival & A->hmask;
329 ANODE *p = table[index].ilink; /* walks ilist */
330 ANODE *q = (ANODE *) 0; /* trails p */
331 while (1) {
332 if (!p) {
333 /* search failed */
334 if (A->type & AY_STR) {
335 /* need to search by string */
336 char buff[256];
337 mawk_string_t *sval;
338 sprintf(buff, INT_FMT, ival);
339 sval = mawk_new_STRING(MAWK, buff);
340 p = mawk_find_by_sval(MAWK, A, sval, create_flag);
341 free_STRING(sval);
342 if (!p)
343 return (ANODE *) 0;
344 }
345 else if (create_flag) {
346 p = MAWK_ZMALLOC(MAWK, ANODE);
347 p->sval = (mawk_string_t *) 0;
348 p->cell.type = C_NOINIT;
349 if (++A->size > A->limit) {
350 double_the_hash_table(MAWK, A); /* changes table, may change index */
351 table = (DUAL_LINK *) A->ptr;
352 index = A->hmask & ival;
353 }
354 }
355 else
356 return (ANODE *) 0;
357 p->ival = ival;
358 A->type |= AY_INT;
359
360 break;
361 }
362 else if (p->ival == ival) {
363 /* found it, now move to the front */
364 if (!q) /* already at the front */
365 return p;
366 /* delete for mawk_insertion at the front */
367 q->ilink = p->ilink;
368 break;
369 }
370 q = p;
371 p = q->ilink;
372 }
373 /* mawk_insert at the front */
374 p->ilink = table[index].ilink;
375 table[index].ilink = p;
376 return p;
377 }
378
379 static ANODE *mawk_find_by_sval(mawk_state_t *MAWK, mawk_array_t A, mawk_string_t *sval, int create_flag)
380 {
381 unsigned hval = ahash(sval);
382 char *str = sval->str;
383 DUAL_LINK *table;
384 int index;
385 ANODE *p; /* walks list */
386 ANODE *q = (ANODE *) 0; /* trails p */
387 if (!(A->type & AY_STR))
388 add_string_associations(MAWK, A);
389 table = (DUAL_LINK *) A->ptr;
390 index = hval & A->hmask;
391 p = table[index].slink;
392 while (1) {
393 if (!p) {
394 if (create_flag) {
395 {
396 p = MAWK_ZMALLOC(MAWK, ANODE);
397 p->sval = sval;
398 sval->ref_cnt++;
399 p->ival = NOT_AN_IVALUE;
400 p->hval = hval;
401 p->cell.type = C_NOINIT;
402 if (++A->size > A->limit) {
403 double_the_hash_table(MAWK, A); /* changes table, may change index */
404 table = (DUAL_LINK *) A->ptr;
405 index = hval & A->hmask;
406 }
407 }
408
409 break;
410 }
411 else
412 return (ANODE *) 0;
413 }
414 else if (p->hval == hval && strcmp(p->sval->str, str) == 0) {
415 /* found */
416 if (!q) /* already at the front */
417 return p;
418 else { /* delete for move to the front */
419 q->slink = p->slink;
420 break;
421 }
422 }
423 q = p;
424 p = q->slink;
425 }
426 p->slink = table[index].slink;
427 table[index].slink = p;
428 return p;
429 }
430
431 static void add_string_associations(mawk_state_t *MAWK, mawk_array_t A)
432 {
433 if (A->type == AY_NULL)
434 make_empty_table(MAWK, A, AY_STR);
435 else {
436 DUAL_LINK *table;
437 int i; /* walks table */
438 ANODE *p; /* walks ilist */
439 char buff[256];
440 if (A->type == AY_SPLIT)
441 convert_split_array_to_table(MAWK, A);
442 table = (DUAL_LINK *) A->ptr;
443 for (i = 0; i <= A->hmask; i++) {
444 p = table[i].ilink;
445 while (p) {
446 sprintf(buff, INT_FMT, p->ival);
447 p->sval = mawk_new_STRING(MAWK, buff);
448 p->hval = ahash(p->sval);
449 p->slink = table[A->hmask & p->hval].slink;
450 table[A->hmask & p->hval].slink = p;
451 p = p->ilink;
452 }
453 }
454 A->type |= AY_STR;
455 }
456 }
457
458 static void make_empty_table(mawk_state_t *MAWK, mawk_array_t A, int type)
459 {
460 /* type -> AY_INT or AY_STR */
461 size_t sz = (STARTING_HMASK + 1) * sizeof(DUAL_LINK);
462
463 A->ptr = mawk_zmalloc(MAWK, sz);
464 if (A->ptr != NULL) {
465 A->type = type;
466 A->hmask = STARTING_HMASK;
467 A->limit = hmask_to_limit(STARTING_HMASK);
468 memset(A->ptr, 0, sz);
469 }
470 else {
471 A->limit = 0;
472 }
473 }
474
475 static void convert_split_array_to_table(mawk_state_t *MAWK, mawk_array_t A)
476 {
477 mawk_cell_t *cells = (mawk_cell_t *) A->ptr;
478 int i; /* walks cells */
479 DUAL_LINK *table;
480 int j; /* walks table */
481 unsigned entry_limit = A->limit;
482 A->hmask = STARTING_HMASK;
483 A->limit = hmask_to_limit(STARTING_HMASK);
484 while (A->size > A->limit) {
485 A->hmask = (A->hmask << 1) + 1; /* double the size */
486 A->limit = hmask_to_limit(A->hmask);
487 }
488 {
489 size_t sz = (A->hmask + 1) * sizeof(DUAL_LINK);
490 A->ptr = memset(mawk_zmalloc(MAWK, sz), 0, sz);
491 table = (DUAL_LINK *) A->ptr;
492 }
493
494
495 /* mawk_insert each cells[i] in the new mawk_hash table on an ilist */
496 for (i = 0, j = 1; i < A->size; i++) {
497 ANODE *p = MAWK_ZMALLOC(MAWK, ANODE);
498 p->sval = (mawk_string_t *) 0;
499 p->ival = i + 1;
500 p->cell = cells[i];
501 p->ilink = table[j].ilink;
502 table[j].ilink = p;
503 j++;
504 j &= A->hmask;
505 }
506 A->type = AY_INT;
507 mawk_zfree(MAWK, cells, entry_limit * sizeof(mawk_cell_t));
508 }
509
510 static void double_the_hash_table(mawk_state_t *MAWK, mawk_array_t A)
511 {
512 unsigned old_hmask = A->hmask;
513 unsigned new_hmask = (old_hmask << 1) + 1;
514 DUAL_LINK *table;
515 A->ptr = mawk_zrealloc(MAWK, A->ptr, (old_hmask + 1) * sizeof(DUAL_LINK), (new_hmask + 1) * sizeof(DUAL_LINK));
516 table = (DUAL_LINK *) A->ptr;
517 /* zero out the new part which is the back half */
518 memset(&table[old_hmask + 1], 0, (old_hmask + 1) * sizeof(DUAL_LINK));
519
520 if (A->type & AY_STR) {
521 int i; /* index to old lists */
522 int j; /* index to new lists */
523 ANODE *p; /* walks an old list */
524 ANODE *q; /* trails p for deletion */
525 ANODE *tail; /* builds new list from the back */
526 ANODE dummy0, dummy1;
527 for (i = 0, j = old_hmask + 1; i <= old_hmask; i++, j++) {
528 q = &dummy0;
529 q->slink = p = table[i].slink;
530 tail = &dummy1;
531 while (p) {
532 if ((p->hval & new_hmask) != i) { /* move it */
533 q->slink = p->slink;
534 tail = tail->slink = p;
535 }
536 else
537 q = p;
538 p = q->slink;
539 }
540 table[i].slink = dummy0.slink;
541 tail->slink = (ANODE *) 0;
542 table[j].slink = dummy1.slink;
543 }
544
545 }
546
547 if (A->type & AY_INT) {
548 int i; /* index to old lists */
549 int j; /* index to new lists */
550 ANODE *p; /* walks an old list */
551 ANODE *q; /* trails p for deletion */
552 ANODE *tail; /* builds new list from the back */
553 ANODE dummy0, dummy1;
554 for (i = 0, j = old_hmask + 1; i <= old_hmask; i++, j++) {
555 q = &dummy0;
556 q->ilink = p = table[i].ilink;
557 tail = &dummy1;
558 while (p) {
559 if ((p->ival & new_hmask) != i) { /* move it */
560 q->ilink = p->ilink;
561 tail = tail->ilink = p;
562 }
563 else
564 q = p;
565 p = q->ilink;
566 }
567 table[i].ilink = dummy0.ilink;
568 tail->ilink = (ANODE *) 0;
569 table[j].ilink = dummy1.ilink;
570 }
571
572 }
573
574 A->hmask = new_hmask;
575 A->limit = hmask_to_limit(new_hmask);
576 }
577
578
579 static unsigned ahash(mawk_string_t *sval)
580 {
581 unsigned sum1 = sval->len;
582 unsigned sum2 = sum1;
583 unsigned char *p, *q;
584 if (sum1 <= 10) {
585 for (p = (unsigned char *) sval->str; *p; p++) {
586 sum1 += sum1 + *p;
587 sum2 += sum1;
588 }
589 }
590 else {
591 int cnt = 5;
592 p = (unsigned char *) sval->str; /* p starts at the front */
593 q = (unsigned char *) sval->str + (sum1 - 1); /* q starts at the back */
594 while (cnt) {
595 cnt--;
596 sum1 += sum1 + *p;
597 sum2 += sum1;
598 sum1 += sum1 + *q;
599 sum2 += sum1;
600 p++;
601 q--;
602 }
603 }
604 return sum2;
605 }
606
607
608 /* iterator for array_generic (for array implementations built on top or array_orig */
609 typedef struct {
610 int i; /* indexes table */
611 ANODE *p; /* walks slists */
612 mawk_cell_t ridx;
613 } array_it_orig_t;
614
615 void *mawk_array_it_start_orig(mawk_state_t *MAWK, mawk_array_t A)
616 {
617 array_it_orig_t *it;
618
619 if (A->size > 0) {
620 if (!(A->type & AY_STR))
621 add_string_associations(MAWK, A);
622 }
623
624 it = mawk_zmalloc(MAWK, sizeof(array_it_orig_t));
625 if (it == NULL)
626 return NULL;
627 it->i = -1;
628 it->p = NULL;
629 it->ridx.type = C_STRING;
630 return it;
631 }
632
633 const mawk_cell_t *mawk_array_it_next_orig(mawk_state_t *MAWK, mawk_array_t A, void *iterator)
634 {
635 DUAL_LINK *table = (DUAL_LINK *) A->ptr;
636 array_it_orig_t *it = iterator;
637
638 if (A->size <= 0)
639 return NULL;
640
641 if ((it->i >= 0) && (it->i > A->hmask))
642 return NULL;
643
644 if (it->p == NULL) {
645 /* this slot is over */
646 for(;;) {
647 it->i++; /* check next slot in the array of linked lists */
648 if (it->i > A->hmask)
649 return NULL; /* hit end of table */
650 it->p = table[it->i].slink;
651 if (it->p != NULL)
652 break; /* found an entry, go on returning it */
653 }
654 }
655
656 it->ridx.ptr = it->p->sval;
657 it->p = it->p->slink;
658 return &it->ridx;
659 }
660
661 void mawk_array_it_stop_orig(mawk_state_t *MAWK, mawk_array_t A, void *iterator)
662 {
663 array_it_orig_t *it = iterator;
664 mawk_zfree(MAWK, it, sizeof(array_it_orig_t));
665 }
666
667
668 /* public implementation array */
669 array_imp_t mawk_array_orig_imp = {
670 mawk_array_find_orig,
671 mawk_array_set_orig,
672 mawk_array_delete_orig,
673
674 mawk_array_clear_orig,
675 mawk_array_loop_vector_orig,
676 mawk_array_load_orig,
677
678 mawk_array_it_start_orig,
679 mawk_array_it_next_orig,
680 mawk_array_it_stop_orig
681 };
682
683
0 /*
1 libmawk (C) 2014, Tibor 'Igor2' Palinkas;
2
3 libMawk is distributed without warranty under the terms of
4 the GNU General Public License, version 2, 1991.
5 */
6
7 #ifndef ARRAY_ORIG_H
8 #define ARRAY_ORIG_H 1
9
10 /* the original mawk array implementation, large, cryptic and well optimized */
11 extern array_imp_t mawk_array_orig_imp;
12
13
14 /* iterator - used by custom array implementations built on top of array_orig */
15 void *mawk_array_it_start_orig(mawk_state_t *MAWK, mawk_array_t A);
16 const mawk_cell_t *mawk_array_it_next_orig(mawk_state_t *MAWK, mawk_array_t A, void *iterator);
17 void mawk_array_it_stop_orig(mawk_state_t *MAWK, mawk_array_t A, void *iterator);
18
19 #endif /* ARRAY_ORIG_H */
0
1 /********************************************
2 bi_funct.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include "mawk.h"
16 #include "bi_funct.h"
17 #include "bi_vars.h"
18 #include "memory.h"
19 #include "init.h"
20 #include "files.h"
21 #include "fin.h"
22 #include "field.h"
23 #include "regexp.h"
24 #include "repl.h"
25 #include "num.h"
26 #include "math_wrap.h"
27 #include "vio.h"
28 #include "cell.h"
29 #include <string.h>
30 #include <unistd.h>
31
32
33 /* statics */
34 static mawk_string_t *gsub(mawk_state_t *, PTR, mawk_cell_t *, char *, char *, int);
35 static void fplib_err(mawk_state_t *, char *, mawk_num_t, char *);
36
37 /****************************************************************
38 string builtins (except split (in split.c) and [g]sub (at end))
39 ****************************************************************/
40
41 mawk_cell_t *mawk_bi_length(mawk_state_t *MAWK, register mawk_cell_t *sp)
42 {
43 unsigned len;
44
45 if (sp->type == 0)
46 mawk_cellcpy(MAWK, sp, MAWK->field);
47 else
48 sp--;
49
50 if (sp->type < C_STRING)
51 mawk_cast1_to_str(MAWK, sp);
52 len = string(sp)->len;
53
54 free_STRING(string(sp));
55 sp->type = C_NUM;
56 sp->d.dval = (double) len;
57
58 return sp;
59 }
60
61 char *mawk_str_str(register char *target, char *key, unsigned key_len)
62 {
63 register int k = key[0];
64
65 switch (key_len) {
66 case 0:
67 return (char *) 0;
68 case 1:
69 return strchr(target, k);
70 case 2:
71 {
72 int k1 = key[1];
73 while ((target = strchr(target, k)))
74 if (target[1] == k1)
75 return target;
76 else
77 target++;
78 /*failed */
79 return (char *) 0;
80 }
81 }
82
83 key_len--;
84 while ((target = strchr(target, k))) {
85 if (strncmp(target + 1, key + 1, key_len) == 0)
86 return target;
87 else
88 target++;
89 }
90 /*failed */
91 return (char *) 0;
92 }
93
94
95
96 mawk_cell_t *mawk_bi_index(mawk_state_t *MAWK, register mawk_cell_t *sp)
97 {
98 register int idx;
99 unsigned len;
100 char *p;
101
102 sp--;
103 if (TEST2(sp) != TWO_STRINGS)
104 mawk_cast2_to_str(MAWK, sp);
105
106 if ((len = string(sp + 1)->len))
107 idx = (p = mawk_str_str(string(sp)->str, string(sp + 1)->str, len))
108 ? p - string(sp)->str + 1 : 0;
109
110 else /* index of the empty string */
111 idx = 1;
112
113 free_STRING(string(sp));
114 free_STRING(string(sp + 1));
115 sp->type = C_NUM;
116 sp->d.dval = (mawk_num_t) idx;
117 return sp;
118 }
119
120 /* substr(s, i, n)
121 if l = length(s) then get the characters
122 from max(1,i) to min(l,n-i-1) inclusive */
123
124 mawk_cell_t *mawk_bi_substr(mawk_state_t *MAWK, mawk_cell_t *sp)
125 {
126 int n_args, len;
127 register int i, n;
128 mawk_string_t *sval; /* substr(sval->str, i, n) */
129
130 n_args = sp->type;
131 sp -= n_args;
132 if (sp->type != C_STRING)
133 mawk_cast1_to_str(MAWK, sp);
134 /* don't use < C_STRING shortcut */
135 sval = string(sp);
136
137 if ((len = sval->len) == 0) { /* substr on null string */
138 if (n_args == 3) {
139 mawk_cell_destroy(MAWK, sp + 2);
140 }
141 mawk_cell_destroy(MAWK, sp + 1);
142 return sp;
143 }
144
145 if (n_args == 2) {
146 n = MAX__INT;
147 if (sp[1].type != C_NUM)
148 mawk_cast1_to_num(MAWK, sp + 1);
149 }
150 else {
151 if (TEST2(sp + 1) != TWO_NUMS)
152 mawk_cast2_to_num(MAWK, sp + 1);
153 n = d_to_i(sp[2].d.dval);
154 }
155 i = d_to_i(sp[1].d.dval) - 1; /* i now indexes into string */
156
157 if (i < 0)
158 i = 0;
159
160 if (n > len - i)
161 n = len - i;
162
163 if (n <= 0) { /* the null string */
164 sp->ptr = (PTR) & (MAWK->null_str);
165 (MAWK->null_str.ref_cnt)++;
166 }
167 else { /* got something */
168
169 sp->ptr = (PTR) mawk_new_STRING0(MAWK, n);
170 memcpy(string(sp)->str, sval->str + i, n);
171 }
172
173 free_STRING(sval);
174 return sp;
175 }
176
177 /*
178 match(s,r)
179 sp[0] holds r, sp[-1] holds s
180 */
181
182 mawk_cell_t *mawk_bi_match(mawk_state_t *MAWK, mawk_cell_t *sp)
183 {
184 char *p;
185 unsigned length;
186
187 if (sp->type != C_RE)
188 mawk_cast_to_RE(MAWK, sp);
189 if ((--sp)->type < C_STRING)
190 mawk_cast1_to_str(MAWK, sp);
191
192 mawk_cell_destroy(MAWK, RSTART);
193 mawk_cell_destroy(MAWK, RLENGTH);
194 RSTART->type = C_NUM;
195 RLENGTH->type = C_NUM;
196
197 p = mawk_REmatch(MAWK, string(sp)->str, (sp + 1)->ptr, &length, 0);
198
199 if (p) {
200 sp->d.dval = (mawk_num_t) (p - string(sp)->str + 1);
201 RLENGTH->d.dval = (mawk_num_t) length;
202 }
203 else {
204 sp->d.dval = MAWK_NUM_ZERO;
205 RLENGTH->d.dval = -MAWK_NUM_ONE; /* posix */
206 }
207
208 free_STRING(string(sp));
209 sp->type = C_NUM;
210
211 RSTART->d.dval = sp->d.dval;
212
213 return sp;
214 }
215
216 mawk_cell_t *mawk_bi_toupper(mawk_state_t *MAWK, mawk_cell_t *sp)
217 {
218 mawk_string_t *old;
219 register char *p, *q;
220
221 if (sp->type != C_STRING)
222 mawk_cast1_to_str(MAWK, sp);
223 old = string(sp);
224 sp->ptr = (PTR) mawk_new_STRING0(MAWK, old->len);
225
226 q = string(sp)->str;
227 p = old->str;
228 while (*p) {
229 *q = *p++;
230 if (*q >= 'a' && *q <= 'z')
231 *q += 'A' - 'a';
232 q++;
233 }
234 free_STRING(old);
235 return sp;
236 }
237
238 mawk_cell_t *mawk_bi_tolower(mawk_state_t *MAWK, mawk_cell_t *sp)
239 {
240 mawk_string_t *old;
241 register char *p, *q;
242
243 if (sp->type != C_STRING)
244 mawk_cast1_to_str(MAWK, sp);
245 old = string(sp);
246 sp->ptr = (PTR) mawk_new_STRING0(MAWK, old->len);
247
248 q = string(sp)->str;
249 p = old->str;
250 while (*p) {
251 *q = *p++;
252 if (*q >= 'A' && *q <= 'Z')
253 *q += 'a' - 'A';
254 q++;
255 }
256 free_STRING(old);
257 return sp;
258 }
259
260
261 /************************************************
262 arithemetic builtins
263 ************************************************/
264
265 static void fplib_err(mawk_state_t *MAWK, char *fname, mawk_num_t val, char *error)
266 {
267 mawk_rt_error(MAWK, "%s(" NUM_FMT ") : %s", fname, val, error);
268 }
269
270 #ifndef MAWK_NO_FLOAT
271 mawk_cell_t *mawk_bi_sin(mawk_state_t *MAWK, mawk_cell_t *sp)
272 {
273 #if ! STDC_MATHERR
274 if (sp->type != C_NUM)
275 mawk_cast1_to_num(MAWK, sp);
276 sp->d.dval = sin(sp->d.dval);
277 return sp;
278 #else
279 mawk_num_t x;
280
281 errno = 0;
282 if (sp->type != C_NUM)
283 mawk_cast1_to_num(MAWK, sp);
284 x = sp->d.dval;
285 sp->d.dval = sin(sp->d.dval);
286 if (errno)
287 fplib_err(MAWK, "sin", x, "loss of precision");
288 return sp;
289 #endif
290 }
291
292 mawk_cell_t *mawk_bi_cos(mawk_state_t *MAWK, mawk_cell_t *sp)
293 {
294 #if ! STDC_MATHERR
295 if (sp->type != C_NUM)
296 mawk_cast1_to_num(MAWK, sp);
297 sp->d.dval = cos(sp->d.dval);
298 return sp;
299 #else
300 mawk_num_t x;
301
302 errno = 0;
303 if (sp->type != C_NUM)
304 mawk_cast1_to_num(MAWK, sp);
305 x = sp->d.dval;
306 sp->d.dval = cos(sp->d.dval);
307 if (errno)
308 fplib_err(MAWK, "cos", x, "loss of precision");
309 return sp;
310 #endif
311 }
312
313 mawk_cell_t *mawk_bi_atan2(mawk_state_t *MAWK, mawk_cell_t *sp)
314 {
315 #if ! STDC_MATHERR
316 sp--;
317 if (TEST2(sp) != TWO_NUMS)
318 mawk_cast2_to_num(MAWK, sp);
319 sp->d.dval = atan2(sp->d.dval, (sp + 1)->d.dval);
320 return sp;
321 #else
322
323 errno = 0;
324 sp--;
325 if (TEST2(sp) != TWO_NUMS)
326 mawk_cast2_to_num(MAWK, sp);
327 sp->d.dval = atan2(sp->d.dval, (sp + 1)->d.dval);
328 if (errno)
329 mawk_rt_error(MAWK, "atan2(0,0) : domain error");
330 return sp;
331 #endif
332 }
333
334 mawk_cell_t *mawk_bi_log(mawk_state_t *MAWK, mawk_cell_t *sp)
335 {
336 mawk_num_t x;
337
338 errno = 0;
339 if (sp->type != C_NUM)
340 mawk_cast1_to_num(MAWK, sp);
341 x = sp->d.dval;
342 PM_BEGIN
343 sp->d.dval = P_log(sp->d.dval);
344 PM_ERROR
345 /* temporary workaround until the final nan support is there */
346 sp->d.dval = P_nan();
347 /* fplib_err(MAWK, "log", x, "domain error");*/
348 PM_END;
349 return sp;
350 }
351
352 mawk_cell_t *mawk_bi_exp(mawk_state_t *MAWK, mawk_cell_t *sp)
353 {
354 #if ! STDC_MATHERR
355 if (sp->type != C_NUM)
356 mawk_cast1_to_num(MAWK, sp);
357 sp->d.dval = exp(sp->d.dval);
358 return sp;
359 #else
360 mawk_num_t x;
361
362 errno = 0;
363 if (sp->type != C_NUM)
364 mawk_cast1_to_num(MAWK, sp);
365 x = sp->d.dval;
366 sp->d.dval = exp(sp->d.dval);
367 if (errno && sp->d.dval)
368 fplib_err(MAWK, "exp", x, "mawk_overflow");
369 /* on underflow sp->d.dval==0, ignore */
370 return sp;
371 #endif
372 }
373 #endif
374
375 mawk_cell_t *mawk_bi_int(mawk_state_t *MAWK, mawk_cell_t *sp)
376 {
377 if (sp->type != C_NUM)
378 mawk_cast1_to_num(MAWK, sp);
379 sp->d.dval = mawk_num_int(sp->d.dval);
380 return sp;
381 }
382
383 mawk_cell_t *mawk_bi_sqrt(mawk_state_t *MAWK, mawk_cell_t *sp)
384 {
385 mawk_num_t x;
386
387 if (sp->type != C_NUM)
388 mawk_cast1_to_num(MAWK, sp);
389
390 x = sp->d.dval;
391
392 if (x < 0) {
393 sp->d.dval = P_nan();
394 return sp;
395 }
396
397 #if ! STDC_MATHERR
398 sp->d.dval = mawk_num_sqrt(x);
399 return sp;
400 #else
401 errno = 0;
402 sp->d.dval = mawk_num_sqrt(x);
403 if (errno)
404 fplib_err(MAWK, "sqrt", x, "domain error");
405 return sp;
406 #endif
407 }
408
409 #ifndef NO_TIME_H
410 #include <time.h>
411 #else
412 #include <sys/types.h>
413 #endif
414
415
416 /* For portability, we'll use our own random number generator , taken
417 from: Park, SK and Miller KW, "Random Number Generators:
418 Good Ones are Hard to Find", CACM, 31, 1192-1201, 1988.
419 */
420
421
422 #define M 0x7fffffff /* 2^31-1 */
423 #define MX 0xffffffff
424 #define A 16807
425 #define Q 127773 /* M/A */
426 #define R 2836 /* M%A */
427
428 #if M == MAX__LONG
429 #define crank(s) s = A * (s % Q) - R * (s / Q) ;\
430 if ( s <= 0 ) s += M
431 #else
432 /* 64 bit longs */
433 #define crank(s) { unsigned long t = s ;\
434 t = (A * (t % Q) - R * (t / Q)) & MX ;\
435 if ( t >= M ) t = (t+M)&M ;\
436 s = t ;\
437 }
438 #endif
439
440
441 mawk_cell_t *mawk_bi_srand(mawk_state_t *MAWK, mawk_cell_t *sp)
442 {
443 mawk_cell_t c;
444
445 if (sp->type == 0) { /* seed off clock */
446 mawk_cellcpy(MAWK, sp, &MAWK->cseed);
447 mawk_cell_destroy(MAWK, &MAWK->cseed);
448 MAWK->cseed.type = C_NUM;
449 MAWK->cseed.d.dval = (mawk_num_t) time((time_t *) 0);
450 }
451 else { /* user seed */
452
453 sp--;
454 /* swap cseed and *sp ; don't need to adjust ref_cnts */
455 c = *sp;
456 *sp = MAWK->cseed;
457 MAWK->cseed = c;
458 }
459
460 /* The old seed is now in *sp ; move the value in cseed to
461 seed in range [1,M) */
462
463 mawk_cellcpy(MAWK, &c, &MAWK->cseed);
464 if (c.type == C_NOINIT)
465 mawk_cast1_to_num(MAWK, &c);
466
467 MAWK->seed = c.type == C_NUM ? (d_to_i(c.d.dval) & M) % M + 1 : mawk_hash(string(&c)->str) % M + 1;
468 if (MAWK->seed == M)
469 MAWK->seed = M - 1;
470
471 mawk_cell_destroy(MAWK, &c);
472
473 /* crank it once so close seeds don't give a close
474 first result */
475 crank(MAWK->seed);
476
477 return sp;
478 }
479
480 mawk_cell_t *mawk_bi_rand(mawk_state_t *MAWK, mawk_cell_t *sp)
481 {
482 crank(MAWK->seed);
483 sp++;
484 sp->type = C_NUM;
485 sp->d.dval = (mawk_num_t) MAWK->seed / (mawk_num_t) M;
486 return sp;
487 }
488
489 #undef A
490 #undef M
491 #undef MX
492 #undef Q
493 #undef R
494 #undef crank
495
496 /*************************************************
497 miscellaneous builtins
498 close, system and getline
499 fflush
500 *************************************************/
501
502 mawk_cell_t *mawk_bi_close(mawk_state_t *MAWK, mawk_cell_t *sp)
503 {
504 int x;
505
506 if (sp->type < C_STRING)
507 mawk_cast1_to_str(MAWK, sp);
508 x = mawk_file_close(MAWK, (mawk_string_t *) sp->ptr);
509 free_STRING(string(sp));
510 sp->type = C_NUM;
511 sp->d.dval = (mawk_num_t) x;
512 return sp;
513 }
514
515
516 mawk_cell_t *mawk_bi_fflush(mawk_state_t *MAWK, mawk_cell_t *sp)
517 {
518 int ret = 0;
519
520 if (sp->type == 0)
521 mawk_vio_flush(MAWK, MAWK->fnode_stdout->vf);
522 else {
523 sp--;
524 if (sp->type < C_STRING)
525 mawk_cast1_to_str(MAWK, sp);
526 ret = mawk_file_flush(MAWK, string(sp));
527 free_STRING(string(sp));
528 }
529
530 sp->type = C_NUM;
531 sp->d.dval = (mawk_num_t) ret;
532 return sp;
533 }
534
535 #ifndef MAWK_NO_FORK
536 mawk_cell_t *mawk_bi_system(mawk_state_t *MAWK, mawk_cell_t *sp)
537 {
538 int pid;
539 unsigned ret_val;
540
541 if (sp->type < C_STRING)
542 mawk_cast1_to_str(MAWK, sp);
543
544 mawk_flush_all_output(MAWK);
545 switch (pid = fork()) {
546 case -1: /* fork failed */
547
548 mawk_errmsg(MAWK, errno, "could not create a new process");
549 ret_val = 127;
550 break;
551
552 case 0: /* the child */
553 mawk_vio_exec_shell(MAWK, string(sp)->str);
554
555 default: /* wait for the child */
556 ret_val = mawk_wait_for(MAWK, pid);
557 break;
558 }
559
560 mawk_cell_destroy(MAWK, sp);
561 sp->type = C_NUM;
562 sp->d.dval = (mawk_num_t) ret_val;
563 return sp;
564 }
565 #endif
566
567 /* getline() */
568
569 /* if type == 0 : stack is 0 , target address
570
571 if type == F_IN : stack is F_IN, expr(filename), target address
572 if type == PIPE_IN : stack is PIPE_IN, target address, expr(pipename)
573 */
574
575 mawk_cell_t *mawk_bi_getline(mawk_state_t *MAWK, mawk_cell_t *sp)
576 {
577 mawk_cell_t tc, *cp;
578 char *p;
579 unsigned len;
580 FILE_NODE *fnode = NULL;
581
582 switch (sp->type) {
583 case 0:
584 sp--;
585 if (!MAWK->main_input)
586 mawk_FINopen_main(MAWK);
587
588 p = mawk_FINgets(MAWK, MAWK->main_input, &len);
589 if (p == (void *) mawk_FIN_nomore)
590 goto nomore;
591
592 if (!p)
593 goto eof;
594
595 cp = (mawk_cell_t *) sp;
596 if (TEST2(NR) != TWO_NUMS)
597 mawk_cast2_to_num(MAWK, NR);
598 NR->d.dval += MAWK_NUM_ONE;
599 MAWK->rt_nr++;
600 FNR->d.dval += MAWK_NUM_ONE;
601 MAWK->rt_fnr++;
602 break;
603
604 case F_IN:
605 sp--;
606 if (sp->type < C_STRING)
607 mawk_cast1_to_str(MAWK, sp);
608 fnode = mawk_file_find(MAWK, sp->ptr, F_IN, 1);
609 free_STRING(string(sp));
610 sp--;
611
612 if (fnode == NULL)
613 goto open_failure;
614
615 p = mawk_FINgets(MAWK, fnode, &len);
616 if (p == (void *) mawk_FIN_nomore)
617 goto nomore;
618
619 if (!p) {
620 mawk_file_close_(MAWK, fnode);
621 goto eof;
622 }
623 cp = sp;
624 break;
625
626 case PIPE_IN:
627 sp -= 2;
628 if (sp->type < C_STRING)
629 mawk_cast1_to_str(MAWK, sp);
630 fnode = mawk_file_find(MAWK, sp->ptr, PIPE_IN, 1);
631 free_STRING(string(sp));
632
633 if (fnode == NULL)
634 goto open_failure;
635
636 p = mawk_FINgets(MAWK, fnode, &len);
637 if (p == (void *) mawk_FIN_nomore)
638 goto nomore;
639
640 if (!p) {
641 mawk_file_close_(MAWK, fnode);
642 goto eof;
643 }
644 cp = (sp + 1);
645 break;
646
647 default:
648 mawk_bozo(MAWK, "type in mawk_bi_getline");
649
650 }
651
652 /* we've read a line , store it */
653
654 if (len == 0) {
655 tc.type = C_STRING;
656 tc.ptr = (PTR) & (MAWK->null_str);
657 MAWK->null_str.ref_cnt++;
658 }
659 else {
660 tc.type = C_MBSTRN;
661 tc.ptr = (PTR) mawk_new_STRING0(MAWK, len);
662 memcpy(string(&tc)->str, p, len);
663 }
664
665 mawk_bifunct_target_assign(MAWK, cp, &tc);
666
667 mawk_cell_destroy(MAWK, &tc);
668
669 sp->d.dval = MAWK_NUM_ONE;
670 goto done;
671 open_failure:;
672 sp->d.dval = -MAWK_NUM_ONE;
673 goto done;
674 eof:;
675 sp->d.dval = MAWK_NUM_ZERO; /* fall thru to done */
676
677 done:;
678 sp->type = C_NUM;
679 return sp;
680
681 nomore:;
682 sp->type = C_REQ_NOMORE;
683 return sp;
684 }
685
686 /**********************************************
687 sub() and gsub()
688 **********************************************/
689
690 /* entry: sp[0] = address of mawk_cell_t to sub on
691 sp[-1] = substitution CELL
692 sp[-2] = regular expression to match
693 */
694
695 mawk_cell_t *mawk_bi_sub(mawk_state_t *MAWK, mawk_cell_t *sp)
696 {
697 mawk_cell_t *cp; /* pointer to the replacement target */
698 mawk_cell_t tc; /* build the new string here */
699 mawk_cell_t sc; /* copy of the target mawk_cell_t */
700 char *front, *middle, *back; /* pieces */
701 unsigned front_len, middle_len, back_len;
702
703 sp -= 2;
704 if (sp->type != C_RE)
705 mawk_cast_to_RE(MAWK, sp);
706 if (sp[1].type != C_REPL && sp[1].type != C_REPLV)
707 mawk_cast_to_REPL(MAWK, sp + 1);
708 cp = (mawk_cell_t *) (sp + 2);
709
710 /* make a copy of the target, because we won't change anything
711 including type unless the match works */
712 if (cp->type == C_ARR_REF_BT) {
713 sc.type = C_NOINIT;
714 mawk_array_find(MAWK, (mawk_array_t)cp->ptr, cp->d.idx_cell, &sc, 1);
715 }
716 else
717 mawk_cellcpy(MAWK, &sc, cp->ptr);
718
719
720 if (sc.type < C_STRING)
721 mawk_cast1_to_str(MAWK, &sc);
722 front = string(&sc)->str;
723
724 if ((middle = mawk_REmatch(MAWK, front, sp->ptr, &middle_len, 0))) {
725 front_len = middle - front;
726 back = middle + middle_len;
727 back_len = string(&sc)->len - front_len - middle_len;
728
729 if ((sp + 1)->type == C_REPLV) {
730 mawk_string_t *sval = mawk_new_STRING0(MAWK, middle_len);
731
732 memcpy(sval->str, middle, middle_len);
733 mawk_replv_to_repl(MAWK, sp + 1, sval);
734 free_STRING(sval);
735 }
736
737 tc.type = C_STRING;
738 tc.ptr = (PTR) mawk_new_STRING0(MAWK, front_len + string(sp + 1)->len + back_len);
739
740 {
741 char *p = string(&tc)->str;
742
743 if (front_len) {
744 memcpy(p, front, front_len);
745 p += front_len;
746 }
747 if (string(sp + 1)->len) {
748 memcpy(p, string(sp + 1)->str, string(sp + 1)->len);
749 p += string(sp + 1)->len;
750 }
751 if (back_len)
752 memcpy(p, back, back_len);
753 }
754
755 mawk_bifunct_target_assign(MAWK, cp, &tc);
756
757 free_STRING(string(&tc));
758 }
759
760 free_STRING(string(&sc));
761 mawk_repl_destroy(MAWK, sp + 1);
762 sp->type = C_NUM;
763 sp->d.dval = (mawk_num_t) (middle != (char *) 0 ? MAWK_NUM_ONE : MAWK_NUM_ZERO);
764 return sp;
765 }
766
767 /* recursive global subsitution
768 dealing with empty matches makes this mildly painful
769 */
770
771 static mawk_string_t *gsub(mawk_state_t *MAWK, PTR re, mawk_cell_t *repl, char *target, char *orig_target, int flag)
772 {
773 /*target -> if on, match of empty string at front is OK */
774 /* repl -> always of type REPL or REPLV, destroyed by caller */
775 /* flag -> if on, match of empty string at front is OK */
776 char *front, *middle;
777 mawk_string_t *back;
778 unsigned front_len, middle_len;
779 mawk_string_t *ret_val;
780 mawk_cell_t xrepl; /* a copy of repl so we can change repl */
781
782 if (!(middle = mawk_REmatch(MAWK, target, re, &middle_len, target != orig_target)))
783 return mawk_new_STRING(MAWK, target); /* no match */
784
785 mawk_cellcpy(MAWK, &xrepl, repl);
786
787 if (!flag && middle_len == 0 && middle == target) { /* match at front that's not allowed */
788
789 if (*target == 0) { /* target is empty string */
790 mawk_repl_destroy(MAWK, &xrepl);
791 MAWK->null_str.ref_cnt++;
792 return &(MAWK->null_str);
793 }
794 else {
795 char xbuff[2];
796
797 front_len = 0;
798 /* make new repl with target[0] */
799 mawk_repl_destroy(MAWK, repl);
800 xbuff[0] = *target++;
801 xbuff[1] = 0;
802 repl->type = C_REPL;
803 repl->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
804 back = gsub(MAWK, re, &xrepl, target, orig_target, 1);
805 }
806 }
807 else { /* a match that counts */
808
809 MAWK->repl_cnt++;
810
811 front = target;
812 front_len = middle - target;
813
814 if (*middle == 0) { /* matched back of target */
815 back = &(MAWK->null_str);
816 MAWK->null_str.ref_cnt++;
817 }
818 else
819 back = gsub(MAWK, re, &xrepl, middle + middle_len, orig_target, 0);
820
821 /* patch the &'s if needed */
822 if (repl->type == C_REPLV) {
823 mawk_string_t *sval = mawk_new_STRING0(MAWK, middle_len);
824
825 memcpy(sval->str, middle, middle_len);
826 mawk_replv_to_repl(MAWK, repl, sval);
827 free_STRING(sval);
828 }
829 }
830
831 /* put the three pieces together */
832 ret_val = mawk_new_STRING0(MAWK, front_len + string(repl)->len + back->len);
833 {
834 char *p = ret_val->str;
835
836 if (front_len) {
837 memcpy(p, front, front_len);
838 p += front_len;
839 }
840
841 if (string(repl)->len) {
842 memcpy(p, string(repl)->str, string(repl)->len);
843 p += string(repl)->len;
844 }
845 if (back->len)
846 memcpy(p, back->str, back->len);
847 }
848
849 /* cleanup, repl is freed by the caller */
850 mawk_repl_destroy(MAWK, &xrepl);
851 free_STRING(back);
852
853 return ret_val;
854 }
855
856 /* set up for call to gsub() */
857 mawk_cell_t *mawk_bi_gsub(mawk_state_t *MAWK, mawk_cell_t *sp)
858 {
859 mawk_cell_t *cp; /* pts at the replacement target */
860 mawk_cell_t sc; /* copy of replacement target */
861 mawk_cell_t tc; /* build the result here */
862
863 sp -= 2;
864 if (sp->type != C_RE)
865 mawk_cast_to_RE(MAWK, sp);
866 if ((sp + 1)->type != C_REPL && (sp + 1)->type != C_REPLV)
867 mawk_cast_to_REPL(MAWK, sp + 1);
868
869 cp = (mawk_cell_t *) (sp + 2);
870 if (cp->type == C_ARR_REF_BT) {
871 sc.type = C_NOINIT;
872 mawk_array_find(MAWK, (mawk_array_t)cp->ptr, cp->d.idx_cell, &sc, 1);
873 }
874 else
875 mawk_cellcpy(MAWK, &sc, cp->ptr);
876
877 if (sc.type < C_STRING)
878 mawk_cast1_to_str(MAWK, &sc);
879
880 MAWK->repl_cnt = 0;
881 tc.ptr = (PTR) gsub(MAWK, sp->ptr, sp + 1, string(&sc)->str, string(&sc)->str, 1);
882
883 if (MAWK->repl_cnt) {
884 tc.type = C_STRING;
885 mawk_bifunct_target_assign(MAWK, cp, &tc);
886 }
887
888 /* cleanup */
889 free_STRING(string(&sc));
890 free_STRING(string(&tc));
891 mawk_repl_destroy(MAWK, sp + 1);
892
893 sp->type = C_NUM;
894 sp->d.dval = (mawk_num_t) MAWK->repl_cnt;
895 return sp;
896 }
897
898
899 mawk_cell_t *mawk_bi_call(mawk_state_t *MAWK, mawk_cell_t *sp)
900 {
901 int i, numargs;
902 SYMTAB *fs;
903 const char *fn;
904 /* mawk_cell_t *ret;*/
905
906 numargs = sp->type;
907 sp -= numargs;
908 if (sp->type < C_STRING)
909 mawk_cast1_to_str(MAWK, sp);
910 fn = string(sp)->str;
911
912 fs = mawk_find(MAWK, fn, 0);
913
914 if ((fs == NULL) || (fs->type != ST_FUNCT)) {
915 /* does not exist or not a function */
916 if (fs == NULL)
917 mawk_set_errno(MAWK, "1 object does not exist");
918 else
919 mawk_set_errno(MAWK, "2 object is not a function");
920
921 #warning this should be some common code in execute.c?
922 for (i = 0; i < numargs; i++) {
923 mawk_cell_destroy(MAWK, &sp[i]);
924 sp[i].type = C_NOINIT;
925 sp[i].d.dval = MAWK_NUM_ZERO;
926 }
927 sp[numargs].type = C_NOINIT;
928 sp[numargs].d.dval = MAWK_NUM_ZERO;
929
930 return sp;
931 }
932
933 mawk_set_errno(MAWK, "");
934 /* ret = mawk_call(MAWK, sp + numargs - 1, fs->stval.fbp, numargs - 1);*/
935
936 /* shift args down to replace first arg (function name) with the first
937 actual arg passed to the function */
938 for (i = 0; i < numargs; i++)
939 sp[i] = sp[i+1];
940 sp += numargs-1;
941
942 /* perform the call */
943 sp->type = C_NUM;
944 sp->d.dval = numargs - 1;
945 inc_sp();
946 sp->type = C_REQ_CALL;
947 sp->ptr = fs->stval.fbp;
948 return sp;
949 }
950
951 mawk_cell_t *mawk_bi_acall(mawk_state_t *MAWK, mawk_cell_t *sp)
952 {
953 int numargs;
954 SYMTAB *fs, *fa;
955 const char *fn;
956 mawk_cell_t *ret, idx;
957
958 numargs = 1;
959 sp -= numargs;
960
961 if (sp->type < C_STRING)
962 mawk_cast1_to_str(MAWK, sp);
963 fn = string(sp)->str;
964
965 fs = mawk_find(MAWK, fn, 0);
966
967 if (fs == NULL) {
968 /* does not exist */
969 mawk_set_errno(MAWK, "1 object does not exist");
970 sp++;
971 goto error;
972 }
973
974 sp++;
975 if (sp->type < C_STRING)
976 mawk_cast1_to_str(MAWK, sp);
977
978 fa = mawk_find(MAWK, string(sp)->str, 0);
979 if (fa == NULL) {
980 mawk_set_errno(MAWK, "3 argument array does not exist");
981 goto error;
982 }
983
984 if (fa->type != ST_ARRAY) {
985 mawk_set_errno(MAWK, "4 argument array is not an array");
986 goto error;
987 }
988
989 sp -= 2;
990 for (numargs = 1;; numargs++) {
991 inc_sp();
992 idx.type = C_NUM;
993 idx.d.dval = numargs;
994 if (mawk_array_find(MAWK, fa->stval.array, &idx, sp, 0) == 0)
995 break;
996 }
997
998 if (fs->type == ST_FUNCT) {
999 /* perform the call */
1000 mawk_set_errno(MAWK, "");
1001 inc_sp();
1002 sp->type = C_NUM;
1003 sp->d.dval = numargs;
1004 inc_sp();
1005 sp->type = C_REQ_CALL;
1006 sp->ptr = fs->stval.fbp;
1007 return sp;
1008 }
1009 else {
1010 mawk_set_errno(MAWK, "5 object is a function");
1011 idx.type = C_NOINIT;
1012 idx.d.dval = MAWK_NUM_ZERO;
1013 ret = &idx;
1014 }
1015
1016 sp -= numargs;
1017 sp--;
1018 #warning TODO: cell destroy all the allocated but unused args?
1019 return sp;
1020
1021 error:;
1022 mawk_cell_destroy(MAWK, sp);
1023 sp--;
1024 sp->type = C_NOINIT;
1025 return sp;
1026 }
1027
1028 mawk_cell_t *mawk_bi_valueof(mawk_state_t *MAWK, mawk_cell_t *sp)
1029 {
1030 int numargs;
1031 SYMTAB *fs;
1032 mawk_cell_t *ret, *idx;
1033
1034 numargs = sp->type;
1035 sp -= numargs;
1036
1037 if (sp->type < C_STRING)
1038 mawk_cast1_to_str(MAWK, sp);
1039
1040 fs = mawk_find(MAWK, string(sp)->str, 0);
1041
1042 if (fs == NULL) {
1043 /* does not exist */
1044 mawk_set_errno(MAWK, "1 object does not exist");
1045 goto error;
1046 }
1047
1048 if (fs->type == ST_FUNCT) {
1049 mawk_set_errno(MAWK, "5 object is a function");
1050 goto error;
1051 }
1052
1053 if (numargs > 1) {
1054 if (fs->type == ST_ARRAY) {
1055 idx = sp + 1;
1056 mawk_array_find(MAWK, fs->stval.array, idx, sp, 0);
1057 goto has_set_sp;
1058 }
1059 else {
1060 mawk_set_errno(MAWK, "6 object is not an array, can not index it");
1061 goto error;
1062 }
1063 }
1064 else {
1065 if (fs->type == ST_ARRAY) {
1066 mawk_set_errno(MAWK, "7 object is an array, need to index it");
1067 goto error;
1068 }
1069 ret = fs->stval.cp;
1070 }
1071
1072 if ((ret != NULL) && ((fs->type == ST_VAR) || (fs->type == ST_KEYWORD))) {
1073 mawk_cell_destroy(MAWK, sp);
1074 *sp = *ret;
1075 has_set_sp:;
1076 mawk_set_errno(MAWK, "");
1077 return sp;
1078 }
1079
1080 if (ret != NULL)
1081 mawk_set_errno(MAWK, "8 object is not a variable (and not a function either)");
1082
1083 error:;
1084 mawk_cell_destroy(MAWK, sp);
1085 sp->type = C_NOINIT;
1086 return sp;
1087 }
1088
1089 mawk_cell_t *mawk_bi_isnan(mawk_state_t *MAWK, mawk_cell_t *sp)
1090 {
1091 if (sp->type != C_NUM)
1092 mawk_cast1_to_num(MAWK, sp);
1093
1094 sp->type = C_NUM;
1095 sp->d.dval = P_isnan(sp->d.dval);
1096
1097 return sp--;
1098 }
0
1 /********************************************
2 bi_funct.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef BI_FUNCT_H
17 #define BI_FUNCT_H 1
18
19 #include <libmawk/symtype.h>
20
21 extern const BI_REC mawk_bi_funct[]; /* read-only */
22
23 /* builtin string functions */
24 mawk_cell_t *mawk_bi_print(mawk_state_t *, mawk_cell_t *);
25 mawk_cell_t *mawk_bi_printf(mawk_state_t *, mawk_cell_t *);
26 mawk_cell_t *mawk_bi_length(mawk_state_t *, mawk_cell_t *);
27 mawk_cell_t *mawk_bi_index(mawk_state_t *, mawk_cell_t *);
28 mawk_cell_t *mawk_bi_substr(mawk_state_t *, mawk_cell_t *);
29 mawk_cell_t *mawk_bi_sprintf(mawk_state_t *, mawk_cell_t *);
30 mawk_cell_t *mawk_bi_split(mawk_state_t *, mawk_cell_t *);
31 mawk_cell_t *mawk_bi_match(mawk_state_t *, mawk_cell_t *);
32 mawk_cell_t *mawk_bi_getline(mawk_state_t *, mawk_cell_t *);
33 mawk_cell_t *mawk_bi_sub(mawk_state_t *, mawk_cell_t *);
34 mawk_cell_t *mawk_bi_gsub(mawk_state_t *, mawk_cell_t *);
35 mawk_cell_t *mawk_bi_toupper(mawk_state_t *, mawk_cell_t *);
36 mawk_cell_t *mawk_bi_tolower(mawk_state_t *, mawk_cell_t *);
37
38 /* builtin arith functions */
39 mawk_cell_t *mawk_bi_sin(mawk_state_t *, mawk_cell_t *);
40 mawk_cell_t *mawk_bi_cos(mawk_state_t *, mawk_cell_t *);
41 mawk_cell_t *mawk_bi_atan2(mawk_state_t *, mawk_cell_t *);
42 mawk_cell_t *mawk_bi_log(mawk_state_t *, mawk_cell_t *);
43 mawk_cell_t *mawk_bi_exp(mawk_state_t *, mawk_cell_t *);
44 mawk_cell_t *mawk_bi_int(mawk_state_t *, mawk_cell_t *);
45 mawk_cell_t *mawk_bi_sqrt(mawk_state_t *, mawk_cell_t *);
46 mawk_cell_t *mawk_bi_srand(mawk_state_t *, mawk_cell_t *);
47 mawk_cell_t *mawk_bi_rand(mawk_state_t *, mawk_cell_t *);
48
49 /* other builtins */
50 mawk_cell_t *mawk_bi_close(mawk_state_t *, mawk_cell_t *);
51 mawk_cell_t *mawk_bi_system(mawk_state_t *, mawk_cell_t *);
52 mawk_cell_t *mawk_bi_fflush(mawk_state_t *, mawk_cell_t *);
53
54 /* libmawk extensions */
55 mawk_cell_t *mawk_bi_call(mawk_state_t *, mawk_cell_t *);
56 mawk_cell_t *mawk_bi_acall(mawk_state_t *, mawk_cell_t *);
57 mawk_cell_t *mawk_bi_valueof(mawk_state_t *, mawk_cell_t *);
58 mawk_cell_t *mawk_bi_isnan(mawk_state_t *, mawk_cell_t *);
59
60 #endif /* BI_FUNCT_H */
0
1 /********************************************
2 bi_funct_common.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include "mawk.h"
16 #include "bi_funct.h"
17 #include "bi_vars.h"
18
19
20 /* global for the disassembler */
21 BI_REC const mawk_bi_funct[] = { /* info to load builtins */
22 {"length", mawk_bi_length, 0, 1}, /* special must come first */
23 {"index", mawk_bi_index, 2, 2},
24 {"substr", mawk_bi_substr, 2, 3},
25 {"sprintf", mawk_bi_sprintf, 1, 255},
26 #ifndef MAWK_NO_FLOAT
27 {"sin", mawk_bi_sin, 1, 1},
28 {"cos", mawk_bi_cos, 1, 1},
29 {"atan2", mawk_bi_atan2, 2, 2},
30 {"exp", mawk_bi_exp, 1, 1},
31 {"log", mawk_bi_log, 1, 1},
32 #endif
33 {"int", mawk_bi_int, 1, 1},
34 {"sqrt", mawk_bi_sqrt, 1, 1},
35 {"rand", mawk_bi_rand, 0, 0},
36 {"srand", mawk_bi_srand, 0, 1},
37 {"close", mawk_bi_close, 1, 1},
38 #ifndef MAWK_NO_FORK
39 {"system", mawk_bi_system, 1, 1},
40 #endif
41 {"toupper", mawk_bi_toupper, 1, 1},
42 {"tolower", mawk_bi_tolower, 1, 1},
43 {"fflush", mawk_bi_fflush, 0, 1},
44 {"call", mawk_bi_call, 1, 255},
45 {"acall", mawk_bi_acall, 2, 2},
46 {"valueof", mawk_bi_valueof, 1, 2},
47 {"isnan", mawk_bi_isnan, 1, 1},
48 {(char *) 0, (PF_CP) 0, 0, 0}
49 };
50
51
52 /* load built-in functions in symbol table */
53 void mawk_bi_funct_init(mawk_state_t *MAWK)
54 {
55 const register BI_REC *p;
56 register SYMTAB *stp;
57
58 /* length is special (posix mawk_bozo) */
59 stp = mawk_insert(MAWK, mawk_bi_funct->name);
60 stp->type = ST_LENGTH;
61 stp->stval.bip = mawk_bi_funct;
62
63 for (p = mawk_bi_funct + 1; p->name; p++) {
64 stp = mawk_insert(MAWK, p->name);
65 stp->type = ST_BUILTIN;
66 stp->stval.bip = p;
67 }
68
69 /* seed rand() off the clock */
70 {
71 mawk_cell_t c;
72
73 c.type = 0;
74 mawk_bi_srand(MAWK, &c);
75 }
76
77 }
78
79 #ifdef MAWK_MEM_PEDANTIC
80 void mawk_bi_funct_uninit(mawk_state_t *MAWK)
81 {
82 const register BI_REC *p;
83 mawk_delete(MAWK, mawk_bi_funct->name, 0);
84
85 for (p = mawk_bi_funct + 1; p->name; p++)
86 mawk_delete(MAWK, p->name, 0);
87 }
88 #endif
0 /********************************************
1 bi_funct.c
2
3 libmawk changes (C) 2009-2013, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991, Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14 #include "mawk.h"
15 #include "bi_funct.h"
16 #include "bi_vars.h"
17
18
19 mawk_cell_t *mawk_bi_length(mawk_state_t *MAWK, register mawk_cell_t *sp)
20 {
21 abort();
22 }
23
24 char *mawk_str_str(register char *target, char *key, unsigned key_len)
25 {
26 abort();
27 }
28
29
30 mawk_cell_t *mawk_bi_index(mawk_state_t *MAWK, register mawk_cell_t *sp)
31 {
32 abort();
33 }
34
35 mawk_cell_t *mawk_bi_substr(mawk_state_t *MAWK, mawk_cell_t *sp)
36 {
37 abort();
38 }
39
40 mawk_cell_t *mawk_bi_match(mawk_state_t *MAWK, mawk_cell_t *sp)
41 {
42 abort();
43 }
44
45 mawk_cell_t *mawk_bi_toupper(mawk_state_t *MAWK, mawk_cell_t *sp)
46 {
47 abort();
48 }
49
50 mawk_cell_t *mawk_bi_tolower(mawk_state_t *MAWK, mawk_cell_t *sp)
51 {
52 abort();
53 }
54
55 #ifndef MAWK_NO_FLOAT
56 mawk_cell_t *mawk_bi_sin(mawk_state_t *MAWK, mawk_cell_t *sp)
57 {
58 abort();
59 }
60
61 mawk_cell_t *mawk_bi_cos(mawk_state_t *MAWK, mawk_cell_t *sp)
62 {
63 abort();
64 }
65
66 mawk_cell_t *mawk_bi_atan2(mawk_state_t *MAWK, mawk_cell_t *sp)
67 {
68 abort();
69 }
70
71 mawk_cell_t *mawk_bi_log(mawk_state_t *MAWK, mawk_cell_t *sp)
72 {
73 abort();
74 }
75
76 mawk_cell_t *mawk_bi_exp(mawk_state_t *MAWK, mawk_cell_t *sp)
77 {
78 abort();
79 }
80 #endif
81
82 mawk_cell_t *mawk_bi_int(mawk_state_t *MAWK, mawk_cell_t *sp)
83 {
84 abort();
85 }
86
87 mawk_cell_t *mawk_bi_sqrt(mawk_state_t *MAWK, mawk_cell_t *sp)
88 {
89 abort();
90 }
91
92
93 mawk_cell_t *mawk_bi_srand(mawk_state_t *MAWK, mawk_cell_t *sp)
94 {
95 /* called from init */
96 return NULL;
97 }
98
99 mawk_cell_t *mawk_bi_rand(mawk_state_t *MAWK, mawk_cell_t *sp)
100 {
101 abort();
102 }
103
104 mawk_cell_t *mawk_bi_close(mawk_state_t *MAWK, mawk_cell_t *sp)
105 {
106 abort();
107 }
108
109
110 mawk_cell_t *mawk_bi_fflush(mawk_state_t *MAWK, mawk_cell_t *sp)
111 {
112 abort();
113 }
114
115 mawk_cell_t *mawk_bi_system(mawk_state_t *MAWK, mawk_cell_t *sp)
116 {
117 abort();
118 }
119
120
121 mawk_cell_t *mawk_bi_getline(mawk_state_t *MAWK, mawk_cell_t *sp)
122 {
123 abort();
124 }
125
126
127 mawk_cell_t *mawk_bi_sub(mawk_state_t *MAWK, mawk_cell_t *sp)
128 {
129 abort();
130 }
131
132 mawk_cell_t *mawk_bi_gsub(mawk_state_t *MAWK, mawk_cell_t *sp)
133 {
134 abort();
135 }
136
137
138 mawk_cell_t *mawk_bi_call(mawk_state_t *MAWK, mawk_cell_t *sp)
139 {
140 abort();
141 }
142
143 mawk_cell_t *mawk_bi_acall(mawk_state_t *MAWK, mawk_cell_t *sp)
144 {
145 abort();
146 }
147
148 mawk_cell_t *mawk_bi_valueof(mawk_state_t *MAWK, mawk_cell_t *sp)
149 {
150 abort();
151 }
152
153 mawk_cell_t *mawk_bi_split(mawk_state_t *MAWK, register mawk_cell_t *sp)
154 {
155 abort();
156 }
157
158 mawk_cell_t *mawk_bi_isnan(mawk_state_t *MAWK, register mawk_cell_t *sp)
159 {
160 abort();
161 }
162
0
1 /********************************************
2 bi_vars.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include "mawk.h"
16 #include "symtype.h"
17 #include "bi_vars.h"
18 #include "field.h"
19 #include "init.h"
20 #include "memory.h"
21 #include "num.h"
22 #include "cell.h"
23 #include "array_environ.h"
24
25 /* the order here must match the order in bi_vars.h */
26
27 static const char *bi_var_names[NUM_BI_VAR] = {
28 "NR",
29 "FNR",
30 "ARGC",
31 "FILENAME",
32 "OFS",
33 "ORS",
34 "RLENGTH",
35 "RSTART",
36 "SUBSEP",
37 "ERRNO",
38 "LIBPATH",
39 };
40
41 /* mawk_insert the builtin vars in the mawk_hash table */
42 void mawk_bi_vars_init(mawk_state_t * MAWK)
43 {
44 register int i;
45 register SYMTAB *s;
46
47
48 for (i = 0; i < NUM_BI_VAR; i++) {
49 s = mawk_insert(MAWK, bi_var_names[i]);
50 s->type = i <= 1 ? ST_NR : ST_VAR;
51 s->stval.cp = MAWK->bi_vars + i;
52 /* MAWK->bi_vars[i].type = 0 which is C_NOINIT */
53 }
54
55 mawk_environ_init(MAWK);
56
57 /* set defaults */
58
59 FILENAME->type = C_STRING;
60 FILENAME->ptr = (PTR) mawk_new_STRING(MAWK, "");
61
62 OFS->type = C_STRING;
63 OFS->ptr = (PTR) mawk_new_STRING(MAWK, " ");
64
65 ORS->type = C_STRING;
66 ORS->ptr = (PTR) mawk_new_STRING(MAWK, "\n");
67
68 SUBSEP->type = C_STRING;
69 SUBSEP->ptr = (PTR) mawk_new_STRING(MAWK, "\034");
70
71 NR->type = FNR->type = C_NUM;
72 /* dval is already 0.0 */
73
74 LIBPATH->type = C_STRING;
75 LIBPATH->ptr = (PTR) mawk_new_STRING(MAWK, ";~/.libmawk;/usr/local/lib/libmawk;/usr/lib/libmawk");
76
77 }
78
79 #ifdef MAWK_MEM_PEDANTIC
80 void mawk_bi_vars_uninit(mawk_state_t * MAWK)
81 {
82 int i;
83
84 /* these ones should be cell-destroyed */
85 mawk_delete(MAWK, "FILENAME", 1);
86 mawk_delete(MAWK, "OFS", 1);
87 mawk_delete(MAWK, "ORS", 1);
88 mawk_delete(MAWK, "SUBSEP", 1);
89 mawk_delete(MAWK, "LIBPATH", 1);
90
91 for (i = 0; i < NUM_BI_VAR; i++)
92 mawk_delete(MAWK, bi_var_names[i], 0);
93
94 /* this was not initialized as a bi_var, but it really is after initialization */
95 mawk_delete(MAWK, "ARGV", 1);
96
97 mawk_environ_uninit(MAWK);
98 }
99 #endif
0
1 /********************************************
2 bi_vars.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef BI_VARS_H
17 #define BI_VARS_H 1
18
19
20 /* builtin variables NF, RS, FS, OFMT are stored
21 internally in field[], so side effects of assignment can
22 be handled
23 */
24
25 /* NR and FNR must be next to each other */
26 #define NR (MAWK->bi_vars+0)
27 #define FNR (MAWK->bi_vars+1)
28 #define ARGC (MAWK->bi_vars+2)
29 #define FILENAME (MAWK->bi_vars+3)
30 #define OFS (MAWK->bi_vars+4)
31 #define ORS (MAWK->bi_vars+5)
32 #define RLENGTH (MAWK->bi_vars+6)
33 #define RSTART (MAWK->bi_vars+7)
34 #define SUBSEP (MAWK->bi_vars+8)
35 #define ERRNO (MAWK->bi_vars+9)
36 #define LIBPATH (MAWK->bi_vars+10)
37
38 #define NUM_BI_VAR 11
39
40 #ifdef MAWK_MEM_PEDANTIC
41 void mawk_bi_vars_uninit(mawk_state_t * m);
42 #endif
43
44 #endif
0
1 /********************************************
2 cast.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include <stdio.h>
16 #include <string.h>
17 #include "mawk.h"
18 #include "field.h"
19 #include "memory.h"
20 #include "scan.h"
21 #include "repl.h"
22 #include "num.h"
23 #include "cell.h"
24
25
26 void mawk_cast1_to_num(mawk_state_t *MAWK, register mawk_cell_t *cp)
27 {
28 switch (cp->type) {
29 case C_NOINIT:
30 cp->d.dval = MAWK_NUM_ZERO;
31 break;
32
33 case C_NUM:
34 return;
35
36 case C_MBSTRN:
37 case C_STRING:
38 {
39 register mawk_string_t *s = (mawk_string_t *) cp->ptr;
40
41 #if FPE_TRAPS_ON /* look for mawk_overflow error */
42 errno = 0;
43 cp->d.dval = strtonum(s->str, (char **) 0);
44 if (errno && cp->d.dval != MAWK_NUM_ZERO) /* ignore underflow */
45 mawk_rt_error("mawk_overflow converting %s to number", s->str);
46 #else
47 cp->d.dval = strtonum(s->str, (char **) 0);
48 #endif
49 free_STRING(s);
50 }
51 break;
52
53 case C_STRNUM:
54 /* don't need to convert, but do need to free the mawk_string_t part */
55 free_STRING(string(cp));
56 break;
57
58
59 default:
60 mawk_bozo(MAWK, "mawk_cast on bad type");
61 }
62 cp->type = C_NUM;
63 }
64
65 void mawk_cast2_to_num(mawk_state_t *MAWK, register mawk_cell_t *cp)
66 {
67 register mawk_string_t *s;
68
69 switch (cp->type) {
70 case C_NOINIT:
71 cp->d.dval = MAWK_NUM_ZERO;
72 break;
73
74 case C_NUM:
75 goto two;
76 case C_STRNUM:
77 free_STRING(string(cp));
78 break;
79
80 case C_MBSTRN:
81 case C_STRING:
82 s = (mawk_string_t *) cp->ptr;
83
84 #if FPE_TRAPS_ON /* look for mawk_overflow error */
85 errno = 0;
86 cp->d.dval = strtonum(s->str, (char **) 0);
87 if (errno && cp->d.dval != MAWK_NUM_ZERO) /* ignore underflow */
88 mawk_rt_error("mawk_overflow converting %s to number", s->str);
89 #else
90 cp->d.dval = strtonum(s->str, (char **) 0);
91 #endif
92 free_STRING(s);
93 break;
94
95 default:
96 mawk_bozo(MAWK, "mawk_cast on bad type");
97 }
98 cp->type = C_NUM;
99
100 two:cp++;
101
102 switch (cp->type) {
103 case C_NOINIT:
104 cp->d.dval = MAWK_NUM_ZERO;
105 break;
106
107 case C_NUM:
108 return;
109 case C_STRNUM:
110 free_STRING(string(cp));
111 break;
112
113 case C_MBSTRN:
114 case C_STRING:
115 s = (mawk_string_t *) cp->ptr;
116
117 #if FPE_TRAPS_ON /* look for mawk_overflow error */
118 errno = 0;
119 cp->d.dval = strtonum(s->str, (char **) 0);
120 if (errno && cp->d.dval != MAWK_NUM_ZERO) /* ignore underflow */
121 mawk_rt_error("mawk_overflow converting %s to number", s->str);
122 #else
123 cp->d.dval = strtonum(s->str, (char **) 0);
124 #endif
125 free_STRING(s);
126 break;
127
128 default:
129 mawk_bozo(MAWK, "mawk_cast on bad type");
130 }
131 cp->type = C_NUM;
132 }
133
134 void mawk_cast1_to_str(mawk_state_t *MAWK, register mawk_cell_t *cp)
135 {
136 register Int lval;
137 char xbuff[260];
138
139 switch (cp->type) {
140 case C_NOINIT:
141 MAWK->null_str.ref_cnt++;
142 cp->ptr = (PTR) & MAWK->null_str;
143 break;
144
145 case C_NUM:
146
147 lval = mawk_d_to_I(cp->d.dval);
148 if (lval == cp->d.dval)
149 sprintf(xbuff, INT_FMT, lval);
150 else
151 sprintf(xbuff, string(MAWK_CONVFMT)->str, cp->d.dval);
152
153 cp->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
154 break;
155
156 case C_STRING:
157 return;
158
159 case C_MBSTRN:
160 case C_STRNUM:
161 break;
162
163 default:
164 mawk_bozo(MAWK, "bad type on mawk_cast");
165 }
166 cp->type = C_STRING;
167 }
168
169 void mawk_cast2_to_str(mawk_state_t *MAWK, register mawk_cell_t *cp)
170 {
171 register Int lval;
172 char xbuff[260];
173
174 switch (cp->type) {
175 case C_NOINIT:
176 MAWK->null_str.ref_cnt++;
177 cp->ptr = (PTR) & (MAWK->null_str);
178 break;
179
180 case C_NUM:
181
182 lval = mawk_d_to_I(cp->d.dval);
183 if (lval == cp->d.dval)
184 sprintf(xbuff, INT_FMT, lval);
185 else
186 sprintf(xbuff, string(MAWK_CONVFMT)->str, cp->d.dval);
187
188 cp->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
189 break;
190
191 case C_STRING:
192 goto two;
193
194 case C_MBSTRN:
195 case C_STRNUM:
196 break;
197
198 default:
199 mawk_bozo(MAWK, "bad type on mawk_cast");
200 }
201 cp->type = C_STRING;
202
203 two:
204 cp++;
205
206 switch (cp->type) {
207 case C_NOINIT:
208 MAWK->null_str.ref_cnt++;
209 cp->ptr = (PTR) & MAWK->null_str;
210 break;
211
212 case C_NUM:
213
214 lval = mawk_d_to_I(cp->d.dval);
215 if (lval == cp->d.dval)
216 sprintf(xbuff, INT_FMT, lval);
217 else
218 sprintf(xbuff, string(MAWK_CONVFMT)->str, cp->d.dval);
219
220 cp->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
221 break;
222
223 case C_STRING:
224 return;
225
226 case C_MBSTRN:
227 case C_STRNUM:
228 break;
229
230 default:
231 mawk_bozo(MAWK, "bad type on mawk_cast");
232 }
233 cp->type = C_STRING;
234 }
235
236 void mawk_cast_to_RE(mawk_state_t *MAWK, register mawk_cell_t *cp)
237 {
238 register PTR p;
239
240 if (cp->type < C_STRING)
241 mawk_cast1_to_str(MAWK, cp);
242
243 p = mawk_re_compile(MAWK, string(cp));
244 free_STRING(string(cp));
245 cp->type = C_RE;
246 cp->ptr = p;
247
248 }
249
250 void mawk_cast_for_split(mawk_state_t *MAWK, register mawk_cell_t *cp)
251 {
252 static const char meta[] = "^$.*+?|[]()";
253 char xbuff[] = "\\X";
254 int c;
255 unsigned len;
256
257 if (cp->type < C_STRING)
258 mawk_cast1_to_str(MAWK, cp);
259
260 if ((len = string(cp)->len) == 1) {
261 if ((c = string(cp)->str[0]) == ' ') {
262 free_STRING(string(cp));
263 cp->type = C_SPACE;
264 return;
265 }
266 else if (strchr(meta, c)) {
267 xbuff[1] = c;
268 free_STRING(string(cp));
269 cp->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
270 }
271 }
272 else if (len == 0) {
273 free_STRING(string(cp));
274 cp->type = C_SNULL;
275 return;
276 }
277
278 mawk_cast_to_RE(MAWK, cp);
279 }
280
281 /* input: cp-> a mawk_cell_t of type C_MBSTRN (maybe strnum)
282 mawk_test it -- mawk_casting it to the appropriate type
283 which is C_STRING or C_STRNUM
284 */
285
286 void mawk_check_strnum(mawk_state_t *MAWK, mawk_cell_t *cp)
287 {
288 char *mawk_test;
289 register unsigned char *s, *q;
290
291 cp->type = C_STRING; /* assume not C_STRNUM */
292 s = (unsigned char *) string(cp)->str;
293 q = s + string(cp)->len;
294 while (MAWK->scan_code[*s] == SC_SPACE)
295 s++;
296 if (s == q)
297 return;
298
299 while (MAWK->scan_code[q[-1]] == SC_SPACE)
300 q--;
301 if (MAWK->scan_code[q[-1]] != SC_DIGIT && q[-1] != '.')
302 return;
303
304 switch (MAWK->scan_code[*s]) {
305 case SC_DIGIT:
306 case SC_PLUS:
307 case SC_MINUS:
308 case SC_DOT:
309
310 #if FPE_TRAPS_ON
311 errno = 0;
312 cp->d.dval = strtonum((char *) s, &mawk_test);
313 /* make mawk_overflow pure string */
314 if (errno && cp->d.dval != MAWK_NUM_ZERO)
315 return;
316 #else
317 cp->d.dval = strtonum((char *) s, &mawk_test);
318 #endif
319
320 if ((char *) q <= mawk_test)
321 cp->type = C_STRNUM;
322 /* <= instead of == , for some buggy strtod
323 e.g. Apple Unix */
324 }
325 }
326
327 /* mawk_cast a mawk_cell_t to a replacement cell */
328
329 void mawk_cast_to_REPL(mawk_state_t *MAWK, register mawk_cell_t *cp)
330 {
331 register mawk_string_t *sval;
332
333 if (cp->type < C_STRING)
334 mawk_cast1_to_str(MAWK, cp);
335 sval = (mawk_string_t *) cp->ptr;
336
337 mawk_cellcpy(MAWK, cp, mawk_repl_compile(MAWK, sval));
338 free_STRING(sval);
339 }
340
0 /********************************************
1 libmawk changes (C) 2009-2014, Tibor 'Igor2' Palinkas;
2 based on mawk code coming with the below copyright:
3
4 copyright 1991-93, Michael D. Brennan
5
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
8
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
12
13 #include "mawk.h"
14 #include "repl.h"
15 #include "cell.h"
16
17 char *mawk_bozo_cellcpy = "bad cell passed to mawk_cellcpy()";
18
19 /* does not assume target was a cell, if so
20 then caller should have made a previous
21 call to cell_destroy */
22
23 #ifdef CELLDEBUG
24 void DB_mawk_cellcpy(mawk_state_t *MAWK, register mawk_cell_t *target, const register mawk_cell_t *source)
25 {
26 static int cnt = 0;
27 cell_paranoia_chk(MAWK, source);
28 switch (target->type = source->type) {
29 case C_NOINIT:
30 case C_SPACE:
31 case C_SNULL:
32 break;
33
34 case C_NUM:
35 target->d.dval = source->d.dval;
36 break;
37
38 case C_STRNUM:
39 target->d.dval = source->d.dval;
40 /* fall thru */
41
42 case C_REPL:
43 case C_MBSTRN:
44 case C_STRING:
45 string(source)->ref_cnt++;
46 /* fall thru */
47
48 case C_RE:
49 target->ptr = source->ptr;
50 break;
51
52 case C_REPLV:
53 mawk_replv_cpy(MAWK, target, source);
54 break;
55
56 default:
57 mawk_bozo(MAWK, "bad cell passed to mawk_cellcpy()");
58 break;
59 }
60 }
61 #endif
62
63 #ifdef CELLDEBUG
64 #include "zmalloc.h"
65 void DB_cell_destroy(mawk_state_t *MAWK, register mawk_cell_t *cp) /* HANGOVER time */
66 {
67 switch (cp->type) {
68 case C_NOINIT:
69 case C_NUM:
70 case C_ARR_REF:
71 break;
72
73 case C_ARR_REF_BT:
74 mawk_bozo(MAWK, "ARR_REF_BT destroy");
75 break;
76
77 case C_MBSTRN:
78 case C_STRING:
79 case C_STRNUM:
80 if (--string(cp)->ref_cnt == 0)
81 mawk_zfree(MAWK, string(cp), string(cp)->len + STRING_OH);
82 break;
83
84 case C_RE:
85 mawk_bozo(MAWK, "cell destroy called on RE cell");
86 default:
87 mawk_bozo(MAWK, "cell destroy called on bad cell type");
88 }
89 cell_destroy_paranoia_set(cp);
90 }
91
92 #endif
0 #include "repl.h"
1
2
3 /* macro to test the type of two adjacent cells */
4 #define TEST2(cp) (MAWK->mpow2[(cp)->type]+MAWK->mpow2[((cp)+1)->type])
5
6 /* paranoia cell checks for cell debug */
7 #ifdef CELLDEBUG
8 #define cell_destroy_paranoia_set(cp) (cp)->type = C_FREED;
9 #define cell_paranoia_chk(MAWK, cp) \
10 do { \
11 if ((cp)->type == C_FREED) \
12 mawk_bozo(MAWK, "invalid cell reference."); \
13 } while (0)
14 #else
15 #define cell_destroy_paranoia_set(cp)
16 #define cell_paranoia_chk(MAWK, cp)
17 #endif
18
19
20 /* cell_destroy: macro or function, for debugging */
21 #ifdef CELLDEBUG
22 #define mawk_cell_destroy(MAWK, cp) DB_cell_destroy(MAWK, cp)
23 #else
24 #define mawk_cell_destroy(MAWK, cp) \
25 do { \
26 if ( (cp)->type >= C_STRING && -- string(cp)->ref_cnt == 0) \
27 mawk_zfree(MAWK, string(cp),string(cp)->len+STRING_OH); \
28 cell_destroy_paranoia_set(cp); \
29 } while(0)
30 #endif
31
32 /* cellcpy: macro or function, for debugging */
33 #ifdef CELLDEBUG
34 /* debug version: real function */
35 void DB_mawk_cellcpy(mawk_state_t *MAWK, register mawk_cell_t *target, const register mawk_cell_t *source);
36 #define mawk_cellcpy DB_mawk_cellcpy
37 #else
38 /* fast version: macro */
39 extern char *mawk_bozo_cellcpy;
40 #define mawk_cellcpy(MAWK_, target, source) \
41 do { \
42 const mawk_cell_t *cellcpy__source = (const mawk_cell_t *)(source); \
43 mawk_cell_t *cellcpy__target = (target); \
44 cell_paranoia_chk((MAWK_), cellcpy__source); \
45 switch (cellcpy__target->type = cellcpy__source->type) { \
46 case C_NOINIT: \
47 case C_SPACE: \
48 case C_SNULL: \
49 break; \
50 case C_NUM: \
51 cellcpy__target->d.dval = cellcpy__source->d.dval; \
52 break; \
53 case C_STRNUM: \
54 cellcpy__target->d.dval = cellcpy__source->d.dval; \
55 case C_REPL: \
56 case C_MBSTRN: \
57 case C_STRING: \
58 string(cellcpy__source)->ref_cnt++; \
59 case C_RE: \
60 cellcpy__target->ptr = cellcpy__source->ptr; \
61 break; \
62 case C_REPLV: \
63 mawk_replv_cpy((MAWK_), cellcpy__target, cellcpy__source); \
64 break; \
65 default: \
66 mawk_bozo(MAWK_, mawk_bozo_cellcpy); \
67 break; \
68 } \
69 } while(0)
70 #endif
71
72
0
1 /********************************************
2 code.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991-93, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include "mawk.h"
16 #include "code.h"
17 #include "init.h"
18 #include "jmp.h"
19 #include "field.h"
20
21
22 static CODEBLOCK *new_code(mawk_state_t *);
23
24 /* grow the active code */
25 void mawk_code_grow(mawk_state_t * MAWK)
26 {
27 unsigned oldsize = mawk_code_limit - mawk_code_base;
28 unsigned newsize = PAGESZ + oldsize;
29 unsigned delta = mawk_code_ptr - mawk_code_base;
30
31 if (mawk_code_ptr > mawk_code_limit)
32 mawk_bozo(MAWK, "CODEWARN is too small");
33
34 mawk_code_base = (INST *)
35 mawk_zrealloc(MAWK, mawk_code_base, INST_BYTES(oldsize), INST_BYTES(newsize));
36 mawk_code_limit = mawk_code_base + newsize;
37 mawk_code_warn = mawk_code_limit - CODEWARN;
38 mawk_code_ptr = mawk_code_base + delta;
39 }
40
41 void mawk_code_reset_size(mawk_state_t *MAWK, int newsize)
42 {
43 unsigned oldsize = mawk_code_limit - mawk_code_base;
44
45 mawk_bfree(MAWK, mawk_code_base, oldsize);
46
47 mawk_code_base = (INST *)mawk_zmalloc(MAWK, INST_BYTES(newsize));
48 mawk_code_limit = mawk_code_base + newsize;
49 mawk_code_warn = mawk_code_limit - CODEWARN;
50 mawk_code_ptr = mawk_code_base;
51 }
52
53
54 /* shrinks executable code that's done to its final size */
55 INST *mawk_code_shrink(mawk_state_t *MAWK, CODEBLOCK *p, unsigned *sizep)
56 {
57
58 unsigned oldsize = INST_BYTES(p->limit - p->base);
59 unsigned newsize = INST_BYTES(p->ptr - p->base);
60 INST *retval;
61
62 *sizep = newsize;
63
64 retval = (INST *) mawk_zrealloc(MAWK, p->base, oldsize, newsize);
65
66 /* free CODEBLOCK: only INST will be used as this block won't grow anymore */
67 MAWK_ZFREE(MAWK, p);
68 return retval;
69 }
70
71 /* code an op and a pointer in the active_code */
72 void mawk_xcode2(mawk_state_t *MAWK, int op, PTR ptr)
73 {
74 register INST *p = mawk_code_ptr + 2;
75
76 if (p >= mawk_code_warn) {
77 mawk_code_grow(MAWK);
78 p = mawk_code_ptr + 2;
79 }
80
81 p[-2].op = op;
82 p[-1].ptr = ptr;
83 mawk_code_ptr = p;
84 }
85
86 /* code two ops in the active_code */
87 void mawk_code2op(mawk_state_t *MAWK, int x, int y)
88 {
89 register INST *p = mawk_code_ptr + 2;
90
91 if (p >= mawk_code_warn) {
92 mawk_code_grow(MAWK);
93 p = mawk_code_ptr + 2;
94 }
95
96 p[-2].op = x;
97 p[-1].op = y;
98 mawk_code_ptr = p;
99 }
100
101 void mawk_code_init(mawk_state_t *MAWK)
102 {
103 MAWK->main_code_p = new_code(MAWK);
104
105 if (MAWK->main_code_p->ptr == NULL)
106 return;
107
108 MAWK->active_code = *MAWK->main_code_p;
109 code1(_OMAIN);
110 }
111
112 /* final code relocation
113 set_code() as in set concrete */
114 void mawk_set_code(mawk_state_t * MAWK)
115 {
116 /* set the main code which is active_code */
117 if (MAWK->end_code_p || mawk_code_offset > 1) {
118 int gl_offset = mawk_code_offset;
119
120 if (MAWK->NR_flag)
121 mawk_code2op(MAWK, OL_GL_NR, _HALT);
122 else
123 mawk_code2op(MAWK, OL_GL, _HALT);
124
125 *MAWK->main_code_p = MAWK->active_code;
126 MAWK->main_start = mawk_code_shrink(MAWK, MAWK->main_code_p, &MAWK->main_size);
127 MAWK->next_label = MAWK->main_start + gl_offset;
128 MAWK->execution_start = MAWK->main_start;
129 }
130 else { /* only BEGIN */
131
132 mawk_zfree(MAWK, mawk_code_base, INST_BYTES(PAGESZ));
133 MAWK_ZFREE(MAWK, MAWK->main_code_p);
134 MAWK->main_code_p = NULL;
135 }
136
137 /* set the END code */
138 if (MAWK->end_code_p) {
139 MAWK->active_code = *MAWK->end_code_p;
140 mawk_code2op(MAWK, _EXIT0, _HALT);
141 *MAWK->end_code_p = MAWK->active_code;
142 MAWK->end_start = mawk_code_shrink(MAWK, MAWK->end_code_p, &MAWK->end_size);
143 MAWK->end_start_orig = MAWK->end_start;
144 }
145
146 /* set the BEGIN code */
147 if (MAWK->begin_code_p) {
148 MAWK->active_code = *MAWK->begin_code_p;
149 if (MAWK->main_start)
150 mawk_code2op(MAWK, _JMAIN, _HALT);
151 else
152 mawk_code2op(MAWK, _EXIT0, _HALT);
153 *MAWK->begin_code_p = MAWK->active_code;
154 MAWK->begin_start = mawk_code_shrink(MAWK, MAWK->begin_code_p, &MAWK->begin_size);
155
156 MAWK->execution_start = MAWK->begin_start;
157 }
158
159 if (!MAWK->execution_start) {
160 /* program had functions but no pattern-action bodies */
161 MAWK->execution_start = MAWK->begin_start = (INST *) mawk_zmalloc(MAWK, 2 * sizeof(INST));
162 MAWK->execution_start[0].op = _EXIT0;
163 MAWK->execution_start[1].op = _HALT;
164 }
165 }
166
167 static CODEBLOCK *new_code(mawk_state_t *MAWK)
168 {
169 CODEBLOCK *p = MAWK_ZMALLOC(MAWK, CODEBLOCK);
170
171 p->base = (INST *) mawk_zmalloc(MAWK, INST_BYTES(PAGESZ));
172 p->limit = p->base + PAGESZ;
173 p->warn = p->limit - CODEWARN;
174 p->ptr = p->base;
175
176 return p;
177 }
178
179 /* mawk_begin/end_setup: switches the active_code from MAIN to a
180 BEGIN or END */
181
182 void mawk_be_setup(mawk_state_t *MAWK, int scope)
183 {
184 *MAWK->main_code_p = MAWK->active_code;
185
186 if (scope == SCOPE_BEGIN) {
187 if (!MAWK->begin_code_p)
188 MAWK->begin_code_p = new_code(MAWK);
189 MAWK->active_code = *MAWK->begin_code_p;
190 }
191 else {
192 if (!MAWK->end_code_p)
193 MAWK->end_code_p = new_code(MAWK);
194 MAWK->active_code = *MAWK->end_code_p;
195 }
196 }
0
1 /********************************************
2 code.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef CODE_H
17 #define CODE_H
18
19 #include <libmawk/memory.h>
20
21 #define PAGESZ 512
22 /* number of code instructions allocated at one time */
23 #define CODEWARN 16
24
25 /* coding scope */
26 #define SCOPE_MAIN 0
27 #define SCOPE_BEGIN 1
28 #define SCOPE_END 2
29 #define SCOPE_FUNCT 3
30
31 #define mawk_code_ptr MAWK->active_code.ptr
32 #define mawk_code_base MAWK->active_code.base
33 #define mawk_code_warn MAWK->active_code.warn
34 #define mawk_code_limit MAWK->active_code.limit
35 #define mawk_code_offset (mawk_code_ptr-mawk_code_base)
36
37 #define INST_BYTES(x) (sizeof(INST)*(unsigned)(x))
38
39 #define addloc \
40 if ((MAWK->debug_symbols) && (MAWK->token_lineno != MAWK->last_token_lineno)) { \
41 mawk_code_ptr++ -> op = LOCATION; \
42 mawk_code_ptr++ -> op = MAWK->token_lineno; \
43 MAWK->last_token_lineno = MAWK->token_lineno; \
44 } \
45
46 #define code1(x) \
47 do { \
48 mawk_code_ptr++ -> op = (x); \
49 } while(0)
50
51 /* shutup picky compilers */
52 #define code2(MAWK, x,p) \
53 do { \
54 addloc \
55 mawk_xcode2(MAWK, x,(PTR)(p)); \
56 } while(0)
57
58 void mawk_xcode2(mawk_state_t *, int, PTR);
59 void mawk_code2op(mawk_state_t *, int, int);
60 INST *mawk_code_shrink(mawk_state_t *, CODEBLOCK *, unsigned *);
61 void mawk_code_reset_size(mawk_state_t *MAWK, int size);
62 void mawk_code_grow(mawk_state_t * MAWK);
63 void mawk_set_code(mawk_state_t *);
64 void mawk_be_setup(mawk_state_t *, int);
65 void mawk_dump_code(mawk_state_t *); /* dump code in a format dictated by MAKW->dump_code_flag */
66 void mawk_dump_code_text(mawk_state_t *);
67 void mawk_dump_sym_text(mawk_state_t *); /* dump symbol table in text (in binary it's automatically included) */
68
69 const char *mawk_find_bi_name(PF_CP);
70 PF_CP mawk_find_bi_ptr(const char *name);
71
72 /* the machine opcodes */
73 /* to avoid confusion with a ptr FE_PUSHA must have op code 0 */
74 /* unfortunately enums are less portable than defines */
75
76 #define FE_PUSHA 0
77 #define FE_PUSHI 1
78 #define F_PUSHA 2
79 #define F_PUSHI 3
80 #define NF_PUSHI 4
81 #define _HALT 5
82 #define _RANGE_STOP 6
83 #define _PUSHC 7
84 #define _PUSHD 8
85 #define _PUSHS 9
86 #define _PUSHINT 10
87 #define _PUSHA 11
88 #define _PUSHI 12
89 #define L_PUSHA 13
90 #define L_PUSHI 14
91 #define AE_PUSHA 15
92 #define AE_PUSHI 16
93 #define A_PUSHA 17
94 #define LAE_PUSHA 18
95 #define LAE_PUSHI 19
96 #define LA_PUSHA 20
97 #define _POP 21
98 #define _ADD 22
99 #define _SUB 23
100 #define _MUL 24
101 #define _DIV 25
102 #define _MOD 26
103 #define _POW 27
104 #define _NOT 28
105 #define _TEST 29
106 #define A_TEST 30
107 #define A_DEL 31
108 #define ALOOP 32
109 #define A_CAT 33
110 #define _UMINUS 34
111 #define _UPLUS 35
112 #define _ASSIGN 36
113 #define _ADD_ASG 37
114 #define _SUB_ASG 38
115 #define _MUL_ASG 39
116 #define _DIV_ASG 40
117 #define _MOD_ASG 41
118 #define _POW_ASG 42
119 #define F_ASSIGN 43
120 #define F_ADD_ASG 44
121 #define F_SUB_ASG 45
122 #define F_MUL_ASG 46
123 #define F_DIV_ASG 47
124 #define F_MOD_ASG 48
125 #define F_POW_ASG 49
126 #define _CAT 50
127 #define _BUILTIN 51
128 #define _PRINT 52
129 #define _POST_INC 53
130 #define _POST_DEC 54
131 #define _PRE_INC 55
132 #define _PRE_DEC 56
133 #define F_POST_INC 57
134 #define F_POST_DEC 58
135 #define F_PRE_INC 59
136 #define F_PRE_DEC 60
137 #define _JMP 61
138 #define _JNZ 62
139 #define _JZ 63
140 #define _LJZ 64
141 #define _LJNZ 65
142 #define _EQ 66
143 #define _NEQ 67
144 #define _LT 68
145 #define _LTE 69
146 #define _GT 70
147 #define _GTE 71
148 #define _MATCH0 72
149 #define _MATCH1 73
150 #define _MATCH2 74
151 #define _EXIT 75
152 #define _EXIT0 76
153 #define _NEXT 77
154 #define _RANGE_CHK 78
155 #define _CALL 79
156 #define _RET 80
157 #define _RET0 81
158 #define SET_ALOOP 82
159 #define POP_AL 83
160 #define OL_GL 84
161 #define OL_GL_NR 85
162 #define _OMAIN 86
163 #define _JMAIN 87
164 #define DEL_A 88
165 #define LOCATION 89
166 /* for catching array write: */
167 #define _ASSIGN_ARR 90
168 #define _ADD_ASG_ARR 91
169 #define _SUB_ASG_ARR 92
170 #define _MUL_ASG_ARR 93
171 #define _DIV_ASG_ARR 94
172 #define _MOD_ASG_ARR 95
173 #define _POW_ASG_ARR 96
174 #define _POST_INC_ARR 97
175 #define _POST_DEC_ARR 98
176 #define _PRE_INC_ARR 99
177 #define _PRE_DEC_ARR 100
178 #define AE_PUSHA_WRARR 101
179 #define LAE_PUSHA_WRARR 102
180
181 /* these opcodes are used for binary dumps to hold references to different
182 linked pointers - assume op to be at least 32 bits unsigned (but pointers
183 are not narrower than that on any target platform). Each opcode is
184 a bitmask applied onto an index integer */
185 #define DUMP_REPL 1 << 28
186 #define DUMP_NUM 2 << 28
187 #define DUMP_STR 3 << 28
188 #define DUMP_VAR 4 << 28
189 #define DUMP_FIELDIDX 5 << 28
190 #define DUMP_CALL 6 << 28
191 #define DUMP_SPECFIELD 7 << 28
192 #define DUMP_RE 8 << 28
193 #define DUMP_SPLIT_SPACE 9 << 28
194 #define DUMP_SPLIT_NULL 10 << 28
195
196 #endif /* CODE_H */
0 /********************************************
1 dump_code.c
2
3 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991-93, Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14 #include "mawk.h"
15 #include "code.h"
16 #include "init.h"
17 #include "jmp.h"
18 #include "field.h"
19 #include "da_bin_helper.h"
20
21 void mawk_dump_code(mawk_state_t * MAWK)
22 {
23 switch(MAWK->dump_code_flag) {
24 case 1: mawk_dump_code_text(MAWK); break;
25 case 2: mawk_print_code_bin(MAWK, ""); break;
26 default:
27 mawk_errmsg(MAWK, -1, "libmawk internal error: unknown MAWK->dump_code_flag value %d\n", MAWK->dump_code_flag);
28 abort();
29 }
30 }
0 put /tmpasm/IFS {\n}
1 put /tmpasm/OFS {\n}
2
3 put /local/includes ?sys/types/size_t/includes
4 gsub /local/includes {\\\\n *} {\n}
5 uniq /local/includes
6
7 put /tmpasm/OFS {}
8 put /tmpasm/IFS {}
9
10 print [@
11 /* Autogenerated by ./configure from conf.h.in - DO NOT EDIT */
12 #ifndef LIBMAWK_CONF_H
13 #define LIBMAWK_CONF_H
14
15 #define LMAWK_VER "@/local/version/1@.@/local/version/2@.@/local/version/3@"
16
17 #define _XOPEN_SOURCE 600
18
19 @/local/includes@
20
21 @]
22
23 switch /local/numeric
24 case {int} print [@
25 /* numeric is int, do not use floating point */
26 #define MAWK_NO_FLOAT
27 @]
28 end
29
30 case {double} print [@
31 /* numeric is double, use floating point */
32 #undef MAWK_NO_FLOAT
33 @]
34 end
35 end
36
37 print {\n\n/* Whether realpath is available */\n}
38 print_ternary ?libs/fs/realpath/presents {#define mawk_realpath realpath} {#undef mawk_realpath}
39
40 print {\n\n/* Whether pipe(2) is available */\n}
41 print_ternary ?libs/io/pipe/presents {#undef MAWK_NO_PIPE} {#define MAWK_NO_PIPE 1}
42
43 print [@
44 /* === math_wrap */
45 @]
46
47 print {/* log() */\n}
48 switch ?libs/math/cc/log/m_0/errno
49 case {0} print {#define P_MBROKEN_LOG_M_0\n}; end
50 default print {/* #define P_MBROKEN_LOG_M_0 */\n}; end
51 end
52
53 switch ?libs/math/cc/log/p_0/errno
54 case {0} print {#define P_MBROKEN_LOG_P_0\n}; end
55 default print {/* #define P_MBROKEN_LOG_P_0 */\n}; end
56 end
57
58 switch ?libs/math/cc/log/p_1/errno
59 case {0} print {#define P_MBROKEN_LOG_P_1\n}; end
60 default print {/* #define P_MBROKEN_LOG_P_1 */\n}; end
61 end
62
63 print {\n\n/* Defined if NaN works as expected in all operations */\n}
64 print_ternary ?libs/math/nanop/allok {#define MAWK_HAVE_SAFE_NAN} {/* #define MAWK_HAVE_SAFE_NAN */}
65
66 print [@
67 /* defined if all static global allocations such as builtin variables
68 should be freed. Pros: easier memory leak testing (no builtin leaks);
69 cons: zmalloc's uninit will throw them out in less cpu cycles.
70 */
71 /* #define MAWK_MEM_PEDANTIC */
72 #endif
73
74 @]
0
1 /********************************************
2 da_bin.c
3
4 libmawk binary dump (C) 2012, Tibor 'Igor2' Palinkas;
5 losely based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include "mawk.h"
17
18 #include "code.h"
19 #include "bi_funct.h"
20 #include "repl.h"
21 #include "field.h"
22 #include "num.h"
23 #include "fin.h"
24 #include "vars.h"
25 #include "f2d.h"
26 #include <string.h>
27
28 /* for load sanity checks declare large maximums; without these a malformed
29 binary may cause libmawk to allocate a lot of memory */
30 #define MEG (1024*1024)
31 #define BIN_CODE_MAXLEN 64*MEG
32 #define BIN_NAME_MAXLEN 1024
33 #define BIN_MAXVARS 1024*1024
34 #define BIN_MAXSTRS BIN_MAXVARS
35
36 #define BIN_FILEVER 1
37
38 /* SAVE:
39 - code
40 - constant nums
41 - constant str
42 - funtion names and pointers (including builtins!)
43 (->repl is not saved; regex's are recompiled since regex compiler needs
44 to be in the binary for runtime purposes anyway - save them as string)
45 */
46
47 static int safe_strcmp(const char *s1, const char *s2)
48 {
49 if ((s1 == NULL) && (s2 == NULL))
50 return 0;
51 if ((s1 == NULL) || (s2 == NULL))
52 return 1;
53 return strcmp(s1, s2);
54 }
55
56 static int safe_strlen(const char *s)
57 {
58 if (s == NULL)
59 return 0;
60 return strlen(s);
61 }
62
63 static mawk_string_t *safe_new_STRING(mawk_state_t *MAWK, const char *s)
64 {
65 if (s == NULL)
66 s = "";
67 return mawk_new_STRING(MAWK, s);
68 }
69
70 /* link tables are slow linear lists for now; may replace with hashes later */
71 typedef struct {
72 int numsu, strsu, varsu;
73 int numsa, strsa, varsa;
74 mawk_num_t *nums;
75 const char **strs;
76 struct {
77 int vtype;
78 mawk_cell_t *cp;
79 } *vars;
80 } link_t;
81
82
83 static void link_free(link_t *l)
84 {
85 if (l->nums != NULL)
86 free(l->nums);
87 if (l->strs != NULL)
88 free(l->strs);
89 if (l->vars != NULL)
90 free(l->vars);
91 }
92
93 #define check_grow(l, arr, used, alloced) \
94 if (l->used >= l->alloced) { \
95 l->alloced += 256; \
96 l->arr = realloc(l->arr, sizeof(*l->arr) * l->alloced); \
97 }
98
99 static int save_num(link_t *l, mawk_num_t *num)
100 {
101 int n;
102 for(n = 0; n < l->numsu; n++)
103 if (l->nums[n] == *num)
104 return n;
105
106 check_grow(l, nums, numsu, numsa);
107 l->nums[l->numsu] = *num;
108 return l->numsu++;
109 }
110
111
112 static int save_str(link_t *l, const char *str)
113 {
114 int n;
115 for(n = 0; n < l->strsu; n++)
116 if (safe_strcmp(l->strs[n], str) == 0) {
117 return n;
118 }
119 check_grow(l, strs, strsu, strsa);
120 l->strs[l->strsu] = str; /* no need to copy, strings are constant during dumping */
121 return l->strsu++;
122 }
123
124 static int save_var(link_t *l, mawk_cell_t *v, int vtype)
125 {
126 int n;
127 for(n = 0; n < l->varsu; n++)
128 if ((l->vars[n].cp == v) && (l->vars[n].vtype == vtype))
129 return n;
130
131 check_grow(l, vars, varsu, varsa);
132 l->vars[l->varsu].vtype = vtype;
133 l->vars[l->varsu].cp = v;
134 return l->varsu++;
135 }
136
137 static mawk_num_t *load_num(mawk_state_t *MAWK, link_t *l, int id)
138 {
139 mawk_num_t *n;
140
141 if ((id < 0) || (id >= l->numsu))
142 return NULL;
143
144 n = mawk_zmalloc(MAWK, sizeof(mawk_num_t));
145 *n = l->nums[id];
146 return n;
147 }
148
149 static const char *invalid_str = "load_str invalid";
150 static const char *load_str(link_t *l, int id)
151 {
152 if ((id < 0) || (id >= l->strsu))
153 return invalid_str;
154 return l->strs[id];
155 }
156
157 static mawk_cell_t *load_var(link_t *l, int id)
158 {
159 if ((id < 0) || (id >= l->varsu))
160 return NULL;
161 return l->vars[id].cp;
162 }
163
164 static void *load_bifunc(link_t *l, int id)
165 {
166 const char *name;
167 name = load_str(l, id);
168 if (name == invalid_str)
169 return NULL;
170 return mawk_f2d(mawk_find_bi_ptr(name));
171 }
172
173 static FBLOCK *bin_new_funct(mawk_state_t *MAWK, const char *name, int add_to_list)
174 {
175 FBLOCK *fbp;
176 SYMTAB *s;
177
178 s = mawk_find(MAWK, name, 0);
179 if (s != NULL) {
180 if (s->type != ST_FUNCT)
181 return NULL;
182
183 if (add_to_list)
184 mawk_add_to_fdump_list(MAWK, s->stval.fbp);
185 return s->stval.fbp;
186 }
187
188 s = mawk_find(MAWK, name, 1);
189 s->type = ST_FUNCT ;
190 fbp = s->stval.fbp = (FBLOCK *) mawk_zmalloc(MAWK, sizeof(FBLOCK)) ;
191 fbp->name = mawk_zstrclone(MAWK, name);
192 fbp->code = (INST*) 0 ;
193
194 if (add_to_list)
195 mawk_add_to_fdump_list(MAWK, fbp);
196
197 return fbp;
198 }
199
200 static void *bin_load_func_ref(mawk_state_t *MAWK, link_t *l, int id)
201 {
202 const char *name;
203
204 name = load_str(l, id);
205 if (name == invalid_str)
206 return NULL;
207 return bin_new_funct(MAWK, name, 0);
208 }
209
210
211
212 #define pack_re(p, cp) p->op = DUMP_RE | save_str(l, mawk_re_uncompile(MAWK, cp->ptr))
213 #define pack_match(p) p->op = DUMP_RE | save_str(l, mawk_re_uncompile(MAWK, p->ptr))
214 #define pack_repl(p, r) p->op = DUMP_REPL | save_str(l, mawk_repl_uncompile(MAWK, r))
215 #define pack_numptr(p) p->op = DUMP_NUM | save_num(l, (mawk_num_t *)p->ptr)
216 #define pack_split_space(p) p->op = DUMP_SPLIT_SPACE
217 #define pack_split_null(p) p->op = DUMP_SPLIT_NULL
218 #define pack_str(p) \
219 do { \
220 mawk_string_t *sval = (mawk_string_t *) p->ptr; \
221 p->op = DUMP_STR | save_str(l, sval->str); \
222 } while(0)
223
224 #define pack_var_(p, cp, t) p->op = DUMP_VAR | save_var(l, p->ptr, t)
225 #define pack_var(p, cp) pack_var_(p, cp, ST_VAR)
226 #define pack_field(p, cp) pack_var_(p, cp, ST_FIELD)
227 #define pack_field_0(p) p->op = DUMP_SPECFIELD | 0
228 #define pack_field_shadow(p) p->op = DUMP_SPECFIELD | 1
229 #define pack_arr(p, cp) pack_var_(p, cp, ST_ARRAY)
230 #define pack_index(p, cp) p->op = DUMP_FIELDIDX | mawk_field_addr_to_index(MAWK, cp)
231 #define pack_bifunc(p, cp) p->op = DUMP_CALL | save_str(l, mawk_find_bi_name((PF_CP) mawk_d2f(p->ptr)))
232 #define pack_call(p) p->op = DUMP_CALL | save_str(l, ((FBLOCK *) p->ptr)->name)
233
234
235 /* check if op matches flag; return NULL if not or remove flag */
236 #define chk_mask(op, flag) do { if ((op & flag) != flag) return NULL; op &= ~(flag); } while(0)
237
238 #define unpack_re(p, cp) do { \
239 const char *s; \
240 chk_mask(p->op, DUMP_RE); \
241 s = load_str(l, p->op); \
242 if (s == invalid_str) \
243 return NULL; \
244 cp = mawk_zmalloc(MAWK, sizeof(mawk_cell_t)); \
245 p->ptr = cp; \
246 cp->type = C_RE; \
247 cp->ptr = mawk_re_compile(MAWK, mawk_new_STRING(MAWK, s)); \
248 } while(0)
249
250 #define unpack_match(p) do { \
251 const char *s; \
252 chk_mask(p->op, DUMP_RE); \
253 s = load_str(l, p->op); \
254 if (s == invalid_str) \
255 return NULL; \
256 p->ptr = mawk_re_compile(MAWK, mawk_new_STRING(MAWK, s)); \
257 } while(0)
258
259 #define unpack_repl(p, r) do { \
260 const char *s; \
261 chk_mask(p->op, DUMP_REPL); \
262 s = load_str(l, p->op); \
263 if (s == invalid_str) \
264 return NULL; \
265 cp = mawk_zmalloc(MAWK, sizeof(mawk_cell_t)); \
266 p->ptr = mawk_repl_compile(MAWK, safe_new_STRING(MAWK, s)); \
267 } while(0)
268
269 #define unpack_numptr(p) do { chk_mask(p->op, DUMP_NUM); p->ptr = load_num(MAWK, l, p->op); if (p->ptr == NULL) return NULL; } while(0)
270 #define unpack_split_space(p) do { mawk_cell_t *cp; chk_mask(p->op, DUMP_SPLIT_SPACE); cp = MAWK_ZMALLOC(MAWK, mawk_cell_t); p->ptr = cp; cp->type = C_SPACE; } while(0)
271 #define unpack_split_null(p) do { mawk_cell_t *cp; chk_mask(p->op, DUMP_SPLIT_NULL); cp = MAWK_ZMALLOC(MAWK, mawk_cell_t); p->ptr = cp; cp->type = C_SNULL; } while(0)
272 #define unpack_str(p) \
273 do { \
274 const char *s; \
275 chk_mask(p->op, DUMP_STR); \
276 s = load_str(l, p->op); \
277 if (s == invalid_str) \
278 return NULL; \
279 p->ptr = safe_new_STRING(MAWK, s); \
280 } while(0)
281 #define unpack_var_(p, cp, t) do { chk_mask(p->op, DUMP_VAR); p->ptr = load_var(l, p->op); if (p->ptr == NULL) return NULL; } while (0)
282 #define unpack_var(p, cp) unpack_var_(p, cp, ST_VAR)
283 #define unpack_field(p, cp) unpack_var_(p, cp, ST_FIELD)
284 #define unpack_field_0(p) do { chk_mask(p->op, DUMP_SPECFIELD); p->ptr = MAWK->field;} while (0)
285 #define unpack_field_shadow(p) do { chk_mask(p->op, DUMP_SPECFIELD); p->ptr = &MAWK->fs_shadow; } while (0)
286 #define unpack_arr(p, cp) unpack_var_(p, cp, ST_ARRAY)
287 #define unpack_index(p, cp) do { chk_mask(p->op, DUMP_FIELDIDX); p->ptr = field_ptr(p->op); } while (0)
288 #define unpack_bifunc(p, cp) do { chk_mask(p->op, DUMP_CALL); p->ptr = load_bifunc(l, p->op); if (p->ptr == NULL) return NULL; } while (0)
289 #define unpack_call(p) do { chk_mask(p->op, DUMP_CALL); p->ptr = bin_load_func_ref(MAWK, l, p->op); if (p->ptr == NULL) return NULL; } while (0)
290
291 /* evaluate macro pack_ or unpack_, depending on pack flag */
292 #define link_re(p, cp) do { if (pack) pack_re(p, cp); else unpack_re(p, cp); } while (0)
293 #define link_match(p) do { if (pack) pack_match(p); else unpack_match(p); } while (0)
294 #define link_repl(p, r) do { if (pack) pack_repl(p, r); else unpack_repl(p, r); } while (0)
295 #define link_numptr(p) do { if (pack) pack_numptr(p); else unpack_numptr(p); } while (0)
296 #define link_split_space(p) do { if (pack) pack_split_space(p); else unpack_split_space(p); } while (0)
297 #define link_split_null(p) do { if (pack) pack_split_null(p); else unpack_split_null(p); } while (0)
298 #define link_str(p) do { if (pack) pack_str(p); else unpack_str(p); } while (0)
299 #define link_var(p, cp) do { if (pack) pack_var(p, cp); else unpack_var(p, cp); } while (0)
300 #define link_field(p, cp) do { if (pack) pack_field(p, cp); else unpack_field(p, cp); } while (0)
301 #define link_field_0(p) do { if (pack) pack_field_0(p); else unpack_field_0(p); } while (0)
302 #define link_field_shadow(p) do { if (pack) pack_field_shadow(p); else unpack_field_shadow(p); } while (0)
303 #define link_arr(p, cp) do { if (pack) pack_arr(p, cp); else unpack_arr(p, cp); } while (0)
304 #define link_index(p, cp) do { if (pack) pack_index(p, cp); else unpack_index(p, cp); } while (0)
305 #define link_bifunc(p, cp) do { if (pack) pack_bifunc(p, cp); else unpack_bifunc(p, cp); } while (0)
306 #define link_call(p) do { if (pack) pack_call(p); else unpack_call(p); } while (0)
307
308 INST *mawk_da_bin(mawk_state_t *MAWK, INST *start, link_t *l, int pack)
309 {
310 mawk_cell_t *cp;
311 register INST *p = start;
312
313 /* fprintf(stderr, "-\n"); */
314 do {
315 /* fprintf(stderr, "%d: %d\n", p-start, p->op);*/
316
317 switch (p++->op) {
318
319 case _PUSHC:
320 cp = (mawk_cell_t *) p->ptr;
321 if (pack) {
322 switch (cp->type) {
323 case C_RE:
324 link_re(p, cp);
325 break;
326 case C_REPL:
327 case C_REPLV:
328 link_repl(p, cp);
329 break;
330 case C_SPACE:
331 link_split_space(p);
332 break;
333 case C_SNULL:
334 link_split_null(p);
335 break;
336 default:
337 /* nothing else to save */
338 break;
339 }
340 }
341 else {
342 if (p->op == DUMP_SPLIT_SPACE)
343 link_split_space(p);
344 else if (p->op == DUMP_SPLIT_NULL)
345 link_split_null(p);
346 else if ((p->op & DUMP_RE) == DUMP_RE)
347 link_re(p, cp);
348 else if ((p->op & DUMP_REPL) == DUMP_REPL)
349 link_repl(p, cp);
350 }
351 p++;
352 break;
353
354 case _PUSHD:
355 link_numptr(p);
356 p++;
357 break;
358 case _PUSHS:
359 link_str(p);
360 p++;
361 break;
362 case _MATCH0:
363 case _MATCH1:
364 link_match(p);
365 p++;
366 break;
367
368 case _PUSHA:
369 cp = (mawk_cell_t *) p->ptr;
370 link_var(p, cp);
371 p++;
372 break;
373
374 case _PUSHI:
375 cp = (mawk_cell_t *) p->ptr;
376 if (pack) {
377 if (cp == MAWK->field)
378 link_field_0(p);
379 else if (cp == &MAWK->fs_shadow)
380 link_field_shadow(p);
381 else {
382 if (cp > MAWK_NF && cp <= LAST_PFIELD)
383 link_field(p, cp);
384 else
385 link_var(p, cp);
386 }
387 }
388 else {
389 if (p->op == (DUMP_SPECFIELD | 0))
390 link_field_0(p);
391 else if (p->op == (DUMP_SPECFIELD | 1))
392 link_field_shadow(p);
393 else
394 link_var(p, cp); /* fields are just variables */
395 }
396 p++;
397 break;
398
399 case L_PUSHA:
400 case L_PUSHI:
401 case LAE_PUSHI:
402 case LAE_PUSHA:
403 case LAE_PUSHA_WRARR:
404 case LA_PUSHA:
405 /* address is (p+1)->op */
406 p++;
407 break;
408
409 case F_PUSHI:
410 /* address is (p+1)->op */
411 p++;
412 p++;
413 break;
414
415
416 case F_PUSHA:
417 cp = (mawk_cell_t *) p->ptr;
418 if (pack) {
419 if (cp >= MAWK_NF && cp <= LAST_PFIELD)
420 link_field(p, cp);
421 else
422 link_index(p, cp);
423 }
424 else {
425 if ((p->op & DUMP_FIELDIDX) == DUMP_FIELDIDX)
426 link_index(p, cp);
427 else
428 link_field(p, cp);
429 }
430 p++;
431 break;
432
433
434 case AE_PUSHA:
435 case AE_PUSHA_WRARR:
436 case AE_PUSHI:
437 case A_PUSHA:
438 cp = (mawk_cell_t *) p->ptr;
439 link_arr(p, cp);
440 p++;
441 break;
442
443 case _PUSHINT:
444 /* integer operand is (p+1)->op */
445 p++;
446 break;
447
448 case _BUILTIN:
449 case _PRINT:
450 cp = (mawk_cell_t *) p->ptr;
451 link_bifunc(p, cp);
452 p++;
453 break;
454
455 case _JMP:
456 case _JNZ:
457 case _JZ:
458 case _LJZ:
459 case _LJNZ:
460 case SET_ALOOP:
461 case ALOOP:
462 case A_CAT:
463 /* address is (p+1)->op */
464 p++;
465 break;
466
467 case _CALL:
468 link_call(p);
469 p += 2;
470 break;
471
472 case _HALT:
473 break;
474
475 case _RANGE_CHK:
476 p += 4;
477 break;
478
479 case LOCATION:
480 p++;
481 break;
482
483 default:
484 /* simple code */
485 break;
486 }
487 } while (p->op != _HALT);
488 p++;
489 return p;
490 }
491
492 void mawk_fdump_bin(mawk_state_t * MAWK, link_t *l)
493 {
494 register struct mawk_fdump *p, *q = MAWK->fdump_list;
495
496 while (q) {
497 p = q;
498 q = p->link;
499 /* fprintf(stdout, "function %s\n", p->fbp->name); */
500 mawk_da_bin(MAWK, p->fbp->code, l, 1);
501 }
502 }
503
504
505 static const char *f_id = "libmawk\n";
506 typedef struct header_s {
507 char f_id[8];
508 char numeric; /* see mawk_num_id in num_*.c */
509 char filever; /* should be BIN_FILEVER */
510 union {
511 short int s;
512 unsigned char c;
513 } byteorder;
514 char inst_size;
515 char num_size;
516 char pad[50]; /* reserved for future use - header size should be 64 bytes long */
517 } header_t;
518
519 #define chk_hdr_size(h) \
520 if (sizeof(h) != 64) { \
521 mawk_errmsg(MAWK, 0, "Internal libmawk error: da_bin: header struct size is not 64 bytes but %d bytes", sizeof(h)); \
522 abort(); \
523 }
524
525 #ifndef MAWK_NO_COMP
526 static int link_bin_sect(mawk_state_t * MAWK, INST *b, link_t *l)
527 {
528 INST *p;
529
530 if (b != NULL) {
531 p = mawk_da_bin(MAWK, b, l, 1);
532 return p - b;
533 }
534 return 0;
535 }
536
537 static int save_bin_sect(mawk_state_t * MAWK, void *fd, int (*write)(void *fd, const void *buff, size_t len), INST *b, int len)
538 {
539 if (write(fd, &len, 4) != 4)
540 return -1;
541 if (b != NULL) {
542 int l;
543 l = len * sizeof(INST);
544 if (write(fd, b, l) != l)
545 return -1;
546 }
547 return 0;
548 }
549
550 int mawk_save_code_bin_(mawk_state_t * MAWK, void *fd, int (*write)(void *fd, const void *buff, size_t len))
551 {
552 header_t h;
553 link_t l;
554 int n;
555 long int len, begin_len, end_len, main_len, num_func;
556 long int *flen;
557 struct mawk_fdump **fps;
558 struct mawk_fdump *fp;
559
560 /* create header */
561 chk_hdr_size(h);
562 memcpy(h.f_id, f_id, sizeof(h.f_id));
563 h.numeric = mawk_num_id;
564 h.byteorder.s = 0x626F; /* bo in MSB */
565 h.filever = BIN_FILEVER;
566 h.inst_size = sizeof(INST);
567 h.num_size = sizeof(mawk_num_t);
568 memset(h.pad, 0, sizeof(h.pad));
569 write(fd, &h, sizeof(h));
570
571 /* prepare for linking */
572 memset(&l, 0, sizeof(l));
573
574 /* count functions */
575 num_func = 0;
576 for(fp = MAWK->fdump_list; fp != NULL; fp = fp->link)
577 num_func++;
578 if (num_func > 0) {
579 flen = malloc(sizeof(long int) * num_func);
580 fps = malloc(sizeof(struct mawk_fdump *) * num_func);
581 }
582 for(n = 0, fp = MAWK->fdump_list; fp != NULL; n++, fp = fp->link) {
583 fps[n] = fp;
584 }
585
586
587 /* fprintf(stderr, "Funcs: %d\n", num_func); */
588
589 begin_len = link_bin_sect(MAWK, MAWK->begin_start, &l);
590 /* fprintf(stderr, "BEGIN: total %d instructions\n", begin_len); */
591 end_len = link_bin_sect(MAWK, MAWK->end_start, &l);
592 /* fprintf(stderr, "END: total %d instructions\n", end_len); */
593 main_len = link_bin_sect(MAWK, MAWK->main_start, &l);
594 /* fprintf(stderr, "MAIN: total %d instructions\n", main_len); */
595
596 for(n = 0, fp = MAWK->fdump_list; fp != NULL; n++, fp = fp->link)
597 flen[n] = link_bin_sect(MAWK, fp->fbp->code, &l);
598
599 /* L1: save nums */
600 len = l.numsu;
601 write(fd, &len, 4);
602 write(fd, l.nums, sizeof(mawk_num_t) * l.numsu);
603 write(fd, &num_func, 4);
604
605 /* L2: save strings */
606 len = l.strsu;
607 write(fd, &len, 4);
608 for(n = 0; n < l.strsu; n++) {
609 len = safe_strlen(l.strs[n]);
610 write(fd, &len, 4);
611 if (len > 0)
612 write(fd, l.strs[n], len);
613 }
614
615 /* L3: save vars */
616 len = l.varsu;
617 write(fd, &len, 4);
618 for(n = 0; n < l.varsu; n++) {
619 const char *name;
620 SYMTAB *stp;
621
622 name = mawk_reverse_find(MAWK, l.vars[n].vtype, &(l.vars[n].cp));
623 if (name == mawk_reverse_uk) {
624 mawk_errmsg(MAWK, 0, "da_bin: Variable name lookup error");
625 return -1;
626 }
627 stp = mawk_find(MAWK, name, 0);
628
629 /* save types */
630 write(fd, &(l.vars[n].vtype), 2);
631 write(fd, &(stp->type), 1);
632
633 /* save name len and name*/
634 len = strlen(name);
635 write(fd, &len, 4);
636 write(fd, name, len);
637
638 /* save value len and content - empty for now */
639 len = 0;
640 write(fd, &len, 4);
641 }
642
643 /* L4: save begin/end/main sections */
644 save_bin_sect(MAWK, fd, write, MAWK->begin_start, begin_len);
645 save_bin_sect(MAWK, fd, write, MAWK->end_start, end_len);
646 save_bin_sect(MAWK, fd, write, MAWK->main_start, main_len);
647
648
649 /* L5: save user functions */
650
651 for(n = num_func-1; n >= 0; n--) {
652 int len;
653
654 fp = fps[n];
655 len = strlen(fp->fbp->name);
656 /* fprintf(stderr, "da_bin function %s/%d len=%d\n", fp->fbp->name, len,flen[n]); */
657 write(fd, &len, 4);
658 write(fd, fp->fbp->name, len);
659 /* fprintf(stderr, "NARGS=%d %d\n", fp->fbp->nargs, fp->fbp->typev[0]); */
660 write(fd, &fp->fbp->nargs, 2);
661 if (fp->fbp->nargs > 0)
662 write(fd, fp->fbp->typev, fp->fbp->nargs);
663 save_bin_sect(MAWK, fd, write, fp->fbp->code, flen[n]);
664 }
665 if (num_func > 0) {
666 free(flen);
667 free(fps);
668 }
669
670 link_free(&l);
671 return 0;
672 }
673 #endif
674
675 #ifndef MAWK_NO_EXEC
676 static int bin_load_func(mawk_state_t *MAWK, void *fd, int (*read)(void *fd, void *buff, size_t len), FBLOCK *fbp)
677 {
678 int len;
679 read(fd, &len, 4);
680 if (len > 0) {
681 if (len > BIN_CODE_MAXLEN)
682 return -1;
683
684 fbp->code = mawk_zmalloc(MAWK, len * sizeof(INST));
685 read(fd, fbp->code, len * sizeof(INST));
686 }
687 return 0;
688 }
689
690 static int bin_load_sect(mawk_state_t *MAWK, void *fd, int (*read)(void *fd, void *buff, size_t len), int scope)
691 {
692 int len;
693
694 read(fd, &len, 4);
695 if (len > 0) {
696 MAWK->scope = scope;
697 if ((scope == SCOPE_BEGIN) || (scope == SCOPE_END))
698 mawk_be_setup(MAWK, MAWK->scope);
699 mawk_code_reset_size(MAWK, len * sizeof(INST));
700 read(fd, MAWK->active_code.base, len * sizeof(INST));
701 MAWK->active_code.ptr = MAWK->active_code.base + len;
702 switch(scope) {
703 case SCOPE_BEGIN: *MAWK->begin_code_p = MAWK->active_code; break;
704 case SCOPE_END: *MAWK->end_code_p = MAWK->active_code; break;
705 case SCOPE_MAIN: *MAWK->main_code_p = MAWK->active_code; break;
706 /* avoid using default so later when scope is enum compiler can give warnings on missing scopes */
707 }
708 MAWK->active_code = *MAWK->main_code_p;
709 }
710 return 0;
711 }
712
713 static int bin_link_sect(mawk_state_t *MAWK, link_t *l, INST *blk, const char *sectname)
714 {
715 if (blk == NULL)
716 return 0;
717 if (mawk_da_bin(MAWK, blk, l, 0) == NULL) {
718 mawk_errmsg(MAWK, 0, "da_bin: Error: failed to link binary in section %s", sectname);
719 return 1;
720 }
721 return 0;
722 }
723
724
725 int mawk_load_code_bin_(mawk_state_t *MAWK, void *fd, int (*read)(void *fd, void *buff, size_t len))
726 {
727 SYMTAB *stp;
728 header_t h;
729 link_t l;
730 int n, num_func;
731 long int len;
732 int ret;
733
734 memset(&l, 0, sizeof(l));
735
736 /* read header */
737 chk_hdr_size(h);
738
739 read(fd, &h, sizeof(h));
740
741 ret = 0;
742 if (memcmp(h.f_id, f_id, sizeof(h.f_id)) != 0) {
743 mawk_errmsg(MAWK, 0, "da_bin: header ID mismatch");
744 ret = MAWK_EHDRSIZE;
745 goto err;
746 }
747 if (h.numeric != mawk_num_id) {
748 mawk_errmsg(MAWK, 0, "da_bin: magic mismatch");
749 ret = MAWK_EFILEMAGIC;
750 goto err;
751 }
752 if (h.byteorder.s != 0x626F) { /* bo in MSB */
753 mawk_errmsg(MAWK, 0, "da_bin: byte order mismatch");
754 ret = MAWK_EBYTEORDER;
755 goto err;
756 }
757 if (h.filever != BIN_FILEVER) {
758 mawk_errmsg(MAWK, 0, "da_bin: file version mismatch: produced by %d, can load %d", h.filever, BIN_FILEVER);
759 ret = MAWK_EVERSION;
760 goto err;
761 }
762 if (h.inst_size != sizeof(INST)) {
763 mawk_errmsg(MAWK, 0, "da_bin: instruction size mismatch: expected %d, got %d", sizeof(INST), h.inst_size);
764 ret = MAWK_EINSTSIZE;
765 goto err;
766 }
767 if (h.num_size != sizeof(mawk_num_t)) {
768 mawk_errmsg(MAWK, 0, "da_bin: numeric size mismatch: expected %d, got %d", sizeof(mawk_num_t), h.num_size);
769 ret = MAWK_ENUMSIZE;
770 goto err;
771 }
772
773 /* prepare for linking */
774 memset(&l, 0, sizeof(l));
775
776
777 /* L1: load nums */
778 read(fd, &len, 4);
779 l.numsa = l.numsu = len;
780 len = sizeof(*l.nums) * l.numsa;
781 if (len > BIN_MAXVARS)
782 goto err;
783 l.nums = malloc(len);
784 read(fd, l.nums, len);
785 read(fd, &num_func, 4);
786
787 /* L2: load strings */
788 read(fd, &len, 4);
789 l.strsa = l.strsu = len;
790 len = sizeof(*l.strs) * l.strsa;
791 if (len > BIN_MAXSTRS)
792 goto err;
793 l.strs = malloc(len);
794 for(n = 0; n < l.strsu; n++) {
795 char *name;
796
797 read(fd, &len, 4);
798 if (len > BIN_NAME_MAXLEN)
799 goto err;
800 if (len > 0) {
801 l.strs[n] = mawk_zmalloc(MAWK, len+1);
802 if (l.strs[n] == NULL) {
803 ret = MAWK_EALLOC;
804 goto err;
805 }
806 read(fd, (char *)l.strs[n], len);
807 name = (char *)l.strs[n];
808 name[len] = '\0';
809 }
810 else
811 l.strs[n] = NULL;
812 /* fprintf(stderr, "LOAD str: [%d] '%s'\n", n, l.strs[n]); */
813 }
814
815 /* L3: load vars */
816 read(fd, &len, 4);
817 l.varsa = l.varsu = len;
818 len = sizeof(*l.vars) * l.varsa;
819 if (l.varsa > BIN_MAXVARS)
820 goto err;
821 l.vars = malloc(len);
822 /* fprintf(stderr, "numvars: %d allocated=%d\n", l.varsu, len); */
823 for(n = 0; n < l.varsu; n++) {
824 char *name;
825 short type;
826 char stype;
827 /* load type */
828 read(fd, &type, 2);
829 read(fd, &stype, 1);
830
831 /* load name len and name*/
832 read(fd, &len, 4);
833 if (len > BIN_NAME_MAXLEN)
834 goto err;
835 name = mawk_zmalloc(MAWK, len+1);
836 read(fd, name, len);
837 name[len] = '\0';
838
839 /* go for existing vars first (because ARGV and builtins) */
840 l.vars[n].cp = mawk_get_var(MAWK, name);
841
842 if (l.vars[n].cp == NULL) {
843 if (type == ST_ARRAY) {
844 SYMTAB *stp;
845
846 stp = mawk_insert(MAWK, name);
847 stp->stval.array = mawk_array_new(MAWK, NULL);
848 stp->type = ST_ARRAY;
849 l.vars[n].cp = (mawk_cell_t *)stp->stval.array;
850 }
851 else {
852 l.vars[n].cp = mawk_create_var(MAWK, name, NULL);
853 if (l.vars[n].cp == NULL) {
854 mawk_errmsg(MAWK, 0, "da_bin: load error: can not create variable %s", name);
855 goto err;
856 }
857 }
858 }
859 l.vars[n].vtype = type;
860 stp = mawk_find(MAWK, name, 0);
861 if (stp->type != stype) {
862 mawk_errmsg(MAWK, 0, "da_bin warning: type of variable %s changed from %d to %d", name, stp->type, stype);
863 }
864 stp->type = stype;
865
866 /* fprintf(stderr, "LOAD var name='%s' type=%d len=%d: %d -> %p\n", name, type, len, n, l.vars[n].cp); */
867 /* load value len and content - empty for now */
868 read(fd, &len, 4);
869 if (len != 0) {
870 ret = MAWK_EWRONGVAL;
871 goto err2;
872 }
873 }
874
875
876 /* L4: load begin/end/main sections */
877 mawk_code_init(MAWK);
878 /* printf("D1: %p %p %p\n", MAWK->main_code_p, MAWK->begin_code_p, MAWK->end_code_p); */
879 if (bin_load_sect(MAWK, fd, read, SCOPE_BEGIN))
880 goto err;
881 if (bin_load_sect(MAWK, fd, read, SCOPE_END))
882 goto err;
883 if (bin_load_sect(MAWK, fd, read, SCOPE_MAIN))
884 goto err;
885
886 /* L5: load functions */
887 for(n = 0; n < num_func; n++) {
888 int len;
889 char *name;
890 FBLOCK *fbp;
891
892 read(fd, &len, 4);
893 /* fprintf(stderr, "LOAD function len=%d\n", len); */
894 if (len > BIN_NAME_MAXLEN)
895 goto err;
896 name = mawk_zmalloc(MAWK, len+1);
897 read(fd, name, len);
898 name[len] = '\0';
899 /* fprintf(stderr, "LOAD function name=%s\n", name); */
900 fbp = bin_new_funct(MAWK, name, 1);
901
902 read(fd, &fbp->nargs, 2);
903 /* fprintf(stderr, "LOAD nargs=%d\n", fbp->nargs); */
904 if (fbp->nargs > 0) {
905 fbp->typev = mawk_zmalloc(MAWK, fbp->nargs);
906 read(fd, fbp->typev, fbp->nargs);
907 }
908 else
909 fbp->typev = NULL;
910
911 bin_load_func(MAWK, fd, read, fbp);
912 if (mawk_da_bin(MAWK, fbp->code, &l, 0) == NULL) {
913 mawk_errmsg(MAWK, 0, "Can't link function %s", name);
914 goto err2;
915 }
916 }
917
918 mawk_set_code(MAWK);
919
920 if (bin_link_sect(MAWK, &l, MAWK->begin_start, "BEGIN"))
921 goto err;
922 if (bin_link_sect(MAWK, &l, MAWK->end_start, "END"))
923 goto err;
924 if (bin_link_sect(MAWK, &l, MAWK->main_start, "main"))
925 goto err;
926
927 goto out;
928 err2:;
929 err:;
930 out:;
931
932 link_free(&l);
933
934 return ret;
935 }
936 #endif
937
0 #ifndef DA_BIN_H
1 #define DA_BIN_H
2 #include "mawk.h"
3
4 /* load a precompiled script, using the provided read() on fd. Read will take
5 place sequentially, typically in small chunks */
6 int mawk_load_code_bin_(mawk_state_t *MAWK, void *fd, int (*read)(void *fd, void *buff, size_t len));
7
8 /* dump a precompiled script in binary form using the provided write() on fd.
9 Write will take place sequentially, in small chunks. */
10 int mawk_save_code_bin_(mawk_state_t * MAWK, void *fd, int (*write)(void *fd, const void *buff, size_t len));
11
12 #endif
0 /********************************************
1 libmawk (C) 2009-2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14
15 #include "da_bin.h"
16
17 static int bin_read(void *fd, void *buff, size_t size)
18 {
19 return read(*(int *)fd, buff, size);
20 }
21
22 int mawk_load_code_bin(mawk_state_t *MAWK, const char *fn)
23 {
24 int ret, fd;
25
26 fd = open(fn, O_RDONLY);
27 if (fd < 0)
28 return MAWK_ECANTOPEN;
29
30 ret = mawk_load_code_bin_(MAWK, &fd, bin_read);
31
32 close(fd);
33 return ret;
34 }
35
36 static int bin_write(void *fd, const void *buff, size_t size)
37 {
38 return write(*(int *)fd, buff, size);
39 }
40
41 int mawk_print_code_bin(mawk_state_t *MAWK, const char *fn)
42 {
43 int ret, fd;
44
45 fd = 1;
46 ret = mawk_save_code_bin_(MAWK, &fd, bin_write);
47 fsync(1);
48
49 return ret;
50 }
51
0 #ifndef DA_BIN_H
1 #define DA_BIN_H
2 #include "mawk.h"
3
4 /* Load precompiled binary script from a file */
5 int mawk_load_code_bin(mawk_state_t *MAWK, const char *fn);
6
7 /* Print precompiled binary from da to stdout */
8 int mawk_print_code_bin(mawk_state_t *MAWK, const char *fn);
9
10 #endif
0 /********************************************
1 da_common.c
2
3 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991, Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14
15 /* disassemble code: common for text and bin */
16
17 #include <string.h>
18 #include "mawk.h"
19
20
21 #include "code.h"
22 #include "bi_funct.h"
23 #include "repl.h"
24 #include "field.h"
25 #include "num.h"
26
27 static const struct {
28 PF_CP action;
29 char *name;
30 } special_cases[] = { /* read-only */
31 {mawk_bi_split, "split"},
32 {mawk_bi_match, "match"},
33 {mawk_bi_getline, "getline"},
34 {mawk_bi_sub, "sub"},
35 {mawk_bi_gsub, "gsub"},
36 {mawk_bi_print, "print"},
37 {mawk_bi_printf, "printf"},
38 {(PF_CP) 0, NULL}
39 };
40
41
42 const char *mawk_find_bi_name(PF_CP p)
43 {
44 const BI_REC *q;
45 int i;
46
47 for (q = mawk_bi_funct; q->name; q++) {
48 if (q->fp == p) {
49 /* found */
50 return q->name;
51 }
52 }
53 /* next check some special cases */
54 for (i = 0; special_cases[i].action; i++) {
55 if (special_cases[i].action == p)
56 return special_cases[i].name;
57 }
58
59 return "unknown builtin";
60 }
61
62 PF_CP mawk_find_bi_ptr(const char *name)
63 {
64 const BI_REC *q;
65 int i;
66
67 for (q = mawk_bi_funct; q->name; q++) {
68 if (strcmp(q->name, name) == 0) {
69 /* found */
70 return q->fp;
71 }
72 }
73 /* next check some special cases */
74 for (i = 0; special_cases[i].action; i++) {
75 if (strcmp(special_cases[i].name, name) == 0)
76 return special_cases[i].action;
77 }
78
79 return NULL;
80 }
81
82 void mawk_add_to_fdump_list(mawk_state_t *MAWK, FBLOCK *fbp)
83 {
84 struct mawk_fdump *p = MAWK_ZMALLOC(MAWK, struct mawk_fdump);
85 p->fbp = fbp;
86 p->link = MAWK->fdump_list;
87 MAWK->fdump_list = p;
88 }
0
1 /********************************************
2 da.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* disassemble code */
17
18 #include "mawk.h"
19 #include <stdio.h>
20
21 #include "code.h"
22 #include "bi_funct.h"
23 #include "repl.h"
24 #include "field.h"
25 #include "num.h"
26 #include "f2d.h"
27
28 static const struct sc {
29 char op;
30 char *name;
31 } simple_code[] = { /* read-only */
32 {_RANGE_STOP,"range_stop"},
33 {FE_PUSHA, "fe_pusha"},
34 {FE_PUSHI, "fe_pushi"},
35 {A_TEST, "a_test"},
36 {A_DEL, "a_del"},
37 {DEL_A, "del_a"},
38 {POP_AL, "pop_al"},
39 {_POP, "pop"},
40 {_ADD, "add"},
41 {_SUB, "sub"},
42 {_MUL, "mul"},
43 {_DIV, "div"},
44 {_MOD, "mod"},
45 {_POW, "pow"},
46 {_NOT, "not"},
47 {_UMINUS, "uminus"},
48 {_UPLUS, "uplus"},
49 {_TEST, "mawk_test"},
50 {_CAT, "cat"},
51 {_ASSIGN, "assign"},
52 {_ADD_ASG, "add_asg"},
53 {_SUB_ASG, "sub_asg"},
54 {_MUL_ASG, "mul_asg"},
55 {_DIV_ASG, "div_asg"},
56 {_MOD_ASG, "mod_asg"},
57 {_POW_ASG, "pow_asg"},
58 {NF_PUSHI, "nf_pushi"},
59 {F_ASSIGN, "f_assign"},
60 {F_ADD_ASG, "f_add_asg"},
61 {F_SUB_ASG, "f_sub_asg"},
62 {F_MUL_ASG, "f_mul_asg"},
63 {F_DIV_ASG, "f_div_asg"},
64 {F_MOD_ASG, "f_mod_asg"},
65 {F_POW_ASG, "f_pow_asg"},
66 {_POST_INC, "post_inc"},
67 {_POST_DEC, "post_dec"},
68 {_PRE_INC, "pre_inc"},
69 {_PRE_DEC, "pre_dec"},
70 {F_POST_INC, "f_post_inc"},
71 {F_POST_DEC, "f_post_dec"},
72 {F_PRE_INC, "f_pre_inc"},
73 {F_PRE_DEC, "f_pre_dec"},
74 {_EQ, "eq"},
75 {_NEQ, "neq"},
76 {_LT, "lt"},
77 {_LTE, "lte"},
78 {_GT, "gt"},
79 {_GTE, "gte"},
80 {_MATCH2, "match2"},
81 {_EXIT, "exit"},
82 {_EXIT0, "exit0"},
83 {_NEXT, "next"},
84 {_RET, "ret"},
85 {_RET0, "ret0"},
86 {_OMAIN, "omain"},
87 {_JMAIN, "jmain"},
88 {OL_GL, "ol_gl"},
89 {OL_GL_NR, "ol_gl_nr"},
90 {_ASSIGN_ARR, "assign_arr"},
91 {_ADD_ASG_ARR, "add_asg_arr"},
92 {_SUB_ASG_ARR, "sub_asg_arr"},
93 {_MUL_ASG_ARR, "mul_asg_arr"},
94 {_DIV_ASG_ARR, "div_asg_arr"},
95 {_MOD_ASG_ARR, "mod_asg_arr"},
96 {_POW_ASG_ARR, "pow_asg_arr"},
97 {_POST_INC_ARR, "post_inc_arr"},
98 {_POST_DEC_ARR, "post_dec_arr"},
99 {_PRE_INC_ARR, "pre_inc_arr"},
100 {_PRE_DEC_ARR, "pre_dec_arr"},
101 {_HALT, NULL}
102 };
103
104 static const char *jfmt = "%s%s%03d\n"; /* read-only */
105 /* format to print jumps */
106 static const char *tab2 = "\t\t"; /* read-only */
107
108 void mawk_da(mawk_state_t *MAWK, INST *start, void *fp_)
109 {
110 mawk_cell_t *cp;
111 FILE *fp = fp_;
112 register INST *p = start;
113 const char *name;
114
115 while (p->op != _HALT) {
116 /* print the relative code address (label) */
117 fprintf(fp, "%03d ", p - start);
118
119 switch (p++->op) {
120
121 case _PUSHC:
122 cp = (mawk_cell_t *) p++->ptr;
123 switch (cp->type) {
124 case C_RE:
125 fprintf(fp, "pushc\t<<%p>>\t/%s/\n", cp->ptr, mawk_re_uncompile(MAWK, cp->ptr));
126 break;
127
128 case C_SPACE:
129 fprintf(fp, "pushc\tspace split\n");
130 break;
131
132 case C_SNULL:
133 fprintf(fp, "pushc\tnull split\n");
134 break;
135 case C_REPL:
136 fprintf(fp, "pushc\trepl\t%s\n", mawk_repl_uncompile(MAWK, cp));
137 break;
138 case C_REPLV:
139 fprintf(fp, "pushc\treplv\t%s\n", mawk_repl_uncompile(MAWK, cp));
140 break;
141
142 default:
143 fprintf(fp, "pushc\tWEIRD\n");;
144 break;
145 }
146 break;
147
148 case _PUSHD:
149 fprintf(fp, "pushd\t" NUM_FMT_DA "\n", *(mawk_num_t *) p++->ptr);
150 break;
151 case _PUSHS:
152 {
153 mawk_string_t *sval = (mawk_string_t *) p++->ptr;
154 fprintf(fp, "pushs\t\"%s\"\n", sval->str);
155 break;
156 }
157
158 case _MATCH0:
159 case _MATCH1:
160 fprintf(fp, "match%d\t<<%p>>\t/%s/\n", p[-1].op == _MATCH1, p->ptr, mawk_re_uncompile(MAWK, p->ptr));
161 p++;
162 break;
163
164 case _PUSHA:
165 fprintf(fp, "pusha\t%s\n", mawk_reverse_find(MAWK, ST_VAR, &p++->ptr));
166 break;
167
168 case _PUSHI:
169 cp = (mawk_cell_t *) p++->ptr;
170 if (cp == MAWK->field)
171 fprintf(fp, "pushi\t$0\n");
172 else if (cp == &MAWK->fs_shadow)
173 fprintf(fp, "pushi\t@fs_shadow\n");
174 else {
175 if (cp > MAWK_NF && cp <= LAST_PFIELD)
176 name = mawk_reverse_find(MAWK, ST_FIELD, &cp);
177 else
178 name = mawk_reverse_find(MAWK, ST_VAR, &cp);
179
180 fprintf(fp, "pushi\t%s\n", name);
181 }
182 break;
183
184 case L_PUSHA:
185 fprintf(fp, "l_pusha\t%ld\n", (long)p++->op);
186 break;
187
188 case L_PUSHI:
189 fprintf(fp, "l_pushi\t%ld\n", (long)p++->op);
190 break;
191
192 case LAE_PUSHI:
193 fprintf(fp, "lae_pushi\t%ld\n", (long)p++->op);
194 break;
195
196 case LAE_PUSHA:
197 fprintf(fp, "lae_pusha\t%ld\n", (long)p++->op);
198 break;
199
200 case LAE_PUSHA_WRARR:
201 fprintf(fp, "lae_pusha_wr\t%ld\n", (long)p++->op);
202 break;
203
204 case LA_PUSHA:
205 fprintf(fp, "la_pusha\t%ld\n", (long)p++->op);
206 break;
207
208 case F_PUSHA:
209 cp = (mawk_cell_t *) p++->ptr;
210 if (cp >= MAWK_NF && cp <= LAST_PFIELD)
211 fprintf(fp, "f_pusha\t%s\n", mawk_reverse_find(MAWK, ST_FIELD, &cp));
212 else
213 fprintf(fp, "f_pusha\t$%d\n", mawk_field_addr_to_index(MAWK, cp));
214 break;
215
216 case F_PUSHI:
217 p++;
218 fprintf(fp, "f_pushi\t$%ld\n", (long)p++->op);
219 break;
220
221 case AE_PUSHA:
222 fprintf(fp, "ae_pusha\t%s\n", mawk_reverse_find(MAWK, ST_ARRAY, &p++->ptr));
223 break;
224
225 case AE_PUSHA_WRARR:
226 fprintf(fp, "ae_pusha_wr\t%s\n", mawk_reverse_find(MAWK, ST_ARRAY, &p++->ptr));
227 break;
228
229 case AE_PUSHI:
230 fprintf(fp, "ae_pushi\t%s\n", mawk_reverse_find(MAWK, ST_ARRAY, &p++->ptr));
231 break;
232
233 case A_PUSHA:
234 fprintf(fp, "a_pusha\t%s\n", mawk_reverse_find(MAWK, ST_ARRAY, &p++->ptr));
235 break;
236
237 case _PUSHINT:
238 fprintf(fp, "pushint\t%ld\n", (long)p++->op);
239 break;
240
241 case _BUILTIN:
242 fprintf(fp, "%s\n", mawk_find_bi_name((PF_CP) mawk_d2f(p++->ptr)));
243 break;
244
245 case _PRINT:
246 fprintf(fp, "%s\n", (PF_CP) mawk_d2f(p++->ptr) == mawk_bi_printf ? "printf" : "print");
247 break;
248
249 case _JMP:
250 fprintf(fp, jfmt, "jmp", tab2, (p - start) + p->op);
251 p++;
252 break;
253
254 case _JNZ:
255 fprintf(fp, jfmt, "jnz", tab2, (p - start) + p->op);
256 p++;
257 break;
258
259 case _JZ:
260 fprintf(fp, jfmt, "jz", tab2, (p - start) + p->op);
261 p++;
262 break;
263
264 case _LJZ:
265 fprintf(fp, jfmt, "ljz", tab2, (p - start) + p->op);
266 p++;
267 break;
268
269 case _LJNZ:
270 fprintf(fp, jfmt, "ljnz", tab2 + 1, (p - start) + p->op);
271 p++;
272 break;
273
274 case SET_ALOOP:
275 fprintf(fp, "set_al\t%03d\n", p + p->op - start);
276 p++;
277 break;
278
279 case ALOOP:
280 fprintf(fp, "aloop\t%03ld\n", (long)(p - start + p->op));
281 p++;
282 break;
283
284 case A_CAT:
285 fprintf(fp, "a_cat\t%ld\n", (long)p++->op);
286 break;
287
288 case _CALL:
289 fprintf(fp, "call\t%s\t%ld\n", ((FBLOCK *) p->ptr)->name, (long)p[1].op);
290 p += 2;
291 break;
292
293 case _RANGE_CHK:
294 fprintf(fp, "range\t%03ld %03ld %03ld\n",
295 /* label for pat2, action, follow */
296 (long)(p - start + p[1].op), (long)(p - start + p[2].op), (long)(p - start + p[3].op));
297 p += 4;
298 break;
299
300 case LOCATION:
301 fprintf(fp, "(location)\t%ld\n", (long)p[0].op);
302 p++;
303 break;
304
305 default:
306 {
307 const struct sc *q = simple_code;
308 int k = (p - 1)->op;
309
310 while (q->op != _HALT && q->op != k)
311 q++;
312
313 if (q->op != _HALT)
314 fprintf(fp, "%s\n", q->name);
315 else
316 fprintf(fp, "bad instruction %d\n", k);
317 }
318 break;
319 }
320 }
321 fflush(fp);
322 }
323
324 int mawk_fdump(mawk_state_t * MAWK)
325 {
326 register struct mawk_fdump *p, *q = MAWK->fdump_list;
327 int dumped = 0;
328
329 while (q) {
330 p = q;
331 q = p->link;
332 if (dumped)
333 fprintf(stdout, "\n");
334 fprintf(stdout, "function %s\n", p->fbp->name);
335 mawk_da(MAWK, p->fbp->code, stdout);
336 dumped++;
337 }
338 return dumped;
339 }
340
341 static void mawk_symdump(mawk_state_t * MAWK, int verbose)
342 {
343 HASHNODE *p;
344 int i;
345 for (i = 0; i < HASH_PRIME; i++) {
346 p = MAWK->hash_table[i];
347 while (p) {
348 switch (p->symtab.type) {
349 case ST_NONE:
350 break;
351 case ST_VAR: fprintf(stdout, "%s var\n", p->symtab.name); break;
352 case ST_KEYWORD: if (verbose) fprintf(stdout, "%s keyword\n", p->symtab.name); break;
353 case ST_BUILTIN: if (verbose) fprintf(stdout, "%s builtin\n", p->symtab.name); break;
354 case ST_ARRAY: fprintf(stdout, "%s array\n", p->symtab.name); break;
355 case ST_FIELD: if (verbose) fprintf(stdout, "%s field\n", p->symtab.name); break;
356 case ST_FUNCT: if (verbose) fprintf(stdout, "%s funct\n", p->symtab.name); break;
357 case ST_NR: if (verbose) fprintf(stdout, "%s <NR>\n", p->symtab.name); break;
358 case ST_LENGTH: if (verbose) fprintf(stdout, "%s <length>\n", p->symtab.name); break;
359 case ST_LOCAL_NONE:
360 case ST_LOCAL_VAR:
361 case ST_LOCAL_ARRAY:
362 fprintf(stdout, "%s ?local?\n", p->symtab.name); break;
363 case ST_C_FUNCTION: if (verbose) fprintf(stdout, "%s C-function\n", p->symtab.name); break;
364 }
365 p = p->link;
366 }
367 }
368 }
369
370 void mawk_dump_code_text(mawk_state_t * MAWK)
371 {
372 int fdmp;
373
374 /* dumps all user functions */
375 fdmp = mawk_fdump(MAWK);
376
377 if (MAWK->begin_start) {
378 if (fdmp)
379 fprintf(stdout, "\n");
380 fprintf(stdout, "BEGIN\n");
381 mawk_da(MAWK, MAWK->begin_start, stdout);
382 fdmp++;
383 }
384
385 if (MAWK->main_start) {
386 if (fdmp)
387 fprintf(stdout, "\n");
388 fprintf(stdout, "MAIN\n");
389 mawk_da(MAWK, MAWK->main_start, stdout);
390 fdmp++;
391 }
392
393 if (MAWK->end_start) {
394 if (fdmp)
395 fprintf(stdout, "\n");
396 fprintf(stdout, "END\n");
397 mawk_da(MAWK, MAWK->end_start, stdout);
398 fdmp++;
399 }
400 }
401
402 void mawk_dump_sym_text(mawk_state_t * MAWK)
403 {
404 fprintf(stdout, "SYMBOLS (global)\n");
405 mawk_symdump(MAWK, 0);
406
407 (void)mawk_f2d(NULL); /* suppress compiler warning on unused func */
408 }
0 /********************************************
1 libmawk (C) 2009-2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9
10 #include <stdio.h>
11 #include "mawk.h"
12
13 /* static mawk_state_t *mawk_debugging = NULL; */
14
15 void mawk_breakpoint(mawk_state_t * MAWK)
16 {
17
18 }
19
20 void mawk_location_change(mawk_state_t * MAWK, int new_token_line)
21 {
22 MAWK->token_lineno = new_token_line;
23 /* mawk_debugging = MAWK; */
24 mawk_breakpoint(MAWK);
25 }
26
27 void mawk_debug_callstack_push(mawk_state_t * MAWK, FBLOCK * f)
28 {
29 mawk_debug_callstack_t *s;
30
31 /* printf("PUSH: %s\n", f->name); */
32 s = malloc(sizeof(mawk_debug_callstack_t));
33 s->f = f;
34 s->next = MAWK->debug_callstack;
35 MAWK->debug_callstack = s;
36 }
37
38 void mawk_debug_callstack_pop(mawk_state_t * MAWK)
39 {
40 mawk_debug_callstack_t *s = MAWK->debug_callstack;
41
42 if (s != NULL) {
43 MAWK->debug_callstack = MAWK->debug_callstack->next;
44 free(s);
45 }
46 }
47
48 void mawk_debug_where(mawk_state_t * MAWK)
49 {
50 mawk_debug_callstack_t *s;
51 int n;
52
53 printf("mawk call stack:\n");
54 for (n = 0, s = MAWK->debug_callstack; s != NULL; s = s->next, n++) {
55 printf(" #%d %s\n", n, s->f->name);
56 }
57 }
58
59 /* name code size nargs typev */
60 const FBLOCK mawk_debug_main = { "MAIN", NULL, 0, 0, "" };
61 const FBLOCK mawk_debug_begin = { "BEGIN", NULL, 0, 0, "" };
0 #include "mawk.h"
1
2 void mawk_location_change(mawk_state_t * MAWK, int new_token_line);
3 void mawk_debug_callstack_pop(mawk_state_t * MAWK);
4 void mawk_debug_callstack_push(mawk_state_t * MAWK, FBLOCK * f);
5
6 extern FBLOCK mawk_debug_main;
7 extern FBLOCK mawk_debug_begin;
0
1 /********************************************
2 error.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, 1992 Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include "conf.h"
17
18 #warning this should be gone:
19 #include <stdio.h>
20
21 #include "mawk.h"
22 #include "scan.h"
23 #include "bi_vars.h"
24 #include "vargs.h"
25 #include "zmalloc.h"
26 #include "memory.h"
27 #include "cell.h"
28
29 #ifndef EOF
30 #define EOF (-1)
31 #endif
32
33 static void rt_where(mawk_state_t *);
34 static char *type_to_str(mawk_state_t *, int);
35
36
37 static const char *strerrors[] = {
38 "succes",
39 "can not open file",
40 "internal error: header size mismatch",
41 "bad file magic",
42 "wrong byte order",
43 "version not supported",
44 "wrong instruction size",
45 "wrong numeric size",
46 "can not allocate memory",
47 NULL
48 };
49
50 const char *mawk_strerror(mawk_errno_t err)
51 {
52 if (err > 0)
53 return "Unknown error (positive)";
54 if (err < MAWK_Elast)
55 return "Unknown error (negative)";
56 return strerrors[-err];
57 }
58
59 #ifdef NO_VFPRINTF
60 #define vfprintf simple_vfprintf
61 #endif
62
63 /* generic error message with a hook into the system error
64 messages if errnum > 0 */
65
66 void mawk_errmsg VA_ALIST2(int, errnum, char *, format)
67 {
68 va_list args;
69
70 fprintf(stderr, "%s: ", MAWK->progname);
71 VA_START2(args, int, errnum, char *, format);
72 vfprintf(stderr, format, args);
73 va_end(args);
74
75 if (errnum > 0)
76 fprintf(stderr, " (%s)", strerror(errnum));
77
78 fprintf(stderr, "\n");
79 }
80
81 void mawk_compile_error VA_ALIST(const char *, format)
82 {
83 va_list args;
84 const char *s0, *s1;
85
86 /* with multiple program files put program name in
87 error message */
88 if (MAWK->ps.pfile_name) {
89 s0 = MAWK->ps.pfile_name;
90 s1 = ": ";
91 }
92 else {
93 s0 = s1 = "";
94 }
95
96 fprintf(stderr, "%s: %s%sline %u: ", MAWK->progname, s0, s1, MAWK->token_lineno);
97 VA_START(args, char *, format);
98 vfprintf(stderr, format, args);
99 va_end(args);
100 fprintf(stderr, "\n");
101 if (++(MAWK->compile_error_count) == MAX_COMPILE_ERRORS)
102 mawk_exit(MAWK, 2);
103 }
104
105 void mawk_rt_error VA_ALIST(const char *, format)
106 {
107 va_list args;
108
109 fprintf(stderr, "%s: run time error: ", MAWK->progname);
110 VA_START(args, char *, format);
111 vfprintf(stderr, format, args);
112 va_end(args);
113 putc('\n', stderr);
114 rt_where(MAWK);
115 MAWK->rt_exit_code = 2;
116 mawk_exit(MAWK, 2);
117 }
118
119
120 void mawk_bozo(MAWK, s)
121 mawk_state_t *MAWK;
122 char *s;
123 {
124 mawk_errmsg(MAWK, 0, "mawk_bozo: %s", s);
125 #ifdef CELLDEBUG
126 abort();
127 #endif
128 #ifdef DEBUG
129 abort();
130 #endif
131 mawk_exit(MAWK, 3);
132 }
133
134 void mawk_overflow(mawk_state_t *MAWK, char *s, unsigned size)
135 {
136 mawk_errmsg(MAWK, 0, "program limit exceeded: %s size=%u", s, size);
137 mawk_exit(MAWK, 2);
138 }
139
140
141 /* print as much as we know about where a rt error occured */
142
143 static void rt_where(mawk_state_t * MAWK)
144 {
145 if (FILENAME->type != C_STRING)
146 mawk_cast1_to_str(MAWK, FILENAME);
147
148 fprintf(stderr, "\tFILENAME=\"%s\" FNR=%u NR=%u\n", string(FILENAME)->str, MAWK->rt_fnr, MAWK->rt_nr);
149 }
150
151 /* run time */
152 void mawk_rt_overflow(mawk_state_t *MAWK, char *s, unsigned size)
153 {
154 mawk_errmsg(MAWK, 0, "program limit exceeded: %s size=%u", s, size);
155 rt_where(MAWK);
156 mawk_exit(MAWK, 2);
157 }
158
159 static char *type_to_str(mawk_state_t *MAWK, int type)
160 {
161 char *retval;
162
163 switch (type) {
164 case ST_VAR:
165 retval = "variable";
166 break;
167 case ST_ARRAY:
168 retval = "array";
169 break;
170 case ST_FUNCT:
171 retval = "function";
172 break;
173 case ST_LOCAL_VAR:
174 retval = "local variable";
175 break;
176 case ST_LOCAL_ARRAY:
177 retval = "local array";
178 break;
179 default:
180 mawk_bozo(MAWK, "type_to_str");
181 }
182 return retval;
183 }
184
185 /* emit an error message about a type clash */
186 void mawk_type_error(mawk_state_t *MAWK, SYMTAB *p)
187 {
188 mawk_compile_error(MAWK, "illegal reference to %s %s", type_to_str(MAWK, p->type), p->name);
189 }
190
191
192
193 #ifdef NO_VFPRINTF
194
195 /* a minimal vfprintf */
196 int simple_vfprintf(FILE *fp, char *format, va_list argp)
197 {
198 char *q, *p, *t;
199 int l_flag;
200 char xbuff[64];
201
202 q = format;
203 xbuff[0] = '%';
204
205 while (*q != 0) {
206 if (*q != '%') {
207 putc(*q, fp);
208 q++;
209 continue;
210 }
211
212 /* mark the start with p */
213 p = ++q;
214 t = xbuff + 1;
215
216 if (*q == '-')
217 *t++ = *q++;
218 while (scan_code[*(unsigned char *) q] == SC_DIGIT)
219 *t++ = *q++;
220 if (*q == '.') {
221 *t++ = *q++;
222 while (scan_code[*(unsigned char *) q] == SC_DIGIT)
223 *t++ = *q++;
224 }
225
226 if (*q == 'l') {
227 l_flag = 1;
228 *t++ = *q++;
229 }
230 else
231 l_flag = 0;
232
233
234 *t = *q++;
235 t[1] = 0;
236
237 switch (*t) {
238 case 'c':
239 case 'd':
240 case 'o':
241 case 'x':
242 case 'u':
243 if (l_flag)
244 fprintf(fp, xbuff, va_arg(argp, long));
245 else
246 fprintf(fp, xbuff, va_arg(argp, int));
247 break;
248
249 case 's':
250 fprintf(fp, xbuff, va_arg(argp, char *));
251 break;
252
253 #ifndef MAWK_NO_FLOAT
254 case 'g':
255 case 'f':
256 fprintf(fp, xbuff, va_arg(argp, double));
257 break;
258 #endif
259
260 default:
261 putc('%', fp);
262 q = p;
263 break;
264 }
265 }
266 return 0; /* shut up */
267 }
268
269 #endif /* USE_SIMPLE_VFPRINTF */
270
271
272 void mawk_set_errno(mawk_state_t * MAWK, const char *error)
273 {
274 mawk_cell_destroy(MAWK, ERRNO);
275 ERRNO->type = C_STRING;
276 ERRNO->ptr = (PTR) mawk_new_STRING(MAWK, error);
277 }
0 #!/usr/local/bin/mawk -f
1
2 # ct_length.awk
3 #
4 # replaces all length
5 # by length($0)
6 #
7
8
9 {
10
11 while ( i = index($0, "length") )
12 {
13 printf "%s" , substr($0,1, i+5) # ...length
14 $0 = substr($0,i+6)
15
16 if ( match($0, /^[ \t]*\(/) )
17 {
18 # its OK
19 printf "%s", substr($0, 1, RLENGTH)
20 $0 = substr($0, RLENGTH+1)
21 }
22 else # length alone
23 printf "($0)"
24
25 }
26 print
27 }
0
1 # parse a C declaration by recursive descent
2 # based on a C program in KR ANSI edition
3 #
4 # run on a C file it finds the declarations
5 #
6 # restrictions: one declaration per line
7 # doesn't understand struct {...}
8 # makes assumptions about type names
9 #
10 #
11 # some awks need double escapes on strings used as
12 # regular expressions. If not run on mawk, use gdecl.awk
13
14
15 ################################################
16 # lexical scanner -- gobble()
17 # input : string s -- treated as a regular expression
18 # gobble eats SPACE, then eats longest match of s off front
19 # of global variable line.
20 # Cuts the matched part off of line
21 #
22
23
24 function gobble(s, x)
25 {
26 sub( /^ /, "", line) # eat SPACE if any
27
28 # surround s with parenthesis to make sure ^ acts on the
29 # whole thing
30
31 match(line, "^" "(" s ")")
32 x = substr(line, 1, RLENGTH)
33 line = substr(line, RLENGTH+1)
34 return x
35 }
36
37
38 function ptr_to(n, x) # print "pointer to" , n times
39 { n = int(n)
40 if ( n <= 0 ) return ""
41 x = "pointer to" ; n--
42 while ( n-- ) x = x " pointer to"
43 return x
44 }
45
46
47 #recursively get a decl
48 # returns an english description of the declaration or
49 # "" if not a C declaration.
50
51 function decl( x, t, ptr_part)
52 {
53
54 x = gobble("[* ]+") # get list of *** ...
55 gsub(/ /, "", x) # remove all SPACES
56 ptr_part = ptr_to( length(x) )
57
58 # We expect to see either an identifier or '('
59 #
60
61 if ( gobble("\(") )
62 {
63 # this is the recursive descent part
64 # we expect to match a declaration and closing ')'
65 # If not return "" to indicate failure
66
67 if ( (x = decl()) == "" || gobble( "\)" ) == "" ) return ""
68
69 }
70 else # expecting an identifier
71 {
72 if ( (x = gobble(id)) == "" ) return ""
73 x = x ":"
74 }
75
76 # finally look for ()
77 # or [ opt_size ]
78
79 while ( 1 )
80 if ( gobble( funct_mark ) ) x = x " function returning"
81 else
82 if ( t = gobble( array_mark ) )
83 { gsub(/ /, "", t)
84 x = x " array" t " of"
85 }
86 else break
87
88
89 x = x " " ptr_part
90 return x
91 }
92
93
94 BEGIN { id = "[_A-Za-z][_A-Za-z0-9]*"
95 funct_mark = "\([ \t]*\)"
96 array_mark = "\[[ \t]*[_A-Za-z0-9]*[ \t]*\]"
97
98 # I've assumed types are keywords or all CAPS or end in _t
99 # Other conventions could be added.
100
101 type0 = "int|char|short|long|double|float|void"
102 type1 = "[_A-Z][_A-Z0-9]*" # types are CAPS
103 type2 = "[_A-Za-z][_A-Za-z0-9]*_t" # end in _t
104
105 types = "(" type0 "|" type1 "|" type2 ")"
106 }
107
108
109 {
110
111 gsub( "/\*([^*]|\*[^/])*(\*/|$)" , " ") # remove comments
112 gsub( /[ \t]+/, " ") # squeeze white space to a single space
113
114
115 line = $0
116
117 scope = gobble( "extern|static" )
118
119 if ( type = gobble("(struct|union|enum) ") )
120 type = type gobble(id) # get the tag
121 else
122 {
123
124 type = gobble("(un)?signed ") gobble( types )
125
126 }
127
128 if ( ! type ) next
129
130 if ( (x = decl()) && gobble( ";") )
131 {
132 x = x " " type
133 if ( scope ) x = x " (" scope ")"
134 gsub( / +/, " ", x) #
135 print x
136 }
137
138 }
139
140
141
142
0
1 # find include dependencies in C source
2 #
3 # mawk -f deps.awk C_source_files
4 # -- prints a dependency list suitable for make
5 # -- ignores #include < >
6 #
7
8
9 BEGIN { stack_index = 0 # stack[] holds the input files
10
11 for(i = 1 ; i < ARGC ; i++)
12 {
13 file = ARGV[i]
14 if ( file !~ /\.[cC]$/ ) continue # skip it
15 outfile = substr(file, 1, length(file)-2) ".o"
16
17 # INCLUDED[] stores the set of included files
18 # -- start with the empty set
19 for( j in INCLUDED ) delete INCLUDED[j]
20
21 while ( 1 )
22 {
23 if ( getline line < file <= 0 ) # no open or EOF
24 { close(file)
25 if ( stack_index == 0 ) break # empty stack
26 else
27 { file = stack[ stack_index-- ]
28 continue
29 }
30 }
31
32 if ( line ~ /^#include[ \t]+".*"/ )
33 {
34 split(line, X, "\"") # filename is in X[2]
35
36 if ( X[2] in INCLUDED ) # we've already included it
37 continue
38
39 #push current file
40 stack[ ++stack_index ] = file
41 INCLUDED[ file = X[2] ] = ""
42 }
43 } # end of while
44
45 # test if INCLUDED is empty
46 flag = 0 # on once the front is printed
47 for( j in INCLUDED )
48 if ( ! flag )
49 { printf "%s : %s" , outfile, j ; flag = 1 }
50 else printf " %s" , j
51
52 if ( flag ) print ""
53
54 }# end of loop over files in ARGV[i]
55
56 }
0
1
2 # eatc.awk
3 # another program to remove comments
4 #
5
6
7 { while( t = index($0 , "/*") )
8 {
9 printf "%s" , substr($0,1,t-1)
10 $0 = eat_comment( substr($0, t+2) )
11 }
12
13 print
14 }
15
16
17 function eat_comment(s, t)
18 {
19 #replace comment by one space
20 printf " "
21
22 while ( (t = index(s, "*/")) == 0 )
23 if ( getline s == 0 )
24 { # input error -- unterminated comment
25 system("/bin/sh -c 'echo unterminated comment' 1>&2")
26 exit 1
27 }
28
29 return substr(s,t+2)
30 }
31
0
1 # parse a C declaration by recursive descent
2 #
3 # decl.awk with extra escapes \
4
5 ################################################
6 ############################################
7
8
9 # lexical scanner -- gobble()
10 # input : string s -- treated as a regular expression
11 # gobble eats SPACE, then eats longest match of s off front
12 # of global variable line.
13 # Cuts the matched part off of line
14 #
15
16
17 function gobble(s, x)
18 {
19 sub( /^ /, "", line) # eat SPACE if any
20
21 # surround s with parenthesis to make sure ^ acts on the
22 # whole thing
23
24 match(line, "^" "(" s ")")
25 x = substr(line, 1, RLENGTH)
26 line = substr(line, RLENGTH+1)
27 return x
28 }
29
30
31 function ptr_to(n, x) # print "pointer to" , n times
32 { n = int(n)
33 if ( n <= 0 ) return ""
34 x = "pointer to" ; n--
35 while ( n-- ) x = x " pointer to"
36 return x
37 }
38
39
40 #recursively get a decl
41 # returns an english description of the declaration or
42 # "" if not a C declaration.
43
44 function decl( x, t, ptr_part)
45 {
46
47 x = gobble("[* ]+") # get list of *** ...
48 gsub(/ /, "", x) # remove all SPACES
49 ptr_part = ptr_to( length(x) )
50
51 # We expect to see either an identifier or '('
52 #
53
54 if ( gobble("\\(") )
55 {
56 # this is the recursive descent part
57 # we expect to match a declaration and closing ')'
58 # If not return "" to indicate failure
59
60 if ( (x = decl()) == "" || gobble( "\\)" ) == "" ) return ""
61
62 }
63 else # expecting an identifier
64 {
65 if ( (x = gobble(id)) == "" ) return ""
66 x = x ":"
67 }
68
69 # finally look for ()
70 # or [ opt_size ]
71
72 while ( 1 )
73 if ( gobble( funct_mark ) ) x = x " function returning"
74 else
75 if ( t = gobble( array_mark ) )
76 { gsub(/ /, "", t)
77 x = x " array" t " of"
78 }
79 else break
80
81
82 x = x " " ptr_part
83 return x
84 }
85
86
87 BEGIN { id = "[_A-Za-z][_A-Za-z0-9]*"
88 funct_mark = "\\([ \t]*\\)"
89 array_mark = "\\[[ \t]*[_A-Za-z0-9]*[ \t]*\\]"
90
91 # I've assumed types are keywords or all CAPS or end in _t
92 # Other conventions could be added.
93
94 type0 = "int|char|short|long|double|float|void"
95 type1 = "[_A-Z][_A-Z0-9]*" # types are CAPS
96 type2 = "[_A-Za-z][_A-Za-z0-9]*_t" # end in _t
97
98 types = "(" type0 "|" type1 "|" type2 ")"
99 }
100
101
102 {
103
104 gsub( /\/\*([^*]|\*[^\/])*(\*\/|$)/ , " ") # remove comments
105 gsub( /[ \t]+/, " ") # squeeze white space to a single space
106
107
108 line = $0
109
110 scope = gobble( "extern|static" )
111
112 if ( type = gobble("(struct|union|enum) ") )
113 type = type gobble(id) # get the tag
114 else
115 {
116
117 type = gobble("(un)?signed ") gobble( types )
118
119 }
120
121 if ( ! type ) next
122
123 if ( (x = decl()) && gobble( ";") )
124 {
125 x = x " " type
126 if ( scope ) x = x " (" scope ")"
127 gsub( / +/, " ", x) #
128 print x
129 }
130
131 }
132
133
134
135
0 #!/usr/local/bin/mawk -We
1 # edit the above to be the full pathname of 'mawk'
2 # @(#) hcal - v01.00.02 - Tue Feb 27 21:21:21 EST 1996
3 # @(#) prints a 3-month (highlighted) calendar centered on the target month
4 # @(#) may be edited for week to start with Sun or Mon & for local language
5 # @(#) to display a usage screen, execute: hcal -h
6 # NOTE: to edit, set ts=4 in 'vi' (or equivalent)
7 # to print, pipe through 'pr -t -e4'
8
9 # Using ideas from a KornShell script by Mikhail Kuperblum (mikhail@klm.com)
10 # Bob Stockler - bob@trebor.iglou.com - Sysop CompuServe SCOForum [75162,1612]
11
12 BEGIN {
13 # Local Edits:
14 PROG = "hcal" # Program name given to this script
15 # FMT = 0 # date format dd/mm/yyyy
16 # FMT1 = 0 # for weekdays ordered "Mo Tu We Th Fr Sa Su"
17 FMT = 1 # date format mm/dd/yyyy
18 FMT1 = 1 # for weekdays ordered "Su Mo Tu We Th Fr Sa"
19 # edit day & month names and abbreviations for local language names
20 Days[0] = "Mo Tu We Th Fr Sa Su"
21 Days[1] = "Su Mo Tu We Th Fr Sa"
22 MONTHS = "January February March April May June July August"
23 MONTHS = MONTHS " September October November December"
24 Months = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
25 # STDOUT = 0 # emulate SCO Unix 'cal' (NO highlighting)
26 STDOUT = 1 # default to highlight mode
27 MINUS = "-" # possible input date field delimiter
28 SLASH = "/" # possible input date field delimiter
29 DOT = "." # possible input date field delimiter
30 IDFD = "[" MINUS # make MINUS the first character in this series
31 IDFD = IDFD SLASH # so that it stands for itself in the RE
32 IDFD = IDFD DOT "]" # Input Date Field Delimiters RE
33 ODFD = SLASH # Output Date Field Delimiter (default)
34 DATE_FMT = "%.2d%s%.2d%s%.4d" # date format
35 ## this script presumes 'date' recognizes these arguments in these ways:
36 ## w - Day of the week - Sunday = 0
37 ## m - Month of year - 01 to 12
38 ## d - Day of month - 01 to 31
39 ## y Last 2 digits of year - 00 to 99
40 ## Y - Year (including century), as decimal numbers
41 ## j - Day of the year - 001 to 366 (Julian date)
42 ## T - Time as HH:MM:SS
43 ## X Current time, as defined by the locale
44 ## a - Abbreviated weekday - Sun to Sat
45 ## b - Abbreviated month name
46 ## Z - Timezone name, or no characters if no timezone exists
47 ## Command to get today's date information:
48 ## DATE = "/bin/date '+%w %m %d 19%y %j~%a %b %d %T %Z 19%y'"
49 ## For sunos4
50 ## DATE = DATE = "/bin/date '+%w %m %d 19%y %j~%a %h %d %T 19%y'"
51 DATE = "/bin/date '+%w %m %d %Y %j~%a %b %d %X %Z %Y'"
52 # End of Local Edits
53
54 INT_RE = "^[0-9]+$" # unsigned integer RE
55 S_INT_RE = "^[-+][0-9]+$" # signed integer RE
56 MNAM_RE = "^[A-Za-z]+$" # month name RE
57 YEAR_RE = "^[0-9]?[0-9]?[0-9]?[0-9]$"
58 DATE_RE = "^[0-9]?[0-9]" IDFD "[0-9]?[0-9]" IDFD "[0-9]?[0-9]?[0-9]?[0-9]$"
59 DAT1_RE = "^[0-9]?[0-9]" IDFD "[0-9]?[0-9]$"
60
61 split(Months,M_Name)
62 split("31 28 31 30 31 30 31 31 30 31 30 31",Mdays) ; Mdays[0] = 0
63
64 NUM_ARGS = ARGC - 1
65 if ( ARGV[1] == "-x" ) {
66 # standout mode switch
67 if ( STDOUT == 1 ) STDOUT = 0 ; else STDOUT = 1
68 ARG1 = ARGV[2] ; ARG2 = ARGV[3] ; NUM_ARGS -= 1
69 }
70 else if ( ARGV[1] ~ /^-[h?]$/ ) { HELP = 1 ; exit }
71 else { ARG1 = ARGV[1] ; ARG2 = ARGV[2] }
72
73 if ( STDOUT == 1 ) {
74 # get the terminal standout-start & standout-end control codes
75 so = ENVIRON["so"] ; if ( ! so ) "tput smso" | getline so
76 se = ENVIRON["se"] ; if ( ! se ) "tput rmso" | getline se
77 }
78
79 if ( NUM_ARGS == 0 ) {
80 # no arguments - print a calendar display centered on today
81 DEFAULT = 1
82 }
83 else if ( NUM_ARGS == 1 ) {
84 # one argument - may be a month name, date, year, or interval of days
85 if ( ARG1 ~ DATE_RE ) DATE1 = Fmt_Date(ARG1)
86 else if ( ARG1 ~ DAT1_RE ) DATE1 = ARG1
87 else if ( ARG1 ~ MNAM_RE ) { Get_Mnum() ; DATE1 = RMSO = ARG1 "/1" }
88 else if ( ARG1 ~ S_INT_RE ) INTERVAL = ARG1 + 0
89 else if ( ARG1 ~ INT_RE ) {
90 if ( ARG1 > 0 && ARG1 <= 9999 ) YEAR = ARG1 + 0
91 else if ( ARG1 > 9999 ) { ERR = 9 ; exit }
92 else { ERR = 7 ; exit }
93 }
94 else { ERR = 1 ; exit }
95 }
96 else if ( NUM_ARGS == 2 ) {
97 # two arguments, the second of which must be an integer
98 if ( ARG2 ~ INT_RE ) {
99 ARG2 = ARG2 + 0
100 if ( ARG2 < 1 ) { ERR = 7 ; exit }
101 else if ( ARG2 > 9999 ) { ERR = 9 ; exit }
102 }
103 else { ERR = 1 ; exit }
104 RMSO = 1
105 # the first may be a string or an integer
106 if ( ARG1 ~ INT_RE ) {
107 # a month number and a year
108 if ( ARG1 < 1 || ARG1 > 12 ) { ERR = 4 ; mm = ARG1 ; exit }
109 }
110 else if ( ARG1 ~ MNAM_RE ) {
111 Get_Mnum()
112 }
113 else { ERR = 6 ; exit }
114 DATE1 = ARG1 "/1/" ARG2
115 }
116 else { ERR = 2 ; exit }
117
118 if ( DEFAULT ) { Get_Now() }
119 else if ( INTERVAL ) {
120 Get_Now()
121 daynum = daynum + ( INTERVAL % 7 )
122 this_date = ""
123 DATE1 = Get_Date(INTERVAL,m,d,y,j)
124 split(DATE1,mdy,IDFD)
125 Mon[2] = mdy[1] + 0
126 today = mdy[2] + 0
127 Year[1] = Year[2] = Year[3] = mdy[3] + 0
128 }
129 else if ( DATE1 ) {
130 Get_Now()
131 if ( split(DATE1,mdy,IDFD) == 2 ) DATE1 = DATE1 "/" This_Year
132 Chk_Date(DATE1)
133 Mon[2] = mdy[1] + 0
134 today = mdy[2] + 0
135 Year[1] = Year[2] = Year[3] = mdy[3] + 0
136 DATE1 = sprintf( "%.2d/%.2d/%.4d", Mon[2], today, Year[2] )
137 INTERVAL = Get_Num(DATE1,m,d,y,j)
138 daynum = daynum + ( INTERVAL % 7 )
139 this_date = ""
140 }
141 else if ( YEAR ) {
142 so = se = ""
143 Get_Now()
144 Mon[2] = 2
145 today = 1
146 Year[1] = Year[2] = Year[3] = YEAR
147 DATE1 = sprintf( "%.2d/%.2d/%.4d", Mon[2], today, Year[2] )
148 INTERVAL = Get_Num(DATE1,m,d,y,j)
149 daynum = daynum + ( INTERVAL % 7 )
150 this_date = ""
151 }
152 else { ERR = 5 ; exit }
153
154 if ( Mon[2] != 1 ) Mon[1] = Mon[2] - 1
155 else { Mon[1] = 12 ; Year[1] -= 1 }
156 if ( Mon[2] != 12 ) Mon[3] = Mon[2] + 1
157 else { Mon[3] = 1 ; Year[3] += 1 }
158 if ( Mon[1] == 2 ) Leap(Year[1])
159 else if ( Mon[2] == 2 ) Leap(Year[2])
160 else if ( Mon[3] == 2 ) Leap(Year[3])
161
162 Start[2] = 7 - ( ( today - daynum ) % 7 )
163 Start[1] = 7 - ( ( Mdays[Mon[1]] - Start[2] ) % 7 )
164 Start[3] = ( Mdays[Mon[2]] + Start[2] ) % 7
165
166 if ( ! YEAR ) quarters = 1
167 else {
168 quarters = 4 ; s[3] = Start[3]
169 for (i=4;i<=12;i++) { s[i] = ( Mdays[i-1] + s[i-1] ) % 7 }
170 }
171 for ( quarter = 1 ; quarter <= quarters ; quarter++ ) {
172 if ( quarter > 1 ) {
173 delete cal
174 ll = 0 ; Mon[1] += 3 ; Mon[2] += 3 ; Mon[3] += 3
175 Start[1] = s[Mon[1]] ; Start[2] = s[Mon[2]] ; Start[3] = s[Mon[3]]
176 }
177 if ( Year[2] == 1752 && Mon[2] ~ /8|9|10/ ) Kludge_1752()
178 if ( ARG1 ) print "" ; else printf( "\n%s\n\n", this_date )
179 for (i=1;i<=3;i++) { while ( Start[i] >= 7 ) Start[i] -= 7 }
180 for (mm=1;mm<=3;mm++) { l = 1
181 if ( mm != 2 ) { So = Se = "" } else { So = so ; Se = se }
182 cal[mm SUBSEP l++] = sprintf( "%s %-4s%.4d %s ", \
183 So, M_Name[Mon[mm]], Year[mm], Se )
184 cal[mm SUBSEP l++] = sprintf( "%s%3s", Days[FMT1], "" )
185 j = k = 1
186 while ( j <= Mdays[Mon[mm]] ) {
187 line = ""
188 for (i=1;i<=7;i++) {
189 if ( Start[mm] > 0 || j > Mdays[Mon[mm]] ) {
190 date = "" ; Start[mm]-- }
191 else date = j++
192 if ( Year[mm] == 1752 && Mon[mm] == 9 && date == 3 ) {
193 date = 14 ; j = 15 }
194 if ( date == today && mm == 2 && ! RMSO ) {
195 So = so ; Se = se }
196 else { So = Se = "" }
197 line = sprintf( "%s%s%2s%s ", line, So, date, Se )
198 }
199 cal[mm SUBSEP l++] = sprintf( "%s ", line )
200 }
201 if ( l > ll ) ll = l
202 }
203 for (l=1;l<ll;l++) {
204 for (mm=1;mm<=3;mm++) {
205 if ( cal[mm SUBSEP l] != "" ) printf( cal[mm SUBSEP l] )
206 else printf( "%23s", "" )
207 if ( mm % 3 == 0 ) print ""
208 }
209 }
210 }
211 print
212 exit 0
213 }
214 END {
215 if ( ! HELP && ! ERR ) exit 0
216 if ( ERR ) {
217 for (i=1;i<ARGC;i++) { ARGS = ARGS sp ARGV[i] ; sp = " " }
218 if ( ERR == 1 ) msg = "Bad argument format or content:"
219 else if ( ERR == 2 ) msg = "Wrong argument count (" ARGC - 1 "):"
220 else if ( ERR == 3 ) msg = "Date before 01/01/0001 (" Get_Y1() "):"
221 else if ( ERR == 4 ) msg = "Bad month (" mm "):"
222 else if ( ERR == 5 ) msg = "Bad date (" dd "):"
223 else if ( ERR == 6 ) msg = "Impossible date:"
224 else if ( ERR == 7 ) msg = "The was no year 0000:"
225 else if ( ERR == 8 ) msg = "Non-unique month name (" ARG1 "):"
226 else if ( ERR == 9 ) msg = "Year greater than 9999:"
227 else msg = "Unknown error:"
228 HELP = 1 ; q = "\""
229 }
230 if ( HELP ) {
231 if ( FMT == 1 ) { fmt = "[m]m/[d]d[/yyyy]" ; range = "12/31/9999" }
232 else { fmt = "[d]d/[m]m[/yyyy]" ; range = "31/12/9999" }
233 if ( STDOUT == 0 ) n = " not " ; else n = " " ; sp = " "
234 u= "\n Usage: " PROG " [-x] [args]\n\n" sp
235 u=u "Prints a 3-month calendar centered on the target month.\n\n" sp
236 u=u "The default is" n "to highlight the target month (and date if\n" sp
237 u=u "appropriate); -x switches the default highlight behavior.\n" sp
238 u=u "With no arguments the target date defaults to today.\n\n" sp
239 u=u "Arguments may be a date in " fmt " format (where\n" sp
240 u=u "leading 0's are implied in all unfilled fields, defaulting\n" sp
241 u=u "to the current year if that field is omitted); a month and\n" sp
242 u=u "year (where month may be an integer or a month name, perhaps\n" sp
243 u=u "abbreviated, but sufficient to be unique); or the month name\n" sp
244 u=u "alone (which defaults to the current year); or a year alone\n" sp
245 u=u "(which prints a 12-month calendar for that year).\n\n" sp
246 u=u "A signed integer alone as an argument specifies the target\n" sp
247 u=u "date to be -n days before or +n days after the current date.\n\n" sp
248 u=u "Dates from 01/01/0001 to " range " are supported.\n"
249 usage = u
250 }
251 printf( "\n%s: %s %s%s%s\n", PROG, msg, q, ARGS, q ) >"/dev/tty"
252 print usage >"/dev/tty"
253 exit ERR
254 }
255
256 function Get_Now() {
257 # get the week, month, date & year numbers and the time-of-day
258 DATE | getline date
259 split(date,Date,"~")
260 split(Date[1],field)
261 daynum = field[1] + FMT1
262 m = field[2] ; This_Mon = Mon[2] = m + 0
263 d = field[3] ; This_Date = today = d + 0
264 y = This_Year = Year[1] = Year[2] = Year[3] = field[4]
265 j = julian = field[5] + 0
266 this_date = Date[2]
267 }
268
269 function Fmt_Date(date) {
270 # format dates as mm/dd/yyyy or dd/mm/yyyy
271 split(date,MorD_DorM_Y,IDFD)
272 if ( FMT == 1 ) { Dt_Fld1 = MorD_DorM_Y[1] ; Dt_Fld2 = MorD_DorM_Y[2] }
273 else { Dt_Fld1 = MorD_DorM_Y[2] ; Dt_Fld2 = MorD_DorM_Y[1] }
274 Dt_Fld3 = MorD_DorM_Y[3]
275 return sprintf( DATE_FMT, Dt_Fld1, ODFD, Dt_Fld2, ODFD, Dt_Fld3 )
276 }
277
278 function Kludge_1752() {
279 # kludge for September 1752 & the change to the Gregorian Calendar
280 Mdays[9] = 30
281 if ( Mon[2] == 9 ) {
282 Start[1] = Start[2] = 1 + FMT1 ; Start[3] = -1 + FMT1
283 }
284 else if ( Mon[2] == 8 ) {
285 Start[1] = 2 + FMT1 ; Start[2] = 5 + FMT1 ; Start[3] = 1 + FMT1
286 }
287 else if ( Mon[2] == 10 ) {
288 Start[1] = 1 + FMT1 ; Start[2] = -1 + FMT1 ; Start[3] = 3
289 }
290 }
291
292 function Get_Mnum() {
293 ARG1 = tolower(ARG1)
294 months = tolower(MONTHS)
295 split(months,month)
296 for (i=1;i<=12;i++) {
297 if ( index(month[i],ARG1) == 1 ) { ARG = i ; n++ }
298 }
299 if ( n == 1 ) ARG1 = ARG
300 else if ( n == 0 ) { ERR = 1 ; exit }
301 else { ERR = 8 ; exit }
302 }
303
304 function Get_Num(date,m,d,y,j) {
305 # get the number of days from one date to another date
306 NOW = y m d ; N = 0 ; M = m + 0 ; D = d + 0 ; Y = y + 0 ; J = j + 0
307 split(date,mdy,IDFD)
308 M2 = mdy[1] ; D2 = mdy[2] ; Y2 = mdy[3]
309 THEN = Y2 M2 D2 ; M2 = M2 + 0 ; D2 = D2 + 0 ; Y2 = Y2 + 0
310 Leap(Y2)
311 if ( M2 > 12 ) { ERR = 4 ; exit }
312 if ( D2 > Mdays[M2] && Y2 != 1752 && M2 != 9 ) { ERR = 5 ; exit }
313 if ( THEN ~ /^1752090[3-9]$|^1752091[0-3]$/ ) { ERR = 6 ; exit }
314 Leap(Y)
315 if ( THEN > NOW ) {
316 Ydays = Ydays - J + 1 ; mdays = Mdays[M] - D + 1
317 while ( Y < Y2 ) Next_Y()
318 while ( M < M2 ) Next_M()
319 while ( D < D2 ) Next_D()
320 N *= -1
321 }
322 else {
323 Ydays = J ; mdays = D
324 while ( Y > Y2 ) Prev_Y()
325 while ( M > M2 ) Prev_M()
326 if ( Y == 1752 && M == 9 && D == 19 ) D = 30
327 while ( D > D2 ) Prev_D()
328 }
329 return N
330 }
331
332 function Get_Date(n,m,d,y,j) {
333 # get the date a number of days before or after a date
334 N = n + 0 ; M = m + 0 ; D = d + 0 ; Y = y + 0 ; J = j + 0
335 if ( N != 0 ) {
336 Leap(Y)
337 if ( N > 0 ) {
338 Ydays = Ydays - J + 1 ; mdays = Mdays[M] - D + 1
339 while ( N >= Ydays ) { Next_Y() ; Leap(Y) }
340 while ( N >= ( ( mdays > 0 ) ? mdays : Mdays[M] ) ) { Next_M() }
341 while ( N > 0 ) Next_D()
342 }
343 else {
344 Ydays = J ; mdays = D ; N *= -1
345 while ( N >= Ydays ) { Prev_Y() ; Leap(Y) }
346 while ( N >= ( ( mdays > 0 ) ? mdays : Mdays[M] ) ) { Prev_M() }
347 if ( Y == 1752 && M == 9 && D == 19 ) D = 30
348 while ( N > 0 ) Prev_D()
349 }
350 if ( Y < 1 ) { ERR = 3 ; exit }
351 }
352 return M ODFD D ODFD Y
353 }
354
355 function Leap(YR) {
356 # adjust for Leap Years
357 if ( YR % 4 == 0 && ( YR % 100 != 0 || YR % 400 == 0 || YR < 1800 ) ) {
358 Ydays = 366 ; Mdays[2] = 29 }
359 else { Ydays = 365 ; Mdays[2] = 28 }
360 if ( YR != 1752 ) Mdays[9] = 30
361 else { Ydays = 355 ; Mdays[9] = 19 }
362 }
363
364 function Chk_Date(date) {
365 # check validity of input dates
366 split(date,mdy,IDFD)
367 mm = mdy[1] + 0 ; dd = mdy[2] + 0 ; yy = mdy[3] + 0
368 if ( mm == 2 ) Leap(yy)
369 if ( yy < 1 ) { ERR = 3 ; exit }
370 if ( mm < 1 || mm > 12 ) { ERR = 4 ; exit }
371 if ( dd < 1 || dd > Mdays[mm] ) { ERR = 5 ; exit }
372 }
373
374 # day counting functions for next or previous year, month and day
375 function Next_Y() {
376 N -= Ydays ; Y += 1 ; M = 1 ; D = 1 ; mdays = 0 ; Leap(Y)
377 }
378 function Next_M() {
379 if ( mdays != 0 ) N -= mdays ; else N -= Mdays[M]
380 M += 1 ; D = 1 ; mdays = 0
381 }
382 function Next_D() {
383 N -= 1 ; D += 1
384 if ( D > Mdays[M] ) { M += 1 ; D = 1 }
385 else if ( Y == 1752 && M == 9 && D == 2 ) D = 13
386 }
387 function Prev_Y() {
388 N -= Ydays ; Y -= 1 ; M = 12 ; D = 31 ; mdays = 0 ; Leap(Y)
389 }
390 function Prev_M() {
391 if ( mdays != 0 ) N -= mdays ; else N -= Mdays[M]
392 M -= 1 ; D = Mdays[M] ; mdays = 0
393 }
394 function Prev_D() {
395 N -= 1 ; D -= 1 ; if ( Y == 1752 && M == 9 && D == 13 ) D = 2
396 }
397
398 function Get_J(m,d,y) {
399 # get the Julian date for an input date
400 m = m + 0 ; d = d + 0 ; y = y + 0
401 Leap(y)
402 j = d
403 for (i=1;i<m;i++) j = j + Mdays[i]
404 return j
405 }
406
407 function Get_Y1() {
408 # get the number of days to day 1 for the help screen
409 if ( ! m ) {
410 if ( mm ) { m = mm ; d = dd ; y = yy }
411 else if ( M ) { m = M ; d = D ; y = Y }
412 }
413 if ( ! j ) Get_J()
414 return Get_Num("01/01/0001",m,d,y,j)
415 }
416
417
0 :
1 # @(#) hical - displays previous, current & next months - today highlighted
2 # @(#) an "internationalizationable" version of a 3-month 'cal' display, it
3 # @(#) may be edited for week to start with Sun or Mon & for local language
4
5 prog=/tmp/hical.$$ ; trap 'rm -f $prog ; trap 0 ; exit' 0 1 2 3 15
6
7 : ${so:=`tput smso`} ${se:=`tput rmso`}
8
9 # USER EDITS MAY BE REQUIRED for the arguments to the 'date' command
10 # the script presumes 'date' recognizes these arguments in these ways:
11 # w - Day of the week - Sunday = 0
12 # m - Month of year - 01 to 12
13 # d - Day of month - 01 to 31
14 # T - Time as HH:MM:SS
15 # Y - Year (including century), as decimal numbers
16 DATE_ARGS='%w %m %d %T 19%y'
17
18 # the 'awk' program file is written to a temporary file to avoid any
19 # "arg list too long" error messages, yet have all the code in one file
20 # observe when editing the program file that '\n' must be '\\n'
21 # NOTE: for the 'bash' shell on Linux, use 'echo -e' in the next line
22 echo '{
23 # USER EDITS MAY BE REQUIRED (for FMT, day & month names, and the time stuff)
24 # FMT = 0 # for weekdays ordered "Mo Tu We Th Fr Sa Su"
25 FMT = 1 # for weekdays ordered "Su Mo Tu We Th Fr Sa"
26 Header[0] = "Mo Tu We Th Fr Sa Su"
27 Header[1] = "Su Mo Tu We Th Fr Sa"
28 months = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
29 time_is = "The time is:" ; time_fmt = "%s %s %s %s\\n"
30 # NO MORE USER EDITS REQUIRED (I think!)
31 split(months,M_Name) ; split("31 28 31 30 31 30 31 31 30 31 30 31",M_Len)
32 daynum = $1 + FMT
33 Mon[2] = $2 + 0
34 today = $3 + 0
35 time = $4
36 Year[1] = Year[2] = Year[3] = $NF
37 if ( Mon[2] == 1 ) { Year[1] = Year[1] - 1 ; Mon[1] = 12 }
38 else { Mon[1] = Mon[2] - 1 }
39 if ( Mon[2] == 12 ) { Year[3] = Year[3] + 1 ; Mon[3] = 1 }
40 else { Mon[3] = Mon[2] + 1 }
41 if ( Year[2] % 4 == 0 && \
42 Year[2] % 100 != 0 || \
43 Year[2] % 400 == 0 ) M_Len[2] = 29
44 Start[2] = 7 - ( ( today - daynum ) % 7 )
45 Start[1] = 7 - ( ( M_Len[Mon[1]] - Start[2] ) % 7 )
46 Start[3] = ( M_Len[Mon[2]] + Start[2] ) % 7
47 for (i=1;i<=3;i++) { while ( Start[i] >= 7 ) Start[i] -= 7 }
48 for (mm=1;mm<=3;mm++) {
49 if ( Year[mm] != Year[mm-1] )
50 printf( "%s %s %s\\n", so, Year[mm], se )
51 if ( mm == 1 ) printf( "%s %s %s\\n", so, Header[FMT], se )
52 j = k = 1
53 while ( j <= M_Len[Mon[mm]] ) {
54 line = ""
55 for (i=1;i<=7;i++) {
56 if ( Start[mm] > 0 || j > M_Len[Mon[mm]] ) { date = "" ; Start[mm]-- }
57 else date = j++
58 if ( mm == 2 && date == today ) { So = so ; Se = se }
59 else { So = Se = "" }
60 line = sprintf( "%s%s%2s%s ", line, So, date, Se )
61 }
62 m1 = substr(M_Name[Mon[mm]],k++,1)
63 printf( "%s %1s %s %s%s %s\\n", so, m1, se, line, so, se )
64 }
65 }
66 printf( time_fmt, so, time_is, time, se )
67 }' >$prog
68
69 date +"$DATE_ARGS" | ${AWK:=mawk} -f $prog so=$so se=$se
70
71 exit 0
72
73 # EOF 'hical' - Tue Dec 19 19:19:19 EST 1994
74 # Bob Stockler - bob@trebor.iglou.com - CIS: 72726,452
0
1 # remove C comments from a list of files
2 # using a comment as the record separator
3 #
4 # this is trickier than I first thought
5 # The first version in .97-.9993 was wrong
6
7 BEGIN {
8 # RS is set to a comment (this is mildly tricky, I blew it here
9 RS = "/\*([^*]|\*+[^*/])*\*+/"
10 ORS = " "
11 getline hold
12 filename = FILENAME
13 }
14
15 # if changing files
16 filename != FILENAME {
17 filename = FILENAME
18 printf "%s" , hold
19 hold = $0
20 next
21 }
22
23 { # hold one record because we don't want ORS on the last
24 # record in each file
25 print hold
26 hold = $0
27 }
28
29 END { printf "%s", hold }
0
1 # primes.awk
2 #
3 # mawk -f primes.awk [START] STOP
4 # find all primes between 2 and STOP
5 # or START and STOP
6 #
7
8
9
10 function usage()
11 { ustr = sprintf("usage: %s [start] stop", ARGV[0])
12 system( "echo " ustr)
13 exit 1
14 }
15
16
17 BEGIN { if (ARGC == 1 || ARGC > 3 ) usage()
18 if ( ARGC == 2 ) { start = 2 ; stop = ARGV[1]+0 }
19 else
20 if ( ARGC == 3 ) { start = ARGV[1]+0 ; stop = ARGV[2]+0 }
21
22 if ( start < 2 ) start = 2
23 if ( stop < start ) stop = start
24
25 prime[ p_cnt = 1 ] = 3 # keep primes in prime[]
26
27 # keep track of integer part of square root by adding
28 # odd integers
29 odd = test = 5
30 root = 2
31 squares = 9
32
33
34 while ( test <= stop )
35 {
36 if ( test >= squares )
37 { root++
38 odd += 2
39 squares += odd
40 }
41
42 flag = 1
43 for ( i = 1 ; prime[i] <= root ; i++ )
44 if ( test % prime[i] == 0 ) # not prime
45 { flag = 0 ; break }
46
47 if ( flag ) prime[ ++p_cnt ] = test
48
49 test += 2
50 }
51
52 prime[0] = 2
53
54 for( i = 0 ; prime[i] < start ; i++) ;
55
56 for ( ; i <= p_cnt ; i++ ) print prime[i]
57
58 }
59
60
61
0
1
2 # qsort text files
3 #
4
5 function middle(x,y,z) #return middle of 3
6 {
7 if ( x <= y )
8 { if ( z >= y ) return y
9 if ( z < x ) return x
10 return z
11 }
12
13 if ( z >= x ) return x
14 if ( z < y ) return y
15 return z
16 }
17
18
19 function isort(A , n, i, j, hold)
20 {
21 # if needed a sentinal at A[0] will be created
22
23 for( i = 2 ; i <= n ; i++)
24 {
25 hold = A[ j = i ]
26 while ( A[j-1] > hold )
27 { j-- ; A[j+1] = A[j] }
28
29 A[j] = hold
30 }
31 }
32
33
34 # recursive quicksort
35 function qsort(A, left, right ,i , j, pivot, hold)
36 {
37
38 pivot = middle(A[left], A[int((left+right)/2)], A[right])
39
40 i = left
41 j = right
42
43 while ( i <= j )
44 {
45 while ( A[i] < pivot ) i++
46 while ( A[j] > pivot ) j--
47
48 if ( i <= j )
49 { hold = A[i]
50 A[i++] = A[j]
51 A[j--] = hold
52 }
53 }
54
55 if ( j - left > BLOCK ) qsort(A,left,j)
56 if ( right - i > BLOCK ) qsort(A,i,right)
57 }
58
59 BEGIN { BLOCK = 5 }
60
61
62 { line[NR] = $0 "" # sort as string
63 }
64
65 END {
66
67 if ( NR > BLOCK ) qsort(line, 1, NR)
68
69 isort(line, NR)
70
71 for(i = 1 ; i <= NR ; i++) print line[i]
72 }
73
74
75
76
77
0 /********************************************
1 mawk_execute.c
2
3 libmawk changes (C) 2009-2014, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991-1996, Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14
15 #include "mawk.h"
16 #include "code.h"
17 #include "memory.h"
18 #include "symtype.h"
19 #include "field.h"
20 #include "bi_funct.h"
21 #include "bi_vars.h"
22 #include "regexp.h"
23 #include "repl.h"
24 #include "fin.h"
25 #include "debug.h"
26 #include <string.h>
27 #include "num.h"
28 #include "math_wrap.h"
29 #include "cell.h"
30 #include "execute.h"
31 #include "f2d.h"
32
33
34 static double compare(mawk_state_t *, mawk_cell_t *);
35 static int d_to_index(mawk_state_t *, mawk_num_t);
36
37
38 /* The stack machine that mawk_executes the code */
39
40 #ifdef DEBUG
41 void DB_mawk_eval_overflow(mawk_state_t * MAWK)
42 {
43 mawk_overflow(MAWK, "eval stack", EVAL_STACK_SIZE);
44 }
45 #endif
46
47 /* holds info for array loops (on a stack) */
48 typedef struct aloop_state {
49 struct aloop_state *link;
50 mawk_cell_t *var; /* for(var in A) */
51 mawk_string_t **base;
52 mawk_string_t **ptr;
53 mawk_string_t **limit;
54 } ALOOP_STATE;
55
56 /* clean up aloop stack on next, return, exit */
57 #define CLEAR_ALOOP_STACK() if(aloop_state){\
58 clear_aloop_stack(MAWK, aloop_state);\
59 aloop_state=(ALOOP_STATE*)0;}else
60
61 /* free the vector (aloop_state's ->base array and its members) */
62 static void aloop_free_vect(mawk_state_t *MAWK, ALOOP_STATE *top)
63 {
64 while (top->ptr < top->limit) {
65 free_STRING(*top->ptr);
66 top->ptr++;
67 }
68
69 if (top->base != NULL)
70 mawk_free(MAWK, top->base);
71 }
72
73
74 static void clear_aloop_stack(mawk_state_t *MAWK, ALOOP_STATE *top)
75 {
76 ALOOP_STATE *q;
77 do {
78 aloop_free_vect(MAWK, top);
79 q = top;
80 top = q->link;
81 MAWK_ZFREE(MAWK, q);
82 } while (top);
83 }
84
85 mawk_cell_t *mawk_call_c_func(mawk_state_t * MAWK, mawk_cell_t * sp, FBLOCK * fbp, int a_args)
86 {
87 /* unresolved functions must be C function calls */
88 if (fbp->code == NULL) {
89 SYMTAB *sym;
90 void *old_userdata;
91
92 sym = mawk_find(MAWK, fbp->name, 1);
93 if (sym->type == ST_C_FUNCTION) {
94 libmawk_c_function *old_func;
95
96 sp[1].type = ST_NONE;
97 old_userdata = MAWK->func_userdata;
98 old_func = MAWK->func_being_called;
99 MAWK->func_userdata = sym->stval.c_function.func_userdata;
100 MAWK->func_being_called = sym->stval.c_function.callback;
101 sp = sym->stval.c_function.callback(MAWK, sp, a_args) + 1;
102 MAWK->func_userdata = old_userdata;
103 MAWK->func_being_called = old_func;
104 }
105 else {
106 mawk_rt_error(MAWK, "unresolved function call %s\n", fbp->name);
107 }
108 return sp;
109 }
110 return NULL;
111 }
112
113 #define comment(s)
114
115 #define mawk_call_vars \
116 mawk_cell_t *nfp = sp - a_args + 1; comment("new fp for callee") \
117 mawk_cell_t *local_p = sp + 1 comment("first local argument on stack") \
118
119 #define mawk_call_pre() \
120 do { \
121 char *type_p; comment("pts to type of an argument") \
122 int t; \
123 if (fbp->nargs) \
124 type_p = fbp->typev + a_args - 1; \
125 comment("create space for locals");\
126 comment("t is number of locals"); \
127 t = fbp->nargs - a_args; \
128 while (t > 0) { \
129 t--; \
130 sp++; \
131 type_p++; \
132 sp->type = C_NOINIT; \
133 if (*type_p == ST_LOCAL_ARRAY) \
134 sp->ptr = (PTR) mawk_array_new(MAWK, NULL); \
135 } \
136 if (MAWK->debug_symbols) \
137 mawk_debug_callstack_push(MAWK, fbp); \
138 } while(0)
139
140 #define mawk_call_post(fbp, a_args_) \
141 do { \
142 int a_args = a_args_; \
143 mawk_call_vars; \
144 char *type_p; comment("pts to type of an argument"); \
145 if (fbp->nargs) \
146 type_p = fbp->typev + a_args - 1; \
147 if (MAWK->debug_symbols) \
148 mawk_debug_callstack_pop(MAWK); \
149 comment("cleanup the callee's arguments"); \
150 comment("putting return value at top of eval stack"); \
151 if (sp >= nfp) { \
152 mawk_cell_t *cp; \
153 comment("cp -> the function return"); \
154 cp = sp + 1; \
155 do { \
156 if (*type_p == ST_LOCAL_ARRAY) { \
157 if (sp >= local_p) { \
158 mawk_array_clear(MAWK, (mawk_array_t)(sp->ptr)); \
159 MAWK_ZFREE(MAWK, (mawk_array_t) sp->ptr); \
160 } \
161 } \
162 else \
163 mawk_cell_destroy(MAWK, sp); \
164 type_p--; \
165 sp--; \
166 } \
167 while (sp >= nfp); \
168 break; \
169 mawk_cellcpy(MAWK, ++sp, cp); \
170 mawk_cell_destroy(MAWK, cp); \
171 } \
172 else {\
173 comment("no arguments passed"); \
174 sp++; \
175 } \
176 } while(0)
177
178 /******************* mawk_execute: the VM ********************/
179
180 enum {
181 EXEST_NORMAL, /* don't do anything special when popping this frame */
182 EXEST_EXIT, /* exit when popping this frame */
183 EXEST_RANGE1, /* frame was the pat1 match code for a range */
184 EXEST_RANGE2 /* frame was the pat1 match code for a range */
185 };
186
187 #include "execute_debug.h"
188
189 /* cast cp to num and copy the value of the num to res_num (which is mawk_num_t) */
190 #define mawk_cast_get_num(res_num, cp) \
191 do { \
192 if (cp->type != C_NUM) \
193 mawk_cast1_to_num(MAWK, cp); \
194 res_num = cp->d.dval; \
195 } while(0)
196
197 #define RECURSION_OVERHEAD 8
198
199 #define mawk_push_exe_state(exest) \
200 do { \
201 inc_sp(); sp->type = C_EXE_STTYPE; sp->d.vcnt = exest; \
202 inc_sp(); sp->type = C_EXE_STATE; sp->ptr = cdp; \
203 inc_sp(); sp->type = C_EXE_STATE; sp->ptr = fp; \
204 inc_sp(); sp->type = C_EXE_STATE; sp->ptr = aloop_state; \
205 inc_sp(); sp->type = C_EXE_STATE; sp->ptr = old_stack_base; \
206 inc_sp(); sp->type = C_EXE_STATE; sp->ptr = old_sp; \
207 inc_sp(); sp->type = C_EXE_STATE; sp->ptr = call_fbp; \
208 inc_sp(); sp->type = C_EXE_STATE; sp->d.vcnt = call_a_args; \
209 db1printf("state push sp=%d..%d\n", stackptr(sp - RECURSION_OVERHEAD+1), stackptr(sp)); \
210 } while(0)
211
212 #define mawk_pop_exe_state()\
213 do { \
214 if ((sp[1-RECURSION_OVERHEAD].type != C_EXE_STTYPE) || (sp[0].type != C_EXE_STATE)) \
215 mawk_bozo(MAWK, "eval stack broken (in recursion)"); \
216 exest = sp[-7].d.vcnt; \
217 cdp = sp[-6].ptr; \
218 fp = sp[-5].ptr; \
219 aloop_state = sp[-4].ptr; \
220 old_stack_base = sp[-3].ptr; \
221 old_sp = sp[-2].ptr; \
222 call_fbp = sp[-1].ptr; \
223 call_a_args = sp[0].d.vcnt; \
224 db1printf("state pop sp=%d..%d exest=%d\n", stackptr(sp - RECURSION_OVERHEAD+1), stackptr(sp), exest); \
225 sp -= RECURSION_OVERHEAD; \
226 } while(0)
227
228 mawk_exec_result_t mawk_execute_(mawk_state_t *MAWK)
229 {
230 /* --- some useful temporaries (not saved on the eval stack during recursion) --- */
231 mawk_cell_t *cp;
232 int t;
233 double dt;
234 mawk_num_t tmp_num;
235 unsigned long runcount;
236
237 #ifdef DEBUG
238 mawk_cell_t *entry_sp = sp;
239 #endif
240
241
242 /* --- execution state (saved on evan stack during recursion) --- */
243 register INST *cdp; /* code ptr, continue execution here */
244 register mawk_cell_t *sp; /* eval_stack pointer */
245 mawk_cell_t *fp = 0; /* frame ptr into eval_stack for user defined functions */
246
247 FBLOCK *call_fbp = NULL; /* user function being executed */
248 int call_a_args = 0; /* number of caller args in user func being executed */
249
250 ALOOP_STATE *aloop_state = (ALOOP_STATE *) 0; /* save state for array loops via a stack */
251 mawk_cell_t *old_stack_base, *old_sp; /* for moving the eval stack on deep recursion */
252 int exest = 0;
253
254 sp = MAWK->sp;
255
256 db1printf("exe enter sp=%d\n", stackptr(sp));
257 exe_return:;
258 db1printf("exe_return sp=%d fp=%d\n", stackptr(sp), stackptr(fp));
259 db1printstack(MAWK, "exe_return:\n", sp, fp);
260 mawk_pop_exe_state();
261 if (exest == EXEST_EXIT) {
262 /* hit the bottom of current execution request; mawk_execute_ either
263 returns from here because normal end-of-execution or from a getline
264 that got "NO_MORE" */
265 goto out;
266 }
267
268 call_entry:;
269 if (fp) {
270 /* we are a function call, check for deep recursion */
271 if (sp > MAWK->stack_danger) { /* change stacks */
272 /* it's enough to save one set of stack_base and sp here; by the next time
273 we get in the danger zone the old values are already saved on the stack by
274 mawk_push_exe_state(exest) */
275 old_stack_base = MAWK->stack_base;
276 old_sp = sp;
277 MAWK->stack_base = (mawk_cell_t *) mawk_zmalloc(MAWK, sizeof(mawk_cell_t) * EVAL_STACK_SIZE);
278 MAWK->stack_danger = MAWK->stack_base + DANGER;
279 sp = MAWK->stack_base;
280 /* waste 1 slot for ANSI, actually large model msdos breaks in
281 RET if we don't */
282 #ifdef DEBUG
283 entry_sp = sp;
284 #endif
285 }
286 else
287 old_stack_base = (mawk_cell_t *) 0;
288 }
289
290 runcount = MAWK->runlimit;
291 while (MAWK->rt_exit_code == 0) {
292 runcount--;
293 if (runcount == 0)
294 goto out_runlimit;
295 switch (cdp++->op) {
296
297 /* HALT only used by the disassemble now ; this remains
298 so compilers don't offset the jump table */
299 case _HALT:
300 mawk_bozo(MAWK, "ran on halt");
301 goto out_exit;
302
303 case _PUSHC:
304 inc_sp();
305 mawk_cellcpy(MAWK, sp, cdp++->ptr);
306 break;
307 case _PUSHD:
308 inc_sp();
309 sp->type = C_NUM;
310 sp->d.dval = *(mawk_num_t *) cdp++->ptr;
311 break;
312
313 case _PUSHS:
314 inc_sp();
315 sp->type = C_STRING;
316 sp->ptr = cdp++->ptr;
317 string(sp)->ref_cnt++;
318 break;
319
320 case F_PUSHA:
321 cp = (mawk_cell_t *) cdp->ptr;
322 if (cp != MAWK->field) {
323 if (MAWK->nf < 0)
324 mawk_split_field0(MAWK);
325
326 if (!(cp >= MAWK_NF && cp <= LAST_PFIELD)) {
327 /* its a real field $1, $2 ...
328 If its greater than $NF, we have to
329 make sure its set to "" so that
330 (++|--) and g?sub() work right
331 */
332 t = mawk_field_addr_to_index(MAWK, cp);
333 if (t > MAWK->nf) {
334 mawk_cell_destroy(MAWK, cp);
335 cp->type = C_STRING;
336 cp->ptr = (PTR) & (MAWK->null_str);
337 MAWK->null_str.ref_cnt++;
338 }
339 }
340 }
341 /* fall thru */
342
343 case _PUSHA:
344 case A_PUSHA:
345 inc_sp();
346 sp->type = C_NOINIT; /* normal varref, not C_ARR_REF */
347 sp->ptr = cdp++->ptr;
348 break;
349
350 case _PUSHI:
351 /* put contents of next address on stack */
352 inc_sp();
353 mawk_cellcpy(MAWK, sp, cdp++->ptr);
354 break;
355
356 case L_PUSHI:
357 /* put the contents of a local var on stack,
358 cdp->op holds the offset from the frame pointer */
359 inc_sp();
360 db1printf("pushi fp=%d + %d\n", stackptr(fp), cdp->op);
361 mawk_cellcpy(MAWK, sp, fp + cdp++->op);
362 break;
363
364 case L_PUSHA:
365 /* put a local address on eval stack */
366 inc_sp();
367 sp->type = C_NOINIT; /* normal varref, not C_ARR_REF */
368 sp->ptr = (PTR) (fp + cdp++->op);
369 break;
370
371
372 case F_PUSHI:
373
374 /* push contents of $i
375 cdp[0] holds & $i , cdp[1] holds i */
376
377 inc_sp();
378 if (MAWK->nf < 0)
379 mawk_split_field0(MAWK);
380 cp = (mawk_cell_t *) cdp->ptr;
381 t = (cdp + 1)->op;
382 cdp += 2;
383
384 if (t <= MAWK->nf)
385 mawk_cellcpy(MAWK, sp, cp);
386 else { /* an unset field */
387
388 sp->type = C_STRING;
389 sp->ptr = (PTR) & (MAWK->null_str);
390 MAWK->null_str.ref_cnt++;
391 }
392 break;
393
394 case NF_PUSHI:
395
396 inc_sp();
397 if (MAWK->nf < 0)
398 mawk_split_field0(MAWK);
399 mawk_cellcpy(MAWK, sp, MAWK_NF);
400 break;
401
402 case FE_PUSHA:
403
404 if (sp->type != C_NUM)
405 mawk_cast1_to_num(MAWK, sp);
406
407 t = d_to_index(MAWK, sp->d.dval);
408 if (t && MAWK->nf < 0)
409 mawk_split_field0(MAWK);
410 sp->ptr = (PTR) field_ptr(t);
411 if (t > MAWK->nf) {
412 /* make sure its set to "" */
413 cp = (mawk_cell_t *) sp->ptr;
414 mawk_cell_destroy(MAWK, cp);
415 cp->type = C_STRING;
416 cp->ptr = (PTR) & (MAWK->null_str);
417 MAWK->null_str.ref_cnt++;
418 }
419 break;
420
421 case FE_PUSHI:
422
423 if (sp->type != C_NUM)
424 mawk_cast1_to_num(MAWK, sp);
425
426 t = d_to_index(MAWK, sp->d.dval);
427
428 if (MAWK->nf < 0)
429 mawk_split_field0(MAWK);
430 if (t <= MAWK->nf)
431 mawk_cellcpy(MAWK, sp, field_ptr(t));
432 else {
433 sp->type = C_STRING;
434 sp->ptr = (PTR) & MAWK->null_str;
435 MAWK->null_str.ref_cnt++;
436 }
437 break;
438
439
440 case AE_PUSHA: /* global lookup and push array mawk_cell_t */
441 /* top of stack has an expr, cdp->ptr points at an
442 array, replace the expr with the bifunct_target arr ref */
443 cp = MAWK_ZMALLOC(MAWK, mawk_cell_t);
444 mawk_cellcpy(MAWK, cp, sp);
445 mawk_cell_destroy(MAWK, sp);
446 sp->type = C_ARR_REF_BT;
447 sp->ptr = (PTR) (mawk_array_t)(cdp->ptr);
448 sp->d.idx_cell = cp;
449 cdp++;
450 break;
451
452 case AE_PUSHA_WRARR: /* global lookup and push array mawk_cell_t _ref_ for a later write */
453 {
454 /* idx in sp, push array ptr to sp+1 */
455 inc_sp();
456 sp->ptr = (mawk_array_t)(cdp->ptr);
457 cdp++;
458 sp->type = C_ARR_REF;
459 }
460 break;
461
462
463 case AE_PUSHI:
464 /* top of stack has an expr, cdp->ptr points at an
465 array, replace the expr with the contents of the
466 cell inside the array */
467
468 mawk_array_find(MAWK, (mawk_array_t)(cdp->ptr), sp, sp, MAWK_CREATE);
469 cdp++;
470 break;
471
472 case LAE_PUSHI:
473 /* sp[0] is an expression
474 cdp->op is offset from frame pointer of a mawk_cell_t which
475 has an mawk_array_t in the ptr field, replace expr
476 with array[expr]
477 */
478 mawk_array_find(MAWK, (mawk_array_t)(fp[cdp->op].ptr), sp, sp, MAWK_CREATE);
479 cdp++;
480 break;
481
482 case LAE_PUSHA: /* local array lookup and push array mawk_cell_t */
483 /* sp[0] is an expression
484 cdp->op is offset from frame pointer of a mawk_cell_t which
485 has an mawk_array_t in the ptr field, replace expr
486 with bifunct_target arr ref
487 */
488 cp = MAWK_ZMALLOC(MAWK, mawk_cell_t);
489 mawk_cellcpy(MAWK, cp, sp);
490 mawk_cell_destroy(MAWK, sp);
491 sp->type = C_ARR_REF_BT;
492 sp->ptr = (PTR) (mawk_array_t)(fp[cdp->op].ptr);
493 sp->d.idx_cell = cp;
494 cdp++;
495 break;
496 case LAE_PUSHA_WRARR: /* local array lookup and push array mawk_cell_t _ref_ for a later write */
497 {
498 /* idx in sp, push array ptr to sp+1 */
499 inc_sp();
500 sp->ptr = (mawk_array_t)(fp[cdp->op].ptr);
501 cdp++;
502 sp->type = C_ARR_REF;
503 }
504 break;
505
506
507 case LA_PUSHA:
508 /* cdp->op is offset from frame pointer of a mawk_cell_t which
509 has an mawk_array_t in the ptr field. Push this ARRAY
510 on the eval stack
511 */
512 inc_sp();
513 sp->type = C_NOINIT; /* normal varref, not C_ARR_REF */
514 sp->ptr = fp[cdp++->op].ptr;
515 break;
516
517 case SET_ALOOP:
518 {
519 ALOOP_STATE *ap = MAWK_ZMALLOC(MAWK, ALOOP_STATE);
520 unsigned vector_size;
521
522 ap->var = (mawk_cell_t *) sp[-1].ptr;
523 ap->base = ap->ptr = mawk_array_loop_vector(MAWK, (mawk_array_t)(sp->ptr), &vector_size);
524 ap->limit = ap->base + vector_size;
525 sp -= 2;
526
527 /* push onto aloop stack */
528 ap->link = aloop_state;
529 aloop_state = ap;
530 cdp += cdp->op;
531 }
532 break;
533
534 case ALOOP:
535 {
536 ALOOP_STATE *ap = aloop_state;
537 if (ap->ptr < ap->limit) {
538 mawk_cell_destroy(MAWK, ap->var);
539 ap->var->type = C_STRING;
540 ap->var->ptr = (PTR) * ap->ptr++;
541 cdp += cdp->op;
542 }
543 else
544 cdp++;
545 }
546 break;
547
548 case POP_AL:
549 {
550 /* finish up an array loop */
551 ALOOP_STATE *ap = aloop_state;
552 aloop_state = ap->link;
553 aloop_free_vect(MAWK, ap);
554 MAWK_ZFREE(MAWK, ap);
555 }
556 break;
557
558 case _POP:
559 mawk_cell_destroy(MAWK, sp);
560 sp--;
561 break;
562
563 case _ASSIGN:
564 /* top of stack has an expr, next down is an
565 address, put the expression in *address and
566 replace the address with the expression */
567
568 /* don't propagate type C_MBSTRN */
569 if (sp->type == C_MBSTRN)
570 mawk_check_strnum(MAWK, sp);
571 sp--;
572 mawk_cell_destroy(MAWK, ((mawk_cell_t *) sp->ptr));
573 mawk_cellcpy(MAWK, sp->ptr, sp + 1);
574 mawk_cellcpy(MAWK, sp, sp->ptr);
575 mawk_cell_destroy(MAWK, sp + 1);
576 break;
577
578 case _ASSIGN_ARR:
579 /* don't propagate type C_MBSTRN */
580 if (sp->type == C_MBSTRN)
581 mawk_check_strnum(MAWK, sp);
582 sp-=2;
583 /* sp is the index, sp+1 is the array ref and sp+2 is rvalue expr result */
584 mawk_array_set_execute(MAWK, sp, sp+1, sp, sp+2);
585 break;
586
587
588 case F_ASSIGN:
589 /* assign to a field */
590 if (sp->type == C_MBSTRN)
591 mawk_check_strnum(MAWK, sp);
592 sp--;
593 mawk_field_assign(MAWK, (mawk_cell_t *) sp->ptr, sp + 1);
594 mawk_cell_destroy(MAWK, sp + 1);
595 mawk_cellcpy(MAWK, sp, (mawk_cell_t *) sp->ptr);
596 break;
597
598 case _ADD_ASG:
599 if (sp->type != C_NUM)
600 mawk_cast1_to_num(MAWK, sp);
601 cp = (mawk_cell_t *) (sp - 1)->ptr;
602 if (cp->type != C_NUM)
603 mawk_cast1_to_num(MAWK, cp);
604 P_nansafe1(cp->d.dval, (cp->d.dval + sp->d.dval), sp->d.dval);
605 sp--;
606 sp->type = C_NUM;
607 sp->d.dval = cp->d.dval;
608 break;
609
610 case _ADD_ASG_ARR:
611 /* convert the expression result */
612 mawk_cast_get_num(tmp_num, sp);
613 sp-=2;
614 /* sp is the index, sp+1 is the array ref and sp+2 is rvalue expr result; after this sp+2 is the array val */
615 if (!mawk_array_pure(MAWK, sp+1, 1)) {
616 mawk_array_getnum_execute(MAWK, sp+2, sp+1, sp);
617 P_nansafe1(sp[2].d.dval, (sp[2].d.dval + tmp_num), tmp_num);
618 mawk_array_set_execute(MAWK, sp, sp+1, sp, sp+2);
619 }
620 else {
621 mawk_array_getptr_execute(MAWK, cp, sp+1, sp);
622 P_nansafe1(cp->d.dval, (cp->d.dval + tmp_num), tmp_num);
623 }
624 break;
625
626 case _SUB_ASG:
627 if (sp->type != C_NUM)
628 mawk_cast1_to_num(MAWK, sp);
629 cp = (mawk_cell_t *) (sp - 1)->ptr;
630 if (cp->type != C_NUM)
631 mawk_cast1_to_num(MAWK, cp);
632 P_nansafe1(cp->d.dval, (cp->d.dval - sp->d.dval), sp->d.dval);
633 sp--;
634 sp->type = C_NUM;
635 sp->d.dval = cp->d.dval;
636 break;
637
638 case _SUB_ASG_ARR:
639 /* convert the expression result */
640 mawk_cast_get_num(tmp_num, sp);
641 sp-=2;
642 /* sp is the index, sp+1 is the array ref and sp+2 is rvalue expr result; after this sp+2 is the array val */
643 if (!mawk_array_pure(MAWK, sp+1, 1)) {
644 mawk_array_getnum_execute(MAWK, sp+2, sp+1, sp);
645 P_nansafe1(sp[2].d.dval, (sp[2].d.dval - tmp_num), tmp_num);
646 mawk_array_set_execute(MAWK, sp, sp+1, sp, sp+2);
647 }
648 else {
649 mawk_array_getptr_execute(MAWK, cp, sp+1, sp);
650 P_nansafe1(cp->d.dval, (cp->d.dval - tmp_num), tmp_num);
651 }
652 break;
653
654 case _MUL_ASG:
655 if (sp->type != C_NUM)
656 mawk_cast1_to_num(MAWK, sp);
657 cp = (mawk_cell_t *) (sp - 1)->ptr;
658 if (cp->type != C_NUM)
659 mawk_cast1_to_num(MAWK, cp);
660 P_nansafe1(cp->d.dval, (cp->d.dval * sp->d.dval), sp->d.dval);
661 sp--;
662 sp->type = C_NUM;
663 sp->d.dval = cp->d.dval;
664 break;
665
666 case _MUL_ASG_ARR:
667 /* convert the expression result */
668 mawk_cast_get_num(tmp_num, sp);
669 sp-=2;
670 /* sp is the index, sp+1 is the array ref and sp+2 is rvalue expr result; after this sp+2 is the array val */
671 if (!mawk_array_pure(MAWK, sp+1, 1)) {
672 mawk_array_getnum_execute(MAWK, sp+2, sp+1, sp);
673 P_nansafe1(sp[2].d.dval, (sp[2].d.dval * tmp_num), tmp_num);
674 mawk_array_set_execute(MAWK, sp, sp+1, sp, sp+2);
675 }
676 else {
677 mawk_array_getptr_execute(MAWK, cp, sp+1, sp);
678 P_nansafe1(cp->d.dval, (cp->d.dval * tmp_num), tmp_num);
679 }
680 break;
681
682 case _DIV_ASG:
683 if (sp->type != C_NUM)
684 mawk_cast1_to_num(MAWK, sp);
685 cp = (mawk_cell_t *) (sp - 1)->ptr;
686 if (cp->type != C_NUM)
687 mawk_cast1_to_num(MAWK, cp);
688
689 #ifdef MAWK_NO_FLOAT
690 {
691 mawk_num_t d;
692 d = sp--->d.dval;
693 if (d != MAWK_NUM_ZERO)
694 cp->d.dval /= d;
695 else
696 cp->d.dval = P_nan();
697 }
698 #else
699 {
700 P_nansafe1(cp->d.dval, (cp->d.dval / sp->d.dval), sp->d.dval);
701 sp--;
702 }
703 #endif
704 sp->type = C_NUM;
705 sp->d.dval = cp->d.dval;
706 break;
707
708
709 case _DIV_ASG_ARR:
710 /* convert the expression result */
711 mawk_cast_get_num(tmp_num, sp);
712 sp-=2;
713 /* sp is the index, sp+1 is the array ref and sp+2 is rvalue expr result; after this sp+2 is the array val */
714 if (!mawk_array_pure(MAWK, sp+1, 1)) {
715 mawk_array_getnum_execute(MAWK, sp+2, sp+1, sp);
716
717 #ifdef MAWK_NO_FLOAT
718 if (tmp_num != MAWK_NUM_ZERO)
719 sp[2].d.dval /= tmp_num;
720 else
721 sp[2].d.dval = P_nan();
722 #else
723 P_nansafe1(sp[2].d.dval, (sp[2].d.dval / tmp_num), tmp_num);
724 #endif
725 mawk_array_set_execute(MAWK, sp, sp+1, sp, sp+2);
726 }
727 else {
728 mawk_array_getptr_execute(MAWK, cp, sp+1, sp);
729 #ifdef MAWK_NO_FLOAT
730 if (tmp_num != MAWK_NUM_ZERO)
731 cp->d.dval /= tmp_num;
732 else
733 cp->d.dval = P_nan();
734 #else
735 P_nansafe1(cp->d.dval, (cp->d.dval / tmp_num), tmp_num);
736 #endif
737 }
738 break;
739
740 case _MOD_ASG:
741 if (sp->type != C_NUM)
742 mawk_cast1_to_num(MAWK, sp);
743 cp = (mawk_cell_t *) (sp - 1)->ptr;
744 if (cp->type != C_NUM)
745 mawk_cast1_to_num(MAWK, cp);
746
747 if (P_isnan_manual(cp->d.dval) || P_isnan_manual(sp->d.dval))
748 cp->d.dval = P_nan();
749 else {
750 #ifdef MAWK_NO_FLOAT
751 cp->d.dval %= sp->d.dval;
752 #else
753 cp->d.dval = P_fmod(cp->d.dval, sp->d.dval);
754 #endif
755 }
756 sp--;
757
758 sp->type = C_NUM;
759 sp->d.dval = cp->d.dval;
760 break;
761
762 case _MOD_ASG_ARR:
763 /* convert the expression result */
764 mawk_cast_get_num(tmp_num, sp);
765 sp-=2;
766 /* sp is the index, sp+1 is the array ref and sp+2 is rvalue expr result; after this sp+2 is the array val */
767 if (!mawk_array_pure(MAWK, sp+1, 1)) {
768 mawk_array_getnum_execute(MAWK, sp+2, sp+1, sp);
769
770 #ifdef MAWK_NO_FLOAT
771 sp[2].d.dval %= tmp_num;
772 #else
773 sp[2].d.dval = P_fmod(sp[2].d.dval, tmp_num);
774 #endif
775 mawk_array_set_execute(MAWK, sp, sp+1, sp, sp+2);
776 }
777 else {
778 mawk_array_getptr_execute(MAWK, cp, sp+1, sp);
779 #ifdef MAWK_NO_FLOAT
780 cp->d.dval %= tmp_num;
781 #else
782 cp->d.dval = P_fmod(cp->d.dval, tmp_num);
783 #endif
784 }
785 break;
786
787
788 case _POW_ASG:
789 if (sp->type != C_NUM)
790 mawk_cast1_to_num(MAWK, sp);
791 cp = (mawk_cell_t *) (sp - 1)->ptr;
792 if (cp->type != C_NUM)
793 mawk_cast1_to_num(MAWK, cp);
794 cp->d.dval = mawk_num_pow(cp->d.dval, sp--->d.dval);
795 sp->type = C_NUM;
796 sp->d.dval = cp->d.dval;
797 break;
798
799 case _POW_ASG_ARR:
800 /* convert the expression result */
801 mawk_cast_get_num(tmp_num, sp);
802 sp-=2;
803 /* sp is the index, sp+1 is the array ref and sp+2 is rvalue expr result; after this sp+2 is the array val */
804 if (!mawk_array_pure(MAWK, sp+1, 1)) {
805 mawk_array_getnum_execute(MAWK, sp+2, sp+1, sp);
806 sp[2].d.dval = mawk_num_pow(sp[2].d.dval, tmp_num);
807 mawk_array_set_execute(MAWK, sp, sp+1, sp, sp+2);
808 }
809 else {
810 mawk_array_getptr_execute(MAWK, cp, sp+1, sp);
811 cp->d.dval = mawk_num_pow(cp->d.dval, tmp_num);
812 }
813 break;
814
815
816 case F_ADD_ASG:
817 if (sp->type != C_NUM)
818 mawk_cast1_to_num(MAWK, sp);
819 cp = (mawk_cell_t *) (sp - 1)->ptr;
820 mawk_cellcpy(MAWK, &MAWK->tc, cp);
821 mawk_cast1_to_num(MAWK, &MAWK->tc);
822 P_nansafe1(MAWK->tc.d.dval, (MAWK->tc.d.dval + sp->d.dval), sp->d.dval);
823 sp--;
824 sp->type = C_NUM;
825 sp->d.dval = MAWK->tc.d.dval;
826 mawk_field_assign(MAWK, cp, &MAWK->tc);
827 break;
828
829 case F_SUB_ASG:
830 if (sp->type != C_NUM)
831 mawk_cast1_to_num(MAWK, sp);
832 cp = (mawk_cell_t *) (sp - 1)->ptr;
833 mawk_cellcpy(MAWK, &MAWK->tc, cp);
834 mawk_cast1_to_num(MAWK, &MAWK->tc);
835 P_nansafe1(MAWK->tc.d.dval, (MAWK->tc.d.dval - sp->d.dval), sp->d.dval);
836 sp--;
837 sp->type = C_NUM;
838 sp->d.dval = MAWK->tc.d.dval;
839 mawk_field_assign(MAWK, cp, &MAWK->tc);
840 break;
841
842 case F_MUL_ASG:
843 if (sp->type != C_NUM)
844 mawk_cast1_to_num(MAWK, sp);
845 cp = (mawk_cell_t *) (sp - 1)->ptr;
846 mawk_cellcpy(MAWK, &MAWK->tc, cp);
847 mawk_cast1_to_num(MAWK, &MAWK->tc);
848
849 P_nansafe1(MAWK->tc.d.dval, (MAWK->tc.d.dval * sp->d.dval), sp->d.dval);
850 sp--;
851
852 sp->type = C_NUM;
853 sp->d.dval = MAWK->tc.d.dval;
854 mawk_field_assign(MAWK, cp, &MAWK->tc);
855 break;
856
857 case F_DIV_ASG:
858 if (sp->type != C_NUM)
859 mawk_cast1_to_num(MAWK, sp);
860 cp = (mawk_cell_t *) (sp - 1)->ptr;
861 mawk_cellcpy(MAWK, &MAWK->tc, cp);
862 mawk_cast1_to_num(MAWK, &MAWK->tc);
863
864 #ifdef MAWK_NO_FLOAT
865 {
866 mawk_num_t d;
867 d = sp--->d.dval;
868 if (d != MAWK_NUM_ZERO)
869 MAWK->tc.d.dval /= d;
870 else
871 MAWK->tc.d.dval = P_nan();
872 }
873 #else
874 P_nansafe1(MAWK->tc.d.dval, (MAWK->tc.d.dval / sp->d.dval), sp->d.dval);
875 sp--;
876 #endif
877 sp->type = C_NUM;
878 sp->d.dval = MAWK->tc.d.dval;
879 mawk_field_assign(MAWK, cp, &MAWK->tc);
880 break;
881
882 case F_MOD_ASG:
883 if (sp->type != C_NUM)
884 mawk_cast1_to_num(MAWK, sp);
885 cp = (mawk_cell_t *) (sp - 1)->ptr;
886 mawk_cellcpy(MAWK, &MAWK->tc, cp);
887 mawk_cast1_to_num(MAWK, &MAWK->tc);
888
889 #ifdef MAWK_NO_FLOAT
890 {
891 int d;
892 d = sp--->d.dval;
893 if (d != MAWK_NUM_ZERO)
894 MAWK->tc.d.dval %= d;
895 else
896 MAWK->tc.d.dval = P_nan();
897 }
898 #else
899 MAWK->tc.d.dval = P_fmod(MAWK->tc.d.dval, sp--->d.dval);
900 #endif
901 sp->type = C_NUM;
902 sp->d.dval = MAWK->tc.d.dval;
903 mawk_field_assign(MAWK, cp, &MAWK->tc);
904 break;
905
906 case F_POW_ASG:
907 if (sp->type != C_NUM)
908 mawk_cast1_to_num(MAWK, sp);
909 cp = (mawk_cell_t *) (sp - 1)->ptr;
910 mawk_cellcpy(MAWK, &MAWK->tc, cp);
911 mawk_cast1_to_num(MAWK, &MAWK->tc);
912 MAWK->tc.d.dval = mawk_num_pow(MAWK->tc.d.dval, sp--->d.dval);
913 sp->type = C_NUM;
914 sp->d.dval = MAWK->tc.d.dval;
915 mawk_field_assign(MAWK, cp, &MAWK->tc);
916 break;
917
918 case _ADD:
919 sp--;
920 if (TEST2(sp) != TWO_NUMS)
921 mawk_cast2_to_num(MAWK, sp);
922
923 P_nansafe1(sp[0].d.dval, (sp[0].d.dval + sp[1].d.dval), sp[1].d.dval);
924 break;
925
926 case _SUB:
927 sp--;
928 if (TEST2(sp) != TWO_NUMS)
929 mawk_cast2_to_num(MAWK, sp);
930
931 P_nansafe1(sp[0].d.dval, (sp[0].d.dval - sp[1].d.dval), sp[1].d.dval);
932 break;
933
934 case _MUL:
935 sp--;
936 if (TEST2(sp) != TWO_NUMS)
937 mawk_cast2_to_num(MAWK, sp);
938
939 P_nansafe1(sp[0].d.dval, (sp[0].d.dval * sp[1].d.dval), sp[1].d.dval);
940 break;
941
942 case _DIV:
943 sp--;
944 if (TEST2(sp) != TWO_NUMS)
945 mawk_cast2_to_num(MAWK, sp);
946
947 #ifdef MAWK_NO_FLOAT
948 if (sp[1].d.dval != 0)
949 sp[0].d.dval /= sp[1].d.dval;
950 else
951 sp[0].d.dval = P_nan();
952 #else
953 P_nansafe1(sp[0].d.dval, (sp[0].d.dval / sp[1].d.dval), sp[1].d.dval);
954 #endif
955 break;
956
957 case _MOD:
958 sp--;
959 if (TEST2(sp) != TWO_NUMS)
960 mawk_cast2_to_num(MAWK, sp);
961
962 #ifdef MAWK_NO_FLOAT
963 {
964 int d;
965 d = sp[1].d.dval;
966 if (d != MAWK_NUM_ZERO)
967 sp[0].d.dval %= d;
968 else
969 sp[0].d.dval = P_nan();
970 }
971 #else
972 sp[0].d.dval = P_fmod(sp[0].d.dval, sp[1].d.dval);
973 #endif
974 break;
975
976 case _POW:
977 sp--;
978 if (TEST2(sp) != TWO_NUMS)
979 mawk_cast2_to_num(MAWK, sp);
980 sp[0].d.dval = mawk_num_pow(sp[0].d.dval, sp[1].d.dval);
981 break;
982
983 case _NOT:
984 /* evaluates to 0.0 or 1.0 */
985 reswitch_1:
986 switch (sp->type) {
987 case C_NOINIT:
988 sp->d.dval = MAWK_NUM_ONE;
989 break;
990 case C_NUM:
991 if (!P_isnan_manual(sp->d.dval))
992 sp->d.dval = sp->d.dval != MAWK_NUM_ZERO ? MAWK_NUM_ZERO : MAWK_NUM_ONE;
993 break;
994 case C_STRING:
995 sp->d.dval = string(sp)->len ? MAWK_NUM_ZERO : MAWK_NUM_ONE;
996 free_STRING(string(sp));
997 break;
998 case C_STRNUM: /* mawk_test as a number */
999 sp->d.dval = sp->d.dval != MAWK_NUM_ZERO ? MAWK_NUM_ZERO : MAWK_NUM_ONE;
1000 free_STRING(string(sp));
1001 break;
1002 case C_MBSTRN:
1003 mawk_check_strnum(MAWK, sp);
1004 goto reswitch_1;
1005 default:
1006 mawk_bozo(MAWK, "bad type on eval stack");
1007 }
1008 sp->type = C_NUM;
1009 break;
1010
1011 case _TEST:
1012 /* evaluates to 0.0 or 1.0 */
1013 reswitch_2:
1014 switch (sp->type) {
1015 case C_NOINIT:
1016 sp->d.dval = MAWK_NUM_ZERO;
1017 break;
1018 case C_NUM:
1019 if (!P_isnan_manual(sp->d.dval))
1020 sp->d.dval = sp->d.dval != MAWK_NUM_ZERO ? MAWK_NUM_ONE : MAWK_NUM_ZERO;
1021 break;
1022 case C_STRING:
1023 sp->d.dval = string(sp)->len ? MAWK_NUM_ONE : MAWK_NUM_ZERO;
1024 free_STRING(string(sp));
1025 break;
1026 case C_STRNUM: /* mawk_test as a number */
1027 sp->d.dval = sp->d.dval != MAWK_NUM_ZERO ? MAWK_NUM_ONE : MAWK_NUM_ZERO;
1028 free_STRING(string(sp));
1029 break;
1030 case C_MBSTRN:
1031 mawk_check_strnum(MAWK, sp);
1032 goto reswitch_2;
1033 default:
1034 mawk_bozo(MAWK, "bad type on eval stack");
1035 }
1036 sp->type = C_NUM;
1037 break;
1038
1039 case _UMINUS:
1040 if (sp->type != C_NUM)
1041 mawk_cast1_to_num(MAWK, sp);
1042 if (!P_isnan_manual(sp->d.dval))
1043 sp->d.dval = -sp->d.dval;
1044 break;
1045
1046 case _UPLUS:
1047 if (sp->type != C_NUM)
1048 mawk_cast1_to_num(MAWK, sp);
1049 break;
1050
1051 case _CAT:
1052 {
1053 unsigned len1, len2;
1054 char *str1, *str2;
1055 mawk_string_t *b;
1056
1057 sp--;
1058 if (TEST2(sp) != TWO_STRINGS)
1059 mawk_cast2_to_str(MAWK, sp);
1060 str1 = string(sp)->str;
1061 len1 = string(sp)->len;
1062 str2 = string(sp + 1)->str;
1063 len2 = string(sp + 1)->len;
1064
1065 b = mawk_new_STRING0(MAWK, len1 + len2);
1066 memcpy(b->str, str1, len1);
1067 memcpy(b->str + len1, str2, len2);
1068 free_STRING(string(sp));
1069 free_STRING(string(sp + 1));
1070
1071 sp->ptr = (PTR) b;
1072 break;
1073 }
1074
1075 case _PUSHINT:
1076 inc_sp();
1077 sp->type = cdp++->op;
1078 break;
1079
1080 case _BUILTIN:
1081 db1printstack(MAWK, "--start before bi", sp, fp);
1082 cp = (*(PF_CP) mawk_d2f(cdp++->ptr)) (MAWK, sp);
1083 db1printstack(MAWK, "--start after bi", sp, fp);
1084 if (cp->type == C_REQ_NOMORE) {
1085 db1printf("->nomore\n");
1086 cdp-=2;
1087 goto out_nomore;
1088 }
1089 sp = cp;
1090 if (sp->type == C_REQ_CALL) { /* the bi function returned with a request to call an user function */
1091 int a_args;
1092 mawk_cell_t *pfp;
1093 FBLOCK *fbp;
1094
1095 db1printf("->req call\n");
1096
1097 fbp = (FBLOCK *) sp->ptr;
1098 sp--;
1099 a_args = sp->d.dval; /* actual/caller's number of args on stack already */
1100 sp--;
1101
1102 pfp = sp - a_args + 1;
1103 {
1104 mawk_call_pre();
1105
1106 db1printf("++ CALL2 sp=%d a_args(caller)=%d fbp->nargs(callee)=%d\n", stackptr(sp), a_args,fbp->nargs);
1107 db1printstack(MAWK, "--start call2", sp, fp);
1108 mawk_push_exe_state(EXEST_NORMAL);
1109 aloop_state = NULL;
1110
1111 /*sp - RECURSION_OVERHEAD - fbp->nargs + a_args*/
1112 fp = pfp;
1113 db1printf("CALL2 fp=%d final-sp=%d\n", stackptr(fp), stackptr(sp));
1114
1115 cdp = fbp->code;
1116 db1printf("CALL new=%d\n", stackptr(sp));
1117 }
1118 }
1119 break;
1120
1121 case _PRINT:
1122 sp = (*(PF_CP) mawk_d2f(cdp++->ptr)) (MAWK, sp);
1123 break;
1124
1125 case _POST_INC:
1126 cp = (mawk_cell_t *) sp->ptr;
1127 if (cp->type != C_NUM)
1128 mawk_cast1_to_num(MAWK, cp);
1129 sp->type = C_NUM;
1130 sp->d.dval = cp->d.dval;
1131 if (!P_isnan_manual(cp->d.dval))
1132 cp->d.dval += MAWK_NUM_ONE;
1133 break;
1134
1135 case _POST_INC_ARR:
1136 inc_sp();
1137 sp->type = C_NOINIT;
1138 sp-=2;
1139 /* sp is the index, sp+1 is the array ref and sp+2 is tmp; after this sp+2 is the array val */
1140 if (!mawk_array_pure(MAWK, sp+1, 1)) {
1141 mawk_array_getnum_execute(MAWK, sp+2, sp+1, sp);
1142 tmp_num = sp[2].d.dval;
1143 if (!P_isnan_manual(sp[2].d.dval))
1144 sp[2].d.dval += MAWK_NUM_ONE;
1145 mawk_array_set(MAWK, (mawk_array_t)sp[1].ptr, sp, sp+2);
1146
1147 }
1148 else {
1149 mawk_array_getptr_execute(MAWK, cp, sp+1, sp);
1150 if (cp->type != C_NUM)
1151 mawk_cast1_to_num(MAWK, cp);
1152 tmp_num = cp->d.dval;
1153 if (!P_isnan_manual(cp->d.dval))
1154 cp->d.dval += MAWK_NUM_ONE;
1155 }
1156 mawk_cell_destroy(MAWK, sp);
1157 sp->type = C_NUM;
1158 sp->d.dval = tmp_num;
1159 break;
1160
1161
1162 case _POST_DEC:
1163 cp = (mawk_cell_t *) sp->ptr;
1164 if (cp->type != C_NUM)
1165 mawk_cast1_to_num(MAWK, cp);
1166 sp->type = C_NUM;
1167 sp->d.dval = cp->d.dval;
1168 if (!P_isnan_manual(sp->d.dval))
1169 cp->d.dval -= MAWK_NUM_ONE;
1170 break;
1171
1172 case _POST_DEC_ARR:
1173 inc_sp();
1174 sp->type = C_NOINIT;
1175 sp-=2;
1176 /* sp is the index, sp+1 is the array ref and sp+2 is tmp; after this sp+2 is the array val */
1177 if (!mawk_array_pure(MAWK, sp+1, 1)) {
1178 mawk_array_getnum_execute(MAWK, sp+2, sp+1, sp);
1179 tmp_num = sp[2].d.dval;
1180 if (!P_isnan_manual(sp[2].d.dval))
1181 sp[2].d.dval -= MAWK_NUM_ONE;
1182 mawk_array_set(MAWK, (mawk_array_t)sp[1].ptr, sp, sp+2);
1183 }
1184 else {
1185 mawk_array_getptr_execute(MAWK, cp, sp+1, sp);
1186 if (cp->type != C_NUM)
1187 mawk_cast1_to_num(MAWK, cp);
1188 tmp_num = cp->d.dval;
1189 if (!P_isnan_manual(cp->d.dval))
1190 cp->d.dval -= MAWK_NUM_ONE;
1191 }
1192 mawk_cell_destroy(MAWK, sp);
1193 sp->type = C_NUM;
1194 sp->d.dval = tmp_num;
1195 break;
1196
1197 case _PRE_INC:
1198 cp = (mawk_cell_t *) sp->ptr;
1199 if (cp->type != C_NUM)
1200 mawk_cast1_to_num(MAWK, cp);
1201 if (!P_isnan_manual(sp->d.dval))
1202 cp->d.dval += MAWK_NUM_ONE;
1203 sp->d.dval = cp->d.dval;
1204 sp->type = C_NUM;
1205 break;
1206
1207 case _PRE_INC_ARR:
1208 inc_sp();
1209 sp->type = C_NOINIT;
1210 sp-=2;
1211 /* sp is the index, sp+1 is the array ref and sp+2 is tmp; after this sp+2 is the array val */
1212 if (!mawk_array_pure(MAWK, sp+1, 1)) {
1213 mawk_array_getnum_execute(MAWK, sp+2, sp+1, sp);
1214 if (!P_isnan_manual(sp[2].d.dval))
1215 sp[2].d.dval += MAWK_NUM_ONE;
1216 mawk_array_set(MAWK, (mawk_array_t)sp[1].ptr, sp, sp+2);
1217 mawk_cell_destroy(MAWK, sp);
1218 sp->type = C_NUM;
1219 sp->d.dval = sp[2].d.dval;
1220 }
1221 else {
1222 mawk_array_getptr_execute(MAWK, cp, sp+1, sp);
1223 if (cp->type != C_NUM)
1224 mawk_cast1_to_num(MAWK, cp);
1225 if (!P_isnan_manual(cp->d.dval))
1226 cp->d.dval += MAWK_NUM_ONE;
1227 mawk_cell_destroy(MAWK, sp);
1228 sp->type = C_NUM;
1229 sp->d.dval = cp->d.dval;
1230 }
1231 break;
1232
1233
1234 case _PRE_DEC:
1235 cp = (mawk_cell_t *) sp->ptr;
1236 if (cp->type != C_NUM)
1237 mawk_cast1_to_num(MAWK, cp);
1238 if (!P_isnan_manual(sp->d.dval))
1239 cp->d.dval -= MAWK_NUM_ONE;
1240 sp->d.dval = cp->d.dval;
1241 sp->type = C_NUM;
1242 break;
1243
1244 case _PRE_DEC_ARR:
1245 inc_sp();
1246 sp->type = C_NOINIT;
1247 sp-=2;
1248 /* sp is the index, sp+1 is the array ref and sp+2 is tmp; after this sp+2 is the array val */
1249 if (!mawk_array_pure(MAWK, sp+1, 1)) {
1250 mawk_array_getnum_execute(MAWK, sp+2, sp+1, sp);
1251 if (!P_isnan_manual(sp[2].d.dval))
1252 sp[2].d.dval -= MAWK_NUM_ONE;
1253 mawk_array_set(MAWK, (mawk_array_t)sp[1].ptr, sp, sp+2);
1254 mawk_cell_destroy(MAWK, sp);
1255 sp->type = C_NUM;
1256 sp->d.dval = sp[2].d.dval;
1257 }
1258 else {
1259 mawk_array_getptr_execute(MAWK, cp, sp+1, sp);
1260 if (cp->type != C_NUM)
1261 mawk_cast1_to_num(MAWK, cp);
1262 if (!P_isnan_manual(cp->d.dval))
1263 cp->d.dval -= MAWK_NUM_ONE;
1264 mawk_cell_destroy(MAWK, sp);
1265 sp->type = C_NUM;
1266 sp->d.dval = cp->d.dval;
1267 }
1268 break;
1269
1270 case F_POST_INC:
1271 cp = (mawk_cell_t *) sp->ptr;
1272 mawk_cellcpy(MAWK, &MAWK->tc, cp);
1273 mawk_cast1_to_num(MAWK, &MAWK->tc);
1274 sp->type = C_NUM;
1275 sp->d.dval = MAWK->tc.d.dval;
1276 if (!P_isnan_manual(MAWK->tc.d.dval))
1277 MAWK->tc.d.dval += MAWK_NUM_ONE;
1278 mawk_field_assign(MAWK, cp, &MAWK->tc);
1279 break;
1280
1281 case F_POST_DEC:
1282 cp = (mawk_cell_t *) sp->ptr;
1283 mawk_cellcpy(MAWK, &MAWK->tc, cp);
1284 mawk_cast1_to_num(MAWK, &MAWK->tc);
1285 sp->type = C_NUM;
1286 sp->d.dval = MAWK->tc.d.dval;
1287 if (!P_isnan_manual(MAWK->tc.d.dval))
1288 MAWK->tc.d.dval -= MAWK_NUM_ONE;
1289 mawk_field_assign(MAWK, cp, &MAWK->tc);
1290 break;
1291
1292 case F_PRE_INC:
1293 cp = (mawk_cell_t *) sp->ptr;
1294 mawk_cellcpy(MAWK, sp, cp);
1295 mawk_cast1_to_num(MAWK, sp);
1296 if (!P_isnan_manual(sp->d.dval))
1297 sp->d.dval += MAWK_NUM_ONE;
1298 mawk_field_assign(MAWK, cp, sp);
1299 break;
1300
1301 case F_PRE_DEC:
1302 cp = (mawk_cell_t *) sp->ptr;
1303 mawk_cellcpy(MAWK, sp, cp);
1304 mawk_cast1_to_num(MAWK, sp);
1305 if (!P_isnan_manual(sp->d.dval))
1306 sp->d.dval -= MAWK_NUM_ONE;
1307 mawk_field_assign(MAWK, cp, sp);
1308 break;
1309
1310 case _JMP:
1311 cdp += cdp->op;
1312 break;
1313
1314 case _JNZ:
1315 /* jmp if top of stack is non-zero and pop stack */
1316 if (P_isnan(sp->d.dval))
1317 mawk_rt_error(MAWK, "NaN in conditional jump");
1318 if (mawk_test(MAWK, sp))
1319 cdp += cdp->op;
1320 else
1321 cdp++;
1322 mawk_cell_destroy(MAWK, sp);
1323 sp--;
1324 break;
1325
1326 case _JZ:
1327 /* jmp if top of stack is zero and pop stack */
1328 if (P_isnan(sp->d.dval))
1329 mawk_rt_error(MAWK, "NaN in conditional jump");
1330 if (!mawk_test(MAWK, sp))
1331 cdp += cdp->op;
1332 else
1333 cdp++;
1334 mawk_cell_destroy(MAWK, sp);
1335 sp--;
1336 break;
1337
1338 case _LJZ:
1339 /* special jump for logical and */
1340 /* this is always preceded by _TEST */
1341 if (P_isnan(sp->d.dval))
1342 mawk_rt_error(MAWK, "NaN in conditional jump");
1343 if (sp->d.dval == MAWK_NUM_ZERO) {
1344 /* take jump, but don't pop stack */
1345 cdp += cdp->op;
1346 }
1347 else {
1348 /* pop and don't jump */
1349 sp--;
1350 cdp++;
1351 }
1352 break;
1353
1354 case _LJNZ:
1355 /* special jump for logical or */
1356 /* this is always preceded by _TEST */
1357 if (P_isnan(sp->d.dval))
1358 mawk_rt_error(MAWK, "NaN in conditional jump");
1359 if (sp->d.dval != MAWK_NUM_ZERO) {
1360 /* take jump, but don't pop stack */
1361 cdp += cdp->op;
1362 }
1363 else {
1364 /* pop and don't jump */
1365 sp--;
1366 cdp++;
1367 }
1368 break;
1369
1370 /* the relation operations */
1371 /* compare() makes sure string ref counts are OK */
1372 case _EQ:
1373 dt = compare(MAWK, --sp);
1374 sp->type = C_NUM;
1375 sp->d.dval = P_nansafe_exp1((dt == 0 ? MAWK_NUM_ONE : MAWK_NUM_ZERO), dt);
1376 break;
1377
1378 case _NEQ:
1379 dt = compare(MAWK, --sp);
1380 sp->type = C_NUM;
1381 sp->d.dval = P_nansafe_exp1((dt ? MAWK_NUM_ONE : MAWK_NUM_ZERO), dt);
1382 break;
1383
1384 case _LT:
1385 dt = compare(MAWK, --sp);
1386 sp->type = C_NUM;
1387 sp->d.dval = P_nansafe_exp1((dt < 0 ? MAWK_NUM_ONE : MAWK_NUM_ZERO), dt);
1388 break;
1389
1390 case _LTE:
1391 dt = compare(MAWK, --sp);
1392 sp->type = C_NUM;
1393 sp->d.dval = P_nansafe_exp1((dt <= 0 ? MAWK_NUM_ONE : MAWK_NUM_ZERO), dt);
1394 break;
1395
1396 case _GT:
1397 dt = compare(MAWK, --sp);
1398 sp->type = C_NUM;
1399 sp->d.dval = P_nansafe_exp1((dt > 0 ? MAWK_NUM_ONE : MAWK_NUM_ZERO), dt);
1400 break;
1401
1402 case _GTE:
1403 dt = compare(MAWK, --sp);
1404 sp->type = C_NUM;
1405 sp->d.dval = P_nansafe_exp1((dt >= 0 ? MAWK_NUM_ONE : MAWK_NUM_ZERO), dt);
1406 break;
1407
1408 case _MATCH0:
1409 /* does $0 match, the RE at cdp? */
1410
1411 inc_sp();
1412 if (MAWK->field->type >= C_STRING) {
1413 sp->type = C_NUM;
1414 sp->d.dval = mawk_REtest(MAWK, string(MAWK->field)->str, cdp++->ptr)
1415 ? MAWK_NUM_ONE : MAWK_NUM_ZERO;
1416
1417 break /* the case */ ;
1418 }
1419 else {
1420 mawk_cellcpy(MAWK, sp, MAWK->field);
1421 /* and FALL THRU */
1422 }
1423
1424 case _MATCH1:
1425 /* does expr at sp[0] match RE at cdp */
1426 if (sp->type < C_STRING)
1427 mawk_cast1_to_str(MAWK, sp);
1428 t = mawk_REtest(MAWK, string(sp)->str, cdp++->ptr);
1429 free_STRING(string(sp));
1430 sp->type = C_NUM;
1431 sp->d.dval = t ? MAWK_NUM_ONE : MAWK_NUM_ZERO;
1432 break;
1433
1434
1435 case _MATCH2:
1436 /* does sp[-1] match sp[0] as re */
1437 mawk_cast_to_RE(MAWK, sp);
1438
1439 if ((--sp)->type < C_STRING)
1440 mawk_cast1_to_str(MAWK, sp);
1441 t = mawk_REtest(MAWK, string(sp)->str, (sp + 1)->ptr);
1442
1443 free_STRING(string(sp));
1444 sp->type = C_NUM;
1445 sp->d.dval = t ? MAWK_NUM_ONE : MAWK_NUM_ZERO;
1446 break;
1447
1448 case A_TEST:
1449 /* entry : sp[0].ptr-> an array
1450 sp[-1] is an expression
1451
1452 we compute (expression in array) */
1453 sp--;
1454 t = mawk_array_find(MAWK, (mawk_array_t)((sp + 1)->ptr), sp, NULL, NO_MAWK_CREATE);
1455 mawk_cell_destroy(MAWK, sp);
1456 sp->type = C_NUM;
1457 sp->d.dval = t ? MAWK_NUM_ONE : MAWK_NUM_ZERO;
1458 break;
1459
1460 case A_DEL:
1461 /* sp[0].ptr -> array
1462 sp[-1] is an expr
1463 delete array[expr] */
1464
1465 mawk_array_delete(MAWK, (mawk_array_t)(sp->ptr), sp - 1);
1466 mawk_cell_destroy(MAWK, sp - 1);
1467 sp -= 2;
1468 break;
1469
1470 case DEL_A:
1471 /* free all the array at once */
1472 mawk_array_clear(MAWK, (mawk_array_t)(sp->ptr));
1473 sp--;
1474 break;
1475
1476 /* form a multiple array index */
1477 case A_CAT:
1478 sp = mawk_array_cat(MAWK, sp, cdp->op);
1479 cdp++;
1480 break;
1481
1482 case _EXIT:
1483 if (sp->type != C_NUM)
1484 mawk_cast1_to_num(MAWK, sp);
1485 MAWK->exit_code = d_to_i(sp->d.dval);
1486 sp--;
1487 /* fall thru */
1488
1489 case _EXIT0:
1490
1491 if (!MAWK->end_start) {
1492 mawk_exit_(MAWK, MAWK->exit_code);
1493 goto out_exit;
1494 }
1495
1496
1497 cdp = MAWK->end_start;
1498 MAWK->end_start = NULL; /* makes sure next exit exits */
1499
1500 if (MAWK->begin_start) {
1501 mawk_zfree(MAWK, MAWK->begin_start, MAWK->begin_size);
1502 MAWK->begin_start = NULL;
1503 }
1504 if (MAWK->main_start) {
1505 mawk_zfree(MAWK, MAWK->main_start, MAWK->main_size);
1506 MAWK->main_start = NULL;
1507 }
1508 sp = MAWK->eval_stack - 1; /* might be in user function */
1509 CLEAR_ALOOP_STACK(); /* ditto */
1510
1511 /* cdp is set up to point to END, go on executing that */
1512 break;
1513 case _JMAIN: /* go from BEGIN code to MAIN code */
1514 mawk_zfree(MAWK, MAWK->begin_start, MAWK->begin_size);
1515 MAWK->begin_start = NULL;
1516 cdp = MAWK->main_start;
1517 if (MAWK->separate_begin)
1518 goto out_sepmain;
1519 break;
1520
1521 case _OMAIN:
1522 if (!MAWK->main_input)
1523 mawk_FINopen_main(MAWK);
1524 if (!MAWK->main_input)
1525 goto jump_end;
1526 MAWK->restart_label = cdp;
1527 cdp = MAWK->next_label;
1528 break;
1529
1530 case _NEXT:
1531 /* next might be inside an aloop -- clear stack */
1532 CLEAR_ALOOP_STACK();
1533 cdp = MAWK->next_label;
1534 break;
1535
1536 case OL_GL:
1537 {
1538 char *p;
1539 unsigned len;
1540
1541 p = mawk_FINgets(MAWK, MAWK->main_input, &len);
1542 if (p == (void *) mawk_FIN_nomore) {
1543 cdp--;
1544 goto out_nomore;
1545 }
1546 if (!p) {
1547 if (!MAWK->end_start)
1548 mawk_exitval(MAWK, 0, MAWK_EXER_DONE);
1549
1550 jump_end:;
1551 cdp = MAWK->end_start;
1552 if (MAWK->main_start != NULL)
1553 mawk_zfree(MAWK, MAWK->main_start, MAWK->main_size);
1554 MAWK->main_start = MAWK->end_start = (INST *) 0;
1555 }
1556 else {
1557 mawk_set_field0(MAWK, p, len);
1558 cdp = MAWK->restart_label;
1559 MAWK->rt_nr++;
1560 MAWK->rt_fnr++;
1561 }
1562 }
1563 break;
1564
1565 /* two kinds of OL_GL is a historical stupidity from working on
1566 a machine with very slow floating point emulation */
1567 case OL_GL_NR:
1568 {
1569 char *p;
1570 unsigned len;
1571 p = mawk_FINgets(MAWK, MAWK->main_input, &len);
1572 if (p == (void *) mawk_FIN_nomore) {
1573 cdp--;
1574 goto out_nomore;
1575 }
1576 if (!p) {
1577 if (!MAWK->end_start)
1578 mawk_exitval(MAWK, 0, MAWK_EXER_DONE);
1579
1580 cdp = MAWK->end_start;
1581 if (MAWK->main_start != NULL)
1582 mawk_zfree(MAWK, MAWK->main_start, MAWK->main_size);
1583 MAWK->main_start = MAWK->end_start = NULL;
1584 }
1585 else {
1586 mawk_set_field0(MAWK, p, len);
1587 cdp = MAWK->restart_label;
1588
1589 if (TEST2(NR) != TWO_NUMS) {
1590 mawk_cast2_to_num(MAWK, NR);
1591 }
1592
1593 NR->d.dval += MAWK_NUM_ONE;
1594 MAWK->rt_nr++;
1595 FNR->d.dval += MAWK_NUM_ONE;
1596 MAWK->rt_fnr++;
1597 }
1598 }
1599 break;
1600
1601 case _RANGE_CHK:
1602 /* mawk_test a range pattern: pat1, pat2 { action }
1603 entry :
1604 cdp[0].op -- a flag, mawk_test pat1 if on else pat2
1605 cdp[1].op -- offset of pat2 code from cdp
1606 cdp[2].op -- offset of action code from cdp
1607 cdp[3].op -- offset of code after the action from cdp
1608 cdp[4] -- start of pat1 code
1609 */
1610 #define FLAG cdp[0].op
1611 #define PAT2 cdp[1].op
1612 #define ACTION cdp[2].op
1613 #define FOLLOW cdp[3].op
1614 #define PAT1 4
1615
1616 db1printstack(MAWK, "--start range", sp, fp);
1617
1618 /* FLAG: 0 means we are running the patten (we are between pat1 and pat2) */
1619 if (FLAG) { /* mawk_test again pat1 */
1620 /* prepare for executing pattern match for pat1 */
1621 mawk_push_exe_state(EXEST_RANGE1);
1622 cdp = cdp + PAT1;
1623 db1printf("matching pat1\n");
1624 break;
1625 }
1626
1627 range_chk_pat2:;
1628 /* mawk_test against pat2 */
1629 mawk_push_exe_state(EXEST_RANGE2);
1630 cdp = cdp + PAT2;
1631 db1printf("matching pat2\n");
1632 break;
1633
1634 case _RANGE_STOP: /* only for range patterns */
1635 cp = sp; /* remember the result of the pattern match expr */
1636 db1printstack(MAWK, "--stop cp", sp, fp);
1637 sp--;
1638 mawk_pop_exe_state();
1639 if (exest == EXEST_RANGE1) {
1640 t = mawk_test(MAWK, cp);
1641 mawk_cell_destroy(MAWK, cp);
1642 if (t) {
1643 FLAG = 0;
1644 goto range_chk_pat2;
1645 }
1646 else {
1647 cdp += FOLLOW;
1648 break; /* break the switch */
1649 }
1650 }
1651 else if (exest == EXEST_RANGE2) {
1652 /* pat2 and then perform the action */
1653 FLAG = mawk_test(MAWK, cp);
1654 mawk_cell_destroy(MAWK, cp);
1655 cdp += ACTION;
1656 }
1657 else
1658 mawk_bozo(MAWK, "wrong execution state when popping range stop frame");
1659 exest = EXEST_NORMAL;
1660 break;
1661
1662 /* function calls */
1663
1664 case _RET0:
1665 db1printf("RET0 on sp=%d\n", stackptr(sp));
1666 inc_sp();
1667 sp->type = C_NOINIT;
1668 /* fall thru */
1669
1670 case _RET:
1671
1672 #ifdef DEBUG
1673 if (sp != entry_sp + 1)
1674 mawk_bozo(MAWK, "ret");
1675 #endif
1676
1677 db1printstack(MAWK, "-- ret entry", sp, fp);
1678
1679 {
1680 mawk_cell_t retval;
1681 mawk_cell_t *pfp = fp;
1682 FBLOCK *cfbp;
1683 int cargs;
1684
1685 /* have to save retval in case the stack got relocated */
1686 mawk_cellcpy(MAWK, &retval, sp);
1687 mawk_cell_destroy(MAWK, sp);
1688 sp--;
1689 db1printf("RET before removing overhead (retval already removed) sp=%d\n", stackptr(sp));
1690 db1printstack(MAWK, "-- ret before overhead", sp, fp);
1691
1692 if (old_stack_base) { /* reset stack */
1693 /* move the return value */
1694 mawk_cellcpy(MAWK, old_sp + 1, &retval);
1695 mawk_cell_destroy(MAWK, &retval);
1696
1697 /* restore */
1698 mawk_zfree(MAWK, MAWK->stack_base, sizeof(mawk_cell_t) * EVAL_STACK_SIZE);
1699 MAWK->stack_base = old_stack_base;
1700 MAWK->stack_danger = old_stack_base + DANGER;
1701 sp = old_sp;
1702 }
1703
1704 /* return might be inside an aloop -- clear stack */
1705 CLEAR_ALOOP_STACK();
1706
1707 cfbp = call_fbp;
1708 cargs = call_a_args;
1709
1710 /* get back at the caller context */
1711 mawk_pop_exe_state();
1712 db1printf("RET after removing overhead sp=%d pfp=%d\n", stackptr(sp), stackptr(pfp));
1713
1714 if (cfbp != NULL) {
1715 db1printf("removing %d locals\n", pfp-sp+1);
1716 mawk_call_post(cfbp, cargs);
1717 }
1718 sp = pfp;
1719
1720 /* save retval to current sp (which might be in an older stack block) */
1721 mawk_cellcpy(MAWK, sp, &retval);
1722 mawk_cell_destroy(MAWK, &retval);
1723
1724 /* caller was not plain awk code, has to return immediately after the func */
1725 if (exest == EXEST_EXIT)
1726 goto out_funcret;
1727
1728 /* go on executing normally; we are back at the caller's context and
1729 sp contains the return value */
1730 }
1731 break;
1732
1733 case _CALL:
1734 {
1735 /* cdp[0] holds ptr to "function block"
1736 cdp[1] holds number of input arguments
1737 */
1738 mawk_cell_t *pfp;
1739 FBLOCK *fbp = (FBLOCK *) cdp++->ptr;
1740 int a_args = cdp++->op; /* actual/caller's number of args already pushed on stack */
1741
1742 /* might be just a C function */
1743 cp = mawk_call_c_func(MAWK, sp, fbp, a_args);
1744 if (cp != NULL) {
1745 /* C function call succeeded, new sp is returned by the user function */
1746 sp = cp;
1747 break;
1748 }
1749
1750 /* native awk user function */
1751 pfp = sp - a_args + 1;
1752 {
1753 mawk_call_pre();
1754
1755 db1printf("++ CALL sp=%d a_args(caller)=%d fbp->nargs(callee)=%d\n", stackptr(sp), a_args,fbp->nargs);
1756 mawk_push_exe_state(EXEST_NORMAL);
1757 aloop_state = NULL;
1758
1759 /*sp - RECURSION_OVERHEAD - fbp->nargs + a_args*/
1760 fp = pfp;
1761 db1printf("CALL fp=%d final-sp=%d\n", stackptr(fp), stackptr(sp));
1762
1763 call_fbp = fbp;
1764 call_a_args = a_args;
1765 cdp = fbp->code;
1766 db1printf("CALL new=%d\n", stackptr(sp));
1767 }
1768 }
1769 goto call_entry;
1770 case LOCATION:
1771 mawk_location_change(MAWK, cdp->op);
1772 cdp++;
1773 break;
1774 default:
1775 mawk_bozo(MAWK, "bad opcode");
1776 }
1777 } /* while */
1778
1779 /* got here because exit */
1780 out:;
1781 MAWK->sp = sp;
1782 db1printf("exe out sp=%d\n", stackptr(sp));
1783 return MAWK_EXER_DONE;
1784
1785 /* jump here to indicate return from a function; top of stack is the retval */
1786 out_funcret:;
1787 MAWK->sp = sp;
1788 db1printf("exe out_funcret sp=%d\n", stackptr(sp));
1789 return MAWK_EXER_FUNCRET;
1790
1791 /* jump here to indicate execution interrupted due to read block (no more input) */
1792 out_nomore:;
1793 mawk_push_exe_state(EXEST_NORMAL); /* for a later resume */
1794 MAWK->sp = sp;
1795 db1printf("exe out_nomore sp=%d\n", stackptr(sp));
1796 return MAWK_EXER_INT_READ;
1797
1798 /* jump here to indicate execution interrupted due to read block (no more input) */
1799 out_runlimit:;
1800 mawk_push_exe_state(EXEST_NORMAL); /* for a later resume */
1801 MAWK->sp = sp;
1802 db1printf("exe out_runlimit sp=%d\n", stackptr(sp));
1803 db1printstack(MAWK, "-- runlimit push", sp, fp);
1804 return MAWK_EXER_INT_RUNLIMIT;
1805
1806 /* jump here to interrupt execution before running main */
1807 out_sepmain:;
1808 mawk_push_exe_state(EXEST_NORMAL); /* for a later resume */
1809 MAWK->sp = sp;
1810 db1printf("exe separate main sp=%d\n", stackptr(sp));
1811 db1printstack(MAWK, "-- sepmain push", sp, fp);
1812 return MAWK_EXER_INT_SEPMAIN;
1813
1814
1815 /* jump here for hard exit; discards the whole stack! */
1816 out_exit:;
1817 /* if we hit exit, we sure won't need the eval stack anymore */
1818 MAWK->sp = MAWK->eval_stack;
1819 db1printf("exe out_exit sp=%d\n", stackptr(MAWK->sp));
1820 return MAWK_EXER_EXIT;
1821 }
1822
1823 /* entry point: start executing cdp (BEGIN, END or main) */
1824 void mawk_execute(mawk_state_t *MAWK, register INST *cdp, register mawk_cell_t *sp, mawk_cell_t *fp)
1825 {
1826 mawk_cell_t *old_stack_base = 0, *old_sp = 0; /* for moving the eval stack on deep recursion */
1827 ALOOP_STATE *aloop_state = (ALOOP_STATE *) 0;
1828 FBLOCK *call_fbp = NULL; /* user function being executed */
1829 int call_a_args = 0; /* number of caller args in user func being executed */
1830
1831 db1printf("=== mawk_execute()\n");
1832 mawk_push_exe_state(EXEST_EXIT); /* this will get execute to exit at the end */
1833 mawk_push_exe_state(EXEST_NORMAL);
1834 MAWK->sp = sp;
1835 mawk_execute_(MAWK);
1836 }
1837
1838 mawk_exec_result_t mawk_resume(mawk_state_t *MAWK)
1839 {
1840 db1printf("=== mawk_resume()\n");
1841 if (MAWK->eval_stack == MAWK->sp)
1842 return MAWK_EXER_ERR_NOSTACK;
1843 return mawk_execute_(MAWK);
1844 }
1845
1846 /* entry point: Call awk function fbp with a_args already pushed on
1847 the stack. sp is the stack pointer that is returned after the operation.
1848
1849 This function is called only from outside of execute.c, vm func calls
1850 are embedded in execute_().
1851 */
1852 mawk_exec_result_t mawk_call(mawk_state_t * MAWK, FBLOCK * fbp, int a_args, mawk_cell_t *res)
1853 {
1854 mawk_exec_result_t exer;
1855 mawk_cell_t *old_stack_base = 0, *old_sp = 0;
1856 ALOOP_STATE *aloop_state = (ALOOP_STATE *) 0;
1857 mawk_cell_t *sp = MAWK->sp;
1858 mawk_call_vars;
1859 mawk_cell_t *cp, *fp = sp - a_args+1;
1860 INST *cdp = fbp->code;
1861 FBLOCK *call_fbp = NULL; /* user function being executed */
1862 int call_a_args = 0; /* number of caller args in user func being executed */
1863
1864 db1printstack(MAWK, "=== mawk_call_do()\n", sp, fp);
1865
1866 /* might be just a C function */
1867 cp = mawk_call_c_func(MAWK, sp, fbp, a_args);
1868 if (cp != NULL) {
1869 MAWK->sp = cp;
1870 exer = MAWK_EXER_FUNCRET;
1871 goto copy_retv;
1872 }
1873
1874 {
1875 mawk_call_pre();
1876
1877 MAWK->sp = sp;
1878 db1printstack(MAWK, "mawk_call_do2()\n", sp, fp);
1879 mawk_push_exe_state(EXEST_EXIT);
1880 MAWK->sp = sp;
1881 db1printstack(MAWK, "mawk_call_do3()\n", sp, fp);
1882 mawk_push_exe_state(EXEST_NORMAL); /* to get mawk_execute_ to run our code */
1883 MAWK->sp = sp;
1884 db1printstack(MAWK, "mawk_call_do4()\n", sp, fp);
1885 MAWK->sp = sp;
1886 exer = mawk_execute_(MAWK);
1887 db1printstack(MAWK, "mawk_call_AFTER()\n", MAWK->sp, fp);
1888 }
1889
1890 copy_retv:;
1891 if (exer == MAWK_EXER_FUNCRET) {
1892 mawk_cellcpy(MAWK, res, MAWK->sp);
1893 mawk_cell_destroy(MAWK, MAWK->sp);
1894 MAWK->sp--;
1895 }
1896
1897 return exer;
1898 }
1899
1900
1901 /*
1902 return 0 if a numeric is zero else return non-zero
1903 return 0 if a string is "" else return non-zero
1904 */
1905 int mawk_test(mawk_state_t *MAWK, register mawk_cell_t *cp)
1906 {
1907 reswitch:
1908
1909 switch (cp->type) {
1910 case C_NOINIT:
1911 return 0;
1912 case C_STRNUM: /* mawk_test as a number */
1913 case C_NUM:
1914 return cp->d.dval != MAWK_NUM_ZERO;
1915 case C_STRING:
1916 return string(cp)->len;
1917 case C_MBSTRN:
1918 mawk_check_strnum(MAWK, cp);
1919 goto reswitch;
1920 default:
1921 mawk_bozo(MAWK, "bad cell type in call to mawk_test");
1922 }
1923 return 0; /*can't get here: shutup */
1924 }
1925
1926 /* compare cells at cp and cp+1 and
1927 frees STRINGs at those cells
1928 */
1929 static double compare(mawk_state_t *MAWK, register mawk_cell_t *cp)
1930 {
1931 int k;
1932
1933 reswitch:
1934
1935 switch (TEST2(cp)) {
1936 case TWO_NOINITS:
1937 return 0;
1938
1939 case TWO_NUMS:
1940 two_d:
1941 if (P_isnan_manual((cp + 1)->d.dval))
1942 return P_nan();
1943 if (P_isnan_manual(cp->d.dval))
1944 return P_nan();
1945 return cp->d.dval > (cp + 1)->d.dval ? 1 : cp->d.dval < (cp + 1)->d.dval ? -1 : 0;
1946
1947 case TWO_STRINGS:
1948 case STRING_AND_STRNUM:
1949 two_s:
1950 k = strcmp(string(cp)->str, string(cp + 1)->str);
1951 free_STRING(string(cp));
1952 free_STRING(string(cp + 1));
1953 return (double)k;
1954
1955 case NOINIT_AND_NUM:
1956 case NOINIT_AND_STRNUM:
1957 case NUM_AND_STRNUM:
1958 case TWO_STRNUMS:
1959 mawk_cast2_to_num(MAWK, cp);
1960 goto two_d;
1961 case NOINIT_AND_STRING:
1962 case NUM_AND_STRING:
1963 mawk_cast2_to_str(MAWK, cp);
1964 goto two_s;
1965 case TWO_MBSTRNS:
1966 mawk_check_strnum(MAWK, cp);
1967 mawk_check_strnum(MAWK, cp + 1);
1968 goto reswitch;
1969
1970 case NOINIT_AND_MBSTRN:
1971 case NUM_AND_MBSTRN:
1972 case STRING_AND_MBSTRN:
1973 case STRNUM_AND_MBSTRN:
1974 mawk_check_strnum(MAWK, cp->type == C_MBSTRN ? cp : cp + 1);
1975 goto reswitch;
1976
1977 default: /* there are no default cases */
1978 mawk_bozo(MAWK, "bad cell type passed to compare");
1979 }
1980 return 0; /* shut up */
1981 }
1982
1983 /* convert a number d to a field index $d -> $i */
1984 static int d_to_index(mawk_state_t *MAWK, mawk_num_t d)
1985 {
1986
1987 if (d > MAX_FIELD)
1988 mawk_rt_overflow(MAWK, "maximum number of fields", MAX_FIELD);
1989
1990 if (d >= MAWK_NUM_ZERO)
1991 return (int) d;
1992
1993 /* might include nan */
1994 mawk_rt_error(MAWK, "negative field index $%.6g", d);
1995 return 0; /* shutup */
1996 }
1997
1998 void mawk_dummy_execute_func(void) { (void)mawk_f2d(NULL); } /* suppress compiler warning on unused func */
0 #ifndef MAWK_EXECUTE_H
1 #define MAWK_EXECUTE_H
2
3 typedef enum mawk_exec_result_e {
4 MAWK_EXER_FUNCRET, /* function return, return value is on top of the stack */
5 MAWK_EXER_DONE, /* done with BEGIN or END */
6 MAWK_EXER_EXIT, /* script ran exit */
7 MAWK_EXER_INT_READ, /* was running BEGIN, END, main or function, got blocked in a read */
8 MAWK_EXER_INT_RUNLIMIT, /* was running BEGIN, END, main or function, reached run limit */
9 MAWK_EXER_INT_SEPMAIN, /* about to jump on main but separate exetuion of main is configured */
10 MAWK_EXER_ERR_NOSTACK /* can't resume: nothing's on the stack */
11 } mawk_exec_result_t;
12
13
14 /* resume execution of an interrupted script */
15 mawk_exec_result_t mawk_resume(mawk_state_t *MAWK);
16
17 mawk_exec_result_t mawk_call(mawk_state_t * MAWK, FBLOCK * fbp, int a_args, mawk_cell_t *res);
18 int mawk_test(mawk_state_t *MAWK, register mawk_cell_t *cp);
19
20 #endif
0 /* this is not a real header and is included in the middle of execute.c to
1 provide real or dummy call debug functionality */
2 /*#define CALLDEBUG*/
3
4 #ifdef CALLDEBUG
5 /* real prints */
6 #include <stdio.h>
7 #define db1printf(x...) fprintf(stderr, x)
8 #define stackptr(p) ((p) == NULL ? -1 : (p)-MAWK->eval_stack)
9 extern void mawk_print_cell(mawk_state_t *, mawk_cell_t *, FILE_NODE *);
10 static void db1printstack(mawk_state_t *MAWK, char *ann, mawk_cell_t *sp, mawk_cell_t *fp)
11 {
12 mawk_cell_t *c;
13 db1printf("%s\n", ann);
14 for(c = sp; c >= MAWK->eval_stack; c--) {
15 if (fp == c)
16 db1printf("*");
17 else
18 db1printf(" ");
19 db1printf("[%d] ", stackptr(c));
20 if (c->type == C_EXE_STTYPE) {
21 db1printf("exest=");
22 switch(c->d.vcnt) {
23 case EXEST_NORMAL: db1printf("EXEST_NORMAL\n"); break;
24 case EXEST_EXIT: db1printf("EXEST_EXIT\n"); break;
25 case EXEST_RANGE1: db1printf("EXEST_RANGE1\n"); break;
26 case EXEST_RANGE2: db1printf("EXEST_RANGE2\n"); break;
27 default: db1printf("EXEST_%d\n", c->d.vcnt); break;
28 }
29 }
30 else if (c->type == C_EXE_STATE)
31 db1printf("state=%p\n", c->ptr);
32 else if (c->type == C_ARR_REF)
33 db1printf("date=arr_ref=%p\n", c->ptr);
34 else {
35 db1printf("data=%d=", c->type);
36 mawk_print_cell(MAWK, c, MAWK->fnode_stderr);
37 db1printf("\n");
38 }
39 }
40 }
41 #else
42
43 /* dummy prints */
44 static void db1printf(const char *fmt, ...) { }
45 #define stackptr(p) 0
46 #define db1printstack(mawk, ann, sp, fp)
47 #endif
48
0 /********************************************
1 f2d.h
2
3 libmawk changes (C) 2018, Tibor 'Igor2' Palinkas;
4
5 This is a source file for libmawk, an implementation of
6 the AWK programming language.
7
8 libmawk is distributed without warranty under the terms of
9 the GNU General Public License, version 2, 1991.
10 ********************************************/
11
12 #ifndef MAWK_F2D_H
13 #define MAWK_F2D_H
14
15 typedef void (mawk_generic_func)();
16
17 /* C89 doesn't allow function pointer vs. data pointer casts */
18 union mawk_f2d_u {
19 void *data;
20 mawk_generic_func *func;
21 };
22
23 static void *mawk_f2d_(mawk_generic_func *func)
24 {
25 union mawk_f2d_u tmp;
26 tmp.func = func;
27 return tmp.data;
28 }
29
30 static mawk_generic_func *mawk_d2f_(void *data)
31 {
32 union mawk_f2d_u tmp;
33 tmp.data = data;
34 return tmp.func;
35 }
36
37 #define mawk_f2d(f) mawk_f2d_((mawk_generic_func *)(f))
38 #define mawk_d2f(d) mawk_d2f_((void *)(d))
39
40 #endif
0
1 /********************************************
2 fcall.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include "mawk.h"
16 #include "symtype.h"
17 #include "code.h"
18
19 /* This file has functions involved with type checking of
20 function calls
21 */
22
23 static FCALL_REC *first_pass(mawk_state_t *, FCALL_REC *);
24 static CA_REC *call_arg_check(mawk_state_t *, FBLOCK *, CA_REC *, INST *, unsigned);
25 static int arg_cnt_ok(mawk_state_t *, FBLOCK *, CA_REC *, unsigned);
26 static void relocate_arglist(CA_REC *, int, unsigned, int);
27
28 /* type checks a list of call arguments,
29 returns a list of arguments whose type is still unknown
30 */
31 static CA_REC *call_arg_check(mawk_state_t *MAWK, FBLOCK *callee, CA_REC *entry_list, INST *start, unsigned line_no)
32 {
33 /* start -> to locate patch */
34 /* line_no -> for error messages */
35 register CA_REC *q;
36 CA_REC *exit_list = (CA_REC *) 0;
37
38 MAWK->check_progress = 0;
39
40 /* loop :
41 take q off entry_list
42 mawk_test it
43 if OK mawk_zfree(MAWK, q) else put on exit_list */
44 while ((q = entry_list)) {
45 entry_list = q->link;
46
47 if (q->type == ST_NONE) {
48 /* try to infer the type */
49 /* it might now be in symbol table */
50 if (q->sym_p->type == ST_VAR) {
51 /* set type and patch */
52 q->type = CA_EXPR;
53 start[q->call_offset + 1].ptr = (PTR) q->sym_p->stval.cp;
54 }
55 else if (q->sym_p->type == ST_ARRAY) {
56 q->type = CA_ARRAY;
57 start[q->call_offset].op = A_PUSHA;
58 start[q->call_offset + 1].ptr = (PTR) q->sym_p->stval.array;
59 }
60 else { /* try to infer from callee */
61
62 switch (callee->typev[q->arg_num]) {
63 case ST_LOCAL_VAR:
64 q->type = CA_EXPR;
65 q->sym_p->type = ST_VAR;
66 q->sym_p->stval.cp = MAWK_ZMALLOC(MAWK, mawk_cell_t);
67 q->sym_p->stval.cp->type = C_NOINIT;
68 start[q->call_offset + 1].ptr = (PTR) q->sym_p->stval.cp;
69 break;
70
71 case ST_LOCAL_ARRAY:
72 q->type = CA_ARRAY;
73 q->sym_p->type = ST_ARRAY;
74 q->sym_p->stval.array = mawk_array_new(MAWK, NULL);
75 start[q->call_offset].op = A_PUSHA;
76 start[q->call_offset + 1].ptr = (PTR) q->sym_p->stval.array;
77 break;
78 }
79 }
80 }
81 else if (q->type == ST_LOCAL_NONE) {
82 /* try to infer the type */
83 if (*q->type_p == ST_LOCAL_VAR) {
84 /* set type , don't need to patch */
85 q->type = CA_EXPR;
86 }
87 else if (*q->type_p == ST_LOCAL_ARRAY) {
88 q->type = CA_ARRAY;
89 start[q->call_offset].op = LA_PUSHA;
90 /* offset+1 op is OK */
91 }
92 else { /* try to infer from callee */
93
94 switch (callee->typev[q->arg_num]) {
95 case ST_LOCAL_VAR:
96 q->type = CA_EXPR;
97 *q->type_p = ST_LOCAL_VAR;
98 /* do not need to patch */
99 break;
100
101 case ST_LOCAL_ARRAY:
102 q->type = CA_ARRAY;
103 *q->type_p = ST_LOCAL_ARRAY;
104 start[q->call_offset].op = LA_PUSHA;
105 break;
106 }
107 }
108 }
109
110 /* if we still do not know the type put on the new list
111 else type check */
112 if (q->type == ST_NONE || q->type == ST_LOCAL_NONE) {
113 q->link = exit_list;
114 exit_list = q;
115 }
116 else { /* type known */
117
118 if (callee->typev[q->arg_num] == ST_LOCAL_NONE)
119 callee->typev[q->arg_num] = q->type;
120 else if (q->type != callee->typev[q->arg_num])
121 mawk_compile_error(MAWK, "type error in arg(%d) in call to %s", q->arg_num + 1, callee->name);
122
123 MAWK_ZFREE(MAWK, q);
124 MAWK->check_progress = 1;
125 }
126 } /* while */
127
128 return exit_list;
129 }
130
131
132 static int arg_cnt_ok(mawk_state_t *MAWK, FBLOCK *fbp, CA_REC *q, unsigned line_no)
133 {
134 if ((int) q->arg_num >= (int) fbp->nargs)
135 /* casts shutup stupid warning from solaris sun cc */
136 {
137 mawk_compile_error(MAWK, "too many arguments in call to %s", fbp->name);
138 return 0;
139 }
140 else
141 return 1;
142 }
143
144 /* function calls whose arg types need checking
145 are stored on this list */
146
147
148 /* on first pass thru the resolve list
149 we check :
150 if forward referenced functions were really defined
151 if right number of arguments
152 and compute call_start which is now known
153 */
154
155 static FCALL_REC *first_pass(mawk_state_t *MAWK, register FCALL_REC *p)
156 {
157 FCALL_REC dummy;
158 register FCALL_REC *q = &dummy; /* trails p */
159
160 q->link = p;
161 while (p) {
162 if (!p->callee->code) {
163 /* callee never defined */
164 if (!MAWK->suppress_undefined_function_warning)
165 mawk_compile_error(MAWK, "function %s never defined", p->callee->name);
166 /* delete p from list */
167 q->link = p->link;
168 /* don't worry about freeing memory, we'll exit soon */
169 }
170 /* note p->arg_list starts with last argument */
171 else if (!p->arg_list /* nothing to do */ ||
172 (!p->arg_cnt_checked && !arg_cnt_ok(MAWK, p->callee, p->arg_list, p->line_no))) {
173 q->link = p->link; /* delete p */
174 /* the ! arg_list case is not an error so free memory */
175 MAWK_ZFREE(MAWK, p);
176 }
177 else {
178 /* keep p and set call_start */
179 q = p;
180 switch (p->call_scope) {
181 case SCOPE_MAIN:
182 p->call_start = MAWK->main_start;
183 break;
184
185 case SCOPE_BEGIN:
186 p->call_start = MAWK->begin_start;
187 break;
188
189 case SCOPE_END:
190 p->call_start = MAWK->end_start;
191 break;
192
193 case SCOPE_FUNCT:
194 p->call_start = p->call->code;
195 break;
196 }
197 }
198 p = q->link;
199 }
200 return dummy.link;
201 }
202
203 /* continuously walk the resolve_list making type deductions
204 until this list goes empty or no more progress can be made
205 (An example where no more progress can be made is at end of file
206 */
207
208 void mawk_resolve_fcalls(mawk_state_t * MAWK)
209 {
210 register FCALL_REC *p, *old_list, *new_list;
211 int progress; /* a flag */
212
213 old_list = first_pass(MAWK, MAWK->resolve_list);
214 new_list = (FCALL_REC *) 0;
215 progress = 0;
216
217 while (1) {
218 if (!old_list) {
219 /* flop the lists */
220 old_list = new_list;
221 if (!old_list /* nothing left */
222 || !progress /* can't do any more */ )
223 return;
224
225 new_list = (FCALL_REC *) 0;
226 progress = 0;
227 }
228
229 p = old_list;
230 old_list = p->link;
231
232 if ((p->arg_list = call_arg_check(MAWK, p->callee, p->arg_list, p->call_start, p->line_no))) {
233 /* still have work to do , put on new_list */
234 progress |= MAWK->check_progress;
235 p->link = new_list;
236 new_list = p;
237 }
238 else {
239 /* done with p */
240 progress = 1;
241 MAWK_ZFREE(MAWK, p);
242 }
243 }
244 }
245
246 /* the mawk_parser has just reduced a function call ;
247 the info needed to type check is passed in. If type checking
248 can not be done yet (most common reason -- function referenced
249 but not defined), a node is added to the resolve list.
250 */
251 void mawk_check_fcall(mawk_state_t *MAWK, FBLOCK *callee, int call_scope, int move_level, FBLOCK *call, CA_REC *arg_list, unsigned line_no)
252 {
253 FCALL_REC *p;
254
255 if (!callee->code) {
256 /* forward reference to a function to be defined later */
257 p = MAWK_ZMALLOC(MAWK, FCALL_REC);
258 p->callee = callee;
259 p->call_scope = call_scope;
260 p->move_level = move_level;
261 p->call = call;
262 p->arg_list = arg_list;
263 p->arg_cnt_checked = 0;
264 p->line_no = line_no;
265 /* add to resolve list */
266 p->link = MAWK->resolve_list;
267 MAWK->resolve_list = p;
268 }
269 else if (arg_list && arg_cnt_ok(MAWK, callee, arg_list, line_no)) {
270 /* usually arg_list disappears here and all is well
271 otherwise add to resolve list */
272
273 if ((arg_list = call_arg_check(MAWK, callee, arg_list, mawk_code_base, line_no))) {
274 p = MAWK_ZMALLOC(MAWK, FCALL_REC);
275 p->callee = callee;
276 p->call_scope = call_scope;
277 p->move_level = move_level;
278 p->call = call;
279 p->arg_list = arg_list;
280 p->arg_cnt_checked = 1;
281 p->line_no = line_no;
282 /* add to resolve list */
283 p->link = MAWK->resolve_list;
284 MAWK->resolve_list = p;
285 }
286 }
287 }
288
289
290 /* code_pop() has just moved some code. If this code contains
291 a function call, it might need to be relocated on the
292 resolve list too. This function does it.
293 */
294 void mawk_relocate_resolve_list(mawk_state_t *MAWK, int scope, int move_level, FBLOCK *fbp, int orig_offset, unsigned len, int delta)
295 {
296 /* delta -> relocation distance */
297 FCALL_REC *p = MAWK->resolve_list;
298
299 while (p) {
300 if (scope == p->call_scope && move_level == p->move_level && (scope == SCOPE_FUNCT ? fbp == p->call : 1)) {
301 relocate_arglist(p->arg_list, orig_offset, len, delta);
302 }
303 p = p->link;
304 }
305 }
306
307 static void relocate_arglist(CA_REC *arg_list, int offset, unsigned len, int delta)
308 {
309 register CA_REC *p;
310
311 if (!arg_list)
312 return;
313
314 p = arg_list;
315 /* all nodes must be relocated or none, so mawk_test the
316 first one */
317
318 /* Note: call_offset is always set even for args that don't need to
319 be patched so that this check works. */
320 if (p->call_offset < offset || p->call_offset >= offset + len)
321 return;
322
323 /* relocate the whole list */
324 do {
325 p->call_offset += delta;
326 p = p->link;
327 }
328 while (p);
329 }
330
331 /* example where typing cannot progress
332
333 { f(z) }
334
335 function f(x) { print NR }
336
337 # this is legal, does something useful, but absurdly written
338 # We have to design so this works
339 */
0
1 /********************************************
2 field.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef FIELD_H
17 #define FIELD_H 1
18
19 void mawk_set_field0(mawk_state_t *, char *, unsigned);
20 void mawk_split_field0(mawk_state_t *);
21 int mawk_space_split(mawk_state_t *, char *, unsigned);
22 int mawk_re_split(mawk_state_t *, char *, PTR);
23 int mawk_null_split(mawk_state_t *, char *);
24 void mawk_field_assign(mawk_state_t *, mawk_cell_t *, mawk_cell_t *);
25 char *mawk_is_string_split(PTR, unsigned *);
26 void mawk_bifunct_target_assign(mawk_state_t *, mawk_cell_t *, mawk_cell_t *);
27 mawk_cell_t *mawk_slow_field_ptr(mawk_state_t *, int);
28 int mawk_field_addr_to_index(mawk_state_t *, mawk_cell_t *);
29 void set_binmode(int);
30 void mawk_load_pfield(mawk_state_t *, char *, mawk_cell_t *);
31
32 #ifdef MAWK_MEM_PEDANTIC
33 void mawk_field_uninit(mawk_state_t * MAWK);
34 #endif
35
36 /* some compilers choke on (NF-field) in a case statement
37 even though it's constant so ...
38 */
39 #define MAWK_NF_field (MAX_SPLIT+1)
40 #define MAWK_RS_field (MAX_SPLIT+2)
41 #define MAWK_FS_field (MAX_SPLIT+3)
42 #define MAWK_CONVFMT_field (MAX_SPLIT+4)
43 #define MAWK_OFMT_field (MAX_SPLIT+5)
44
45 /* index to mawk_cell_t * for a field */
46 #define field_ptr(i) ((i)<=MAX_SPLIT ? MAWK->field+(i):mawk_slow_field_ptr(MAWK, i))
47
48 /* the pseudo fields, assignment has side effects */
49 #define MAWK_NF (MAWK->field+MAX_SPLIT+1) /* must be first */
50 #define MAWK_RS (MAWK->field+MAX_SPLIT+2)
51 #define MAWK_FS (MAWK->field+MAX_SPLIT+3)
52 #define MAWK_CONVFMT (MAWK->field+MAX_SPLIT+4)
53 #define MAWK_OFMT (MAWK->field+MAX_SPLIT+5) /* must be last */
54
55 #define LAST_PFIELD MAWK_OFMT
56
57 /* a shadow type for RS and FS */
58 #define SEP_SPACE 0
59 #define SEP_CHAR 1
60 #define SEP_STR 2
61 #define SEP_RE 3
62 #define SEP_MLR 4
63
64 /* types for splitting mawk_overflow */
65
66
67 #endif /* FIELD_H */
0 /********************************************
1 field_common.c - $ field operation required in both compile and execute time
2
3 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991, Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14 #include "mawk.h"
15 #include "field.h"
16 #include "init.h"
17 #include "memory.h"
18 #include "scan.h"
19 #include "bi_vars.h"
20 #include "repl.h"
21 #include "regexp.h"
22
23 void mawk_load_pfield(mawk_state_t *MAWK, char *name, mawk_cell_t *cp)
24 {
25 SYMTAB *stp;
26
27 stp = mawk_insert(MAWK, name);
28 stp->type = ST_FIELD;
29 stp->stval.cp = cp;
30 }
31
32
33 int mawk_field_addr_to_index(mawk_state_t *MAWK, mawk_cell_t *cp)
34 {
35 mawk_cell_t **p = MAWK->fbank;
36
37 while (cp < *p || cp >= *p + FBANK_SZ)
38 p++;
39
40 return ((p - MAWK->fbank) << FB_SHIFT) + (cp - *p);
41 }
42
43 /*------- more than 1 fbank needed ------------*/
44
45 /*
46 compute the address of a field with index
47 > MAX_SPLIT
48 */
49 mawk_cell_t *mawk_slow_field_ptr(mawk_state_t *MAWK, register int i)
50 {
51
52 if (i > MAWK->max_field) {
53 int j;
54
55 if (i > MAX_FIELD)
56 mawk_rt_overflow(MAWK, "maximum number of fields", MAX_FIELD);
57
58 j = 1;
59 while (MAWK->fbank[j])
60 j++;
61
62 do {
63 MAWK->fbank[j] = (mawk_cell_t *) mawk_zmalloc(MAWK, sizeof(mawk_cell_t) * FBANK_SZ);
64 memset(MAWK->fbank[j], 0, sizeof(mawk_cell_t) * FBANK_SZ);
65 j++;
66 MAWK->max_field += FBANK_SZ;
67 }
68 while (i > MAWK->max_field);
69 }
70
71 return &MAWK->fbank[i >> FB_SHIFT][i & (FBANK_SZ - 1)];
72 }
73
74
75 /* mawk_initialize $0 and the pseudo fields */
76 void mawk_field_init(mawk_state_t * MAWK)
77 {
78 MAWK->field[0].type = C_STRING;
79 MAWK->field[0].ptr = (PTR) & MAWK->null_str;
80 MAWK->null_str.ref_cnt++;
81
82 mawk_load_pfield(MAWK, "NF", MAWK_NF);
83 MAWK_NF->type = C_NUM;
84 MAWK_NF->d.dval = MAWK_NUM_ZERO;
85
86 mawk_load_pfield(MAWK, "RS", MAWK_RS);
87 MAWK_RS->type = C_STRING;
88 MAWK_RS->ptr = (PTR) mawk_new_STRING(MAWK, "\n");
89 /* rs_shadow already set */
90
91 mawk_load_pfield(MAWK, "FS", MAWK_FS);
92 MAWK_FS->type = C_STRING;
93 MAWK_FS->ptr = (PTR) mawk_new_STRING(MAWK, " ");
94 /* fs_shadow is already set */
95
96 mawk_load_pfield(MAWK, "OFMT", MAWK_OFMT);
97 MAWK_OFMT->type = C_STRING;
98 MAWK_OFMT->ptr = (PTR) mawk_new_STRING(MAWK, "%.6g");
99
100 mawk_load_pfield(MAWK, "CONVFMT", MAWK_CONVFMT);
101 MAWK_CONVFMT->type = C_STRING;
102 MAWK_CONVFMT->ptr = MAWK_OFMT->ptr;
103 string(MAWK_OFMT)->ref_cnt++;
104 }
105
106 #ifdef MAWK_MEM_PEDANTIC
107 void mawk_field_uninit(mawk_state_t * MAWK)
108 {
109 mawk_delete(MAWK, "NF", 1);
110 mawk_delete(MAWK, "RS", 1);
111 mawk_delete(MAWK, "FS", 1);
112 mawk_delete(MAWK, "OFMT", 1);
113 mawk_delete(MAWK, "CONVFMT", 1);
114 }
115 #endif
0
1 /********************************************
2 field.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include <stdio.h>
16 #include "mawk.h"
17 #include "field.h"
18 #include "init.h"
19 #include "memory.h"
20 #include "scan.h"
21 #include "bi_vars.h"
22 #include "repl.h"
23 #include "regexp.h"
24 #include "cell.h"
25
26 static void build_field0(mawk_state_t *);
27 static void set_rs_shadow(mawk_state_t *);
28 static void load_field_ov(mawk_state_t *);
29
30 static void set_rs_shadow(mawk_state_t * MAWK)
31 {
32 mawk_cell_t c;
33 mawk_string_t *sval;
34 char *s;
35 unsigned len;
36
37 if (MAWK->posix_space_flag && MAWK->mawk_state == EXECUTION)
38 MAWK->scan_code['\n'] = SC_UNEXPECTED;
39
40 if (MAWK->rs_shadow.type == SEP_STR) {
41 free_STRING((mawk_string_t *) MAWK->rs_shadow.ptr);
42 }
43
44 mawk_cellcpy(MAWK, &c, MAWK_RS);
45 mawk_cast_for_split(MAWK, &c);
46 switch (c.type) {
47 case C_RE:
48 if ((s = mawk_is_string_split(c.ptr, &len))) {
49 if (len == 1) {
50 MAWK->rs_shadow.type = SEP_CHAR;
51 MAWK->rs_shadow.c = s[0];
52 }
53 else {
54 MAWK->rs_shadow.type = SEP_STR;
55 MAWK->rs_shadow.ptr = (PTR) mawk_new_STRING(MAWK, s);
56 }
57 }
58 else {
59 MAWK->rs_shadow.type = SEP_RE;
60 MAWK->rs_shadow.ptr = c.ptr;
61 }
62 break;
63
64 case C_SPACE:
65 MAWK->rs_shadow.type = SEP_CHAR;
66 MAWK->rs_shadow.c = ' ';
67 break;
68
69 case C_SNULL: /* RS becomes one or more blank lines */
70 if (MAWK->mawk_state == EXECUTION)
71 MAWK->scan_code['\n'] = SC_SPACE;
72 MAWK->rs_shadow.type = SEP_MLR;
73 sval = mawk_new_STRING(MAWK, "\n\n+");
74 MAWK->rs_shadow.ptr = mawk_re_compile(MAWK, sval);
75 free_STRING(sval);
76 break;
77
78 default:
79 mawk_bozo(MAWK, "bad cell in set_rs_shadow");
80 }
81 }
82
83
84 void mawk_set_field0(mawk_state_t *MAWK, char *s, unsigned len)
85 {
86 mawk_cell_destroy(MAWK, &MAWK->field[0]);
87 MAWK->nf = -1;
88
89 if (len) {
90 MAWK->field[0].type = C_MBSTRN;
91 MAWK->field[0].ptr = (PTR) mawk_new_STRING0(MAWK, len);
92 memcpy(string(&MAWK->field[0])->str, s, len);
93 }
94 else {
95 MAWK->field[0].type = C_STRING;
96 MAWK->field[0].ptr = (PTR) & MAWK->null_str;
97 MAWK->null_str.ref_cnt++;
98 }
99 }
100
101
102
103 /* split field[0] into $1, $2 ... and set NF */
104
105 void mawk_split_field0(mawk_state_t * MAWK)
106 {
107 register mawk_cell_t *cp;
108 register int cnt;
109 mawk_cell_t c; /* copy field[0] here if not string */
110
111
112 if (MAWK->field[0].type < C_STRING) {
113 mawk_cellcpy(MAWK, &c, MAWK->field + 0);
114 mawk_cast1_to_str(MAWK, &c);
115 cp = &c;
116 }
117 else
118 cp = &MAWK->field[0];
119
120 if (string(cp)->len == 0)
121 MAWK->nf = 0;
122 else {
123 switch (MAWK->fs_shadow.type) {
124 case C_SNULL: /* FS == "" */
125 MAWK->nf = mawk_null_split(MAWK, string(cp)->str);
126 break;
127
128 case C_SPACE:
129 MAWK->nf = mawk_space_split(MAWK, string(cp)->str, string(cp)->len);
130 break;
131
132 default:
133 MAWK->nf = mawk_re_split(MAWK, string(cp)->str, MAWK->fs_shadow.ptr);
134 break;
135 }
136
137 }
138
139 mawk_cell_destroy(MAWK, MAWK_NF);
140 MAWK_NF->type = C_NUM;
141 MAWK_NF->d.dval = (mawk_num_t) MAWK->nf;
142
143 if (MAWK->nf > MAX_SPLIT) {
144 cnt = MAX_SPLIT;
145 load_field_ov(MAWK);
146 }
147 else
148 cnt = MAWK->nf;
149
150 while (cnt > 0) {
151 mawk_cell_destroy(MAWK, MAWK->field + cnt);
152 MAWK->field[cnt].ptr = (PTR) split_buff[cnt - 1];
153 MAWK->field[cnt--].type = C_MBSTRN;
154 }
155
156 if (cp == &c) {
157 free_STRING(string(cp));
158 }
159 }
160
161 /* construct field[0] from the other fields */
162
163 static void build_field0(mawk_state_t * MAWK)
164 {
165 #ifdef DEBUG
166 if (MAWK->nf < 0)
167 mawk_bozo(MAWK, "nf <0 in build_field0");
168 #endif
169
170 mawk_cell_destroy(MAWK, MAWK->field + 0);
171
172 if (MAWK->nf == 0) {
173 MAWK->field[0].type = C_STRING;
174 MAWK->field[0].ptr = (PTR) & MAWK->null_str;
175 MAWK->null_str.ref_cnt++;
176 }
177 else if (MAWK->nf == 1) {
178 mawk_cellcpy(MAWK, MAWK->field, MAWK->field + 1);
179 }
180 else {
181 mawk_cell_t c;
182 mawk_string_t *ofs, *tail;
183 unsigned len;
184 register mawk_cell_t *cp;
185 register char *p, *q;
186 int cnt;
187 mawk_cell_t **fbp, *cp_limit;
188
189
190 mawk_cellcpy(MAWK, &c, OFS);
191 mawk_cast1_to_str(MAWK, &c);
192 ofs = (mawk_string_t *) c.ptr;
193 mawk_cellcpy(MAWK, &c, field_ptr(MAWK->nf));
194 mawk_cast1_to_str(MAWK, &c);
195 tail = (mawk_string_t *) c.ptr;
196 cnt = MAWK->nf - 1;
197
198 len = cnt * ofs->len + tail->len;
199
200 fbp = MAWK->fbank;
201 cp_limit = MAWK->field + FBANK_SZ;
202 cp = MAWK->field + 1;
203
204 while (cnt-- > 0) {
205 if (cp->type < C_STRING) { /* use the string field temporarily */
206 if (cp->type == C_NOINIT) {
207 cp->ptr = (PTR) & MAWK->null_str;
208 MAWK->null_str.ref_cnt++;
209 }
210 else { /* its a number */
211
212 Int ival;
213 char xbuff[260];
214
215 ival = mawk_d_to_I(cp->d.dval);
216 if (ival == cp->d.dval)
217 sprintf(xbuff, INT_FMT, ival);
218 else
219 sprintf(xbuff, string(MAWK_CONVFMT)->str, cp->d.dval);
220
221 cp->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
222 }
223 }
224
225 len += string(cp)->len;
226
227 if (++cp == cp_limit) {
228 cp = *++fbp;
229 cp_limit = cp + FBANK_SZ;
230 }
231
232 }
233
234 MAWK->field[0].type = C_STRING;
235 MAWK->field[0].ptr = (PTR) mawk_new_STRING0(MAWK, len);
236
237 p = string(MAWK->field)->str;
238
239 /* walk it again , putting things together */
240 cnt = MAWK->nf - 1;
241 fbp = MAWK->fbank;
242 cp = MAWK->field + 1;
243 cp_limit = MAWK->field + FBANK_SZ;
244 while (cnt-- > 0) {
245 memcpy(p, string(cp)->str, string(cp)->len);
246 p += string(cp)->len;
247 /* if not really string, free temp use of ptr */
248 if (cp->type < C_STRING) {
249 free_STRING(string(cp));
250 }
251 if (++cp == cp_limit) {
252 cp = *++fbp;
253 cp_limit = cp + FBANK_SZ;
254 }
255 /* add the separator */
256 q = ofs->str;
257 while (*q)
258 *p++ = *q++;
259 }
260 /* tack tail on the end */
261 memcpy(p, tail->str, tail->len);
262
263 /* cleanup */
264 free_STRING(tail);
265 free_STRING(ofs);
266 }
267 }
268
269 /* We are assigning to a mawk_cell_t and we aren't sure if its
270 a field */
271
272 void mawk_bifunct_target_assign(mawk_state_t *MAWK, register mawk_cell_t *target_, mawk_cell_t *source)
273 {
274 mawk_cell_t *target = target_->ptr; /* target is assumed to be the varref */
275
276 if (target_->type == C_ARR_REF_BT) {
277 /* reference to an array member: ->ptr is the array, ->d.idx_str is the zmalloc'd string cell */
278 mawk_array_set(MAWK, (mawk_array_t)target_->ptr, target_->d.idx_cell, source);
279 mawk_cell_destroy(MAWK, target_->d.idx_cell);
280 mawk_zfree(MAWK, target_->d.idx_cell, sizeof(mawk_cell_t));
281 target_->type = C_NOINIT; /* don't need to destroy this: it's a special arr ref */
282 return ;
283 }
284
285 /* original code dealing with a normal varref */
286 if (target >= MAWK->field && target <= LAST_PFIELD)
287 mawk_field_assign(MAWK, target, source);
288 else {
289 mawk_cell_t **p = MAWK->fbank + 1;
290
291 while (*p) {
292 if (target >= *p && target < *p + FBANK_SZ) {
293 mawk_field_assign(MAWK, target, source);
294 return;
295 }
296 p++;
297 }
298 /* its not a field */
299 mawk_cell_destroy(MAWK, target);
300 mawk_cellcpy(MAWK, target, source);
301 }
302 }
303
304 /*
305 $0 split into more than MAX_SPLIT fields,
306 $(MAX_FIELD+1) ... are on the split_ov_list.
307 Copy into fields which start at fbank[1]
308 */
309
310 static void load_field_ov(mawk_state_t * MAWK)
311 {
312 register SPLIT_OV *p; /* walks split_ov_list */
313 register mawk_cell_t *cp; /* target of copy */
314 int j; /* current fbank[] */
315 mawk_cell_t *cp_limit; /* change fbank[] */
316 SPLIT_OV *q; /* trails p */
317
318 /* make sure the fields are allocated */
319 mawk_slow_field_ptr(MAWK, MAWK->nf);
320
321 p = MAWK->split_ov_list;
322 MAWK->split_ov_list = (SPLIT_OV *) 0;
323 j = 1;
324 cp = MAWK->fbank[j];
325 cp_limit = cp + FBANK_SZ;
326 while (p) {
327 mawk_cell_destroy(MAWK, cp);
328 cp->type = C_MBSTRN;
329 cp->ptr = (PTR) p->sval;
330
331 if (++cp == cp_limit) {
332 cp = MAWK->fbank[++j];
333 cp_limit = cp + FBANK_SZ;
334 }
335
336 q = p;
337 p = p->link;
338 MAWK_ZFREE(MAWK, q);
339 }
340 }
341
342 /*
343 assign mawk_cell_t *cp to field or pseudo field
344 and take care of all side effects
345 */
346 void mawk_field_assign(mawk_state_t *MAWK, register mawk_cell_t *fp, mawk_cell_t *cp)
347 {
348 mawk_cell_t c;
349 int i, j;
350
351 /* the most common case first */
352 if (fp == MAWK->field) {
353 mawk_cell_destroy(MAWK, MAWK->field);
354 mawk_cellcpy(MAWK, fp, cp);
355 MAWK->nf = -1;
356 return;
357 }
358
359 /* its not important to do any of this fast */
360
361 if (MAWK->nf < 0)
362 mawk_split_field0(MAWK);
363
364 switch (i = (fp - MAWK->field)) {
365
366 case MAWK_NF_field:
367
368 mawk_cell_destroy(MAWK, MAWK_NF);
369 mawk_cellcpy(MAWK, &c, cp);
370 mawk_cellcpy(MAWK, MAWK_NF, &c);
371 if (c.type != C_NUM)
372 mawk_cast1_to_num(MAWK, &c);
373
374 if ((j = d_to_i(c.d.dval)) < 0)
375 mawk_rt_error(MAWK, "negative value assigned to NF");
376
377 if (j > MAWK->nf)
378 for (i = MAWK->nf + 1; i <= j; i++) {
379 cp = field_ptr(i);
380 mawk_cell_destroy(MAWK, cp);
381 cp->type = C_STRING;
382 cp->ptr = (PTR) & MAWK->null_str;
383 MAWK->null_str.ref_cnt++;
384 }
385
386 MAWK->nf = j;
387 build_field0(MAWK);
388 break;
389
390 case MAWK_RS_field:
391 mawk_cell_destroy(MAWK, MAWK_RS);
392 mawk_cellcpy(MAWK, MAWK_RS, cp);
393 set_rs_shadow(MAWK);
394 break;
395
396 case MAWK_FS_field:
397 mawk_cell_destroy(MAWK, MAWK_FS);
398 mawk_cellcpy(MAWK, MAWK_FS, cp);
399 mawk_cellcpy(MAWK, &MAWK->fs_shadow, MAWK_FS);
400 mawk_cast_for_split(MAWK, &MAWK->fs_shadow);
401 break;
402
403 case MAWK_OFMT_field:
404 case MAWK_CONVFMT_field:
405 /* If the user does something stupid with OFMT or CONVFMT,
406 we could crash.
407 We'll make an attempt to protect ourselves here. This is
408 why OFMT and CONVFMT are pseudo fields.
409
410 The ptrs of OFMT and CONVFMT always have a valid mawk_string_t,
411 even if assigned a NUM or NOINIT
412 */
413
414 free_STRING(string(fp));
415 mawk_cellcpy(MAWK, fp, cp);
416 if (fp->type < C_STRING) /* !! */
417 fp->ptr = (PTR) mawk_new_STRING(MAWK, "%.6g");
418 else if (fp == MAWK_CONVFMT) {
419 /* It's a string, but if it's really goofy and CONVFMT,
420 it could still mawk_damage us. Test it .
421 */
422 char xbuff[512];
423
424 xbuff[256] = 0;
425 sprintf(xbuff, string(fp)->str, 3.1459);
426 if (xbuff[256])
427 mawk_rt_error(MAWK, "CONVFMT assigned unusable value");
428 }
429 break;
430
431 default: /* $1 or $2 or ... */
432 mawk_cell_destroy(MAWK, fp);
433 mawk_cellcpy(MAWK, fp, cp);
434
435 if (i < 0 || i > MAX_SPLIT)
436 i = mawk_field_addr_to_index(MAWK, fp);
437
438 if (i > MAWK->nf) {
439 for (j = MAWK->nf + 1; j < i; j++) {
440 cp = field_ptr(j);
441 mawk_cell_destroy(MAWK, cp);
442 cp->type = C_STRING;
443 cp->ptr = (PTR) & MAWK->null_str;
444 MAWK->null_str.ref_cnt++;
445 }
446 MAWK->nf = i;
447 mawk_cell_destroy(MAWK, MAWK_NF);
448 MAWK_NF->type = C_NUM;
449 MAWK_NF->d.dval = (mawk_num_t) i;
450 }
451
452 build_field0(MAWK);
453
454 }
455 }
0 /********************************************
1 files.c
2
3 libmawk changes (C) 2009-2013, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991-94. Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14 #include "conf.h"
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include "mawk.h"
19 #include "files.h"
20 #include "memory.h"
21 #include "fin.h"
22 #include "vio.h"
23
24 #ifdef PATH_MAX
25 #define PATH_BUFF_SIZE PATH_MAX
26 #else
27 #define PATH_BUFF_SIZE 1024
28 #endif
29
30 /* mawk_find a file on file_list */
31 FILE_NODE *mawk_file_find(mawk_state_t *MAWK, mawk_string_t *sval, int type, int create)
32 {
33 register FILE_NODE *p = MAWK->file_list;
34 FILE_NODE *q = (FILE_NODE *) 0;
35 const char *name_orig = sval->str;
36 const char *name;
37 char name_buff[PATH_BUFF_SIZE];
38 mawk_vio_t *vf;
39
40 if (MAWK->file_name_rewrite != NULL)
41 name = MAWK->file_name_rewrite(name_orig, name_buff, sizeof(name_buff), type);
42 else
43 name = name_orig;
44
45 if (name == NULL)
46 goto out_failure;
47
48 /* rewrite - to be /dev/stdin so we never have 2 names for the same thing */
49 if ((name[0] == '-') && (name[1] == '\0'))
50 name = "/dev/stdin";
51
52 while (1) {
53 if (!p) {
54 if (!create)
55 goto nocreate_failure;
56 /* open a new one */
57 p = MAWK_ZMALLOC(MAWK, FILE_NODE);
58
59 p->vf = NULL;
60 p->fin = NULL;
61
62 switch (p->type = type) {
63 case F_TRUNC:
64 p->vf = mawk_vio_open(MAWK, name, MAWK_VIO_O_TRUNC);
65 if (p->vf == NULL)
66 goto out_failure;
67 p->vf->refco = 1;
68 break;
69
70 case F_APPEND:
71 p->vf = mawk_vio_open(MAWK, name, MAWK_VIO_O_APPEND);
72 if (p->vf == NULL)
73 goto out_failure;
74 p->vf->refco = 1;
75 break;
76
77 case F_IN:
78 if ((p->fin = (PTR) mawk_fin_alloc(MAWK, p)) == NULL) {
79 mawk_zfree(MAWK, p, sizeof(FILE_NODE));
80 return (PTR) 0;
81 }
82 p->vf = mawk_vio_open(MAWK, name, MAWK_VIO_I);
83 if (p->vf == NULL) {
84 mawk_fin_free(MAWK, p->fin);
85 mawk_zfree(MAWK, p, sizeof(FILE_NODE));
86 return (PTR) 0;
87 }
88 p->vf->refco = 1;
89 break;
90
91 case PIPE_OUT:
92 case PIPE_IN:
93 vf = mawk_vio_open_pipe(MAWK, name, type);
94 if (vf == NULL) {
95 if (type == PIPE_OUT) {
96 goto out_failure;
97 }
98 else {
99 mawk_zfree(MAWK, p, sizeof(FILE_NODE));
100 return (PTR) 0;
101 }
102 }
103 if (type == PIPE_IN)
104 p->fin = mawk_fin_alloc(MAWK, p);
105 p->vf = vf;
106 p->vf->refco = 1;
107 break;
108
109 #ifdef DEBUG
110 default:
111 mawk_bozo(MAWK, "bad file type");
112 #endif
113 }
114 /* successful open */
115 if (name != name_orig) {
116 /* name has been rewritten, have to alloc a new string */
117 p->name = mawk_new_STRING(MAWK, name);
118 }
119 else
120 p->name = sval;
121 sval->ref_cnt++;
122 break; /* while loop */
123 }
124
125 /* search is by name and type */
126 if ((strcmp(name, p->name->str) == 0 && ((p->type == type) ||
127 /* no distinction between F_APPEND and F_TRUNC here */
128 (p->type >= F_APPEND && type >= F_APPEND))))
129 {
130 /* found */
131 if (!q) /*at front of list */
132 return p;
133 /* delete from list for move to front */
134 q->link = p->link;
135 break; /* while loop */
136 }
137
138 q = p;
139 p = p->link;
140 } /* end while loop */
141
142 /* put p at the front of the list */
143 p->link = MAWK->file_list;
144 return (MAWK->file_list = p);
145
146 out_failure:;
147 mawk_errmsg(MAWK, errno, "cannot open \"%s\" for output", name);
148 mawk_exitval(MAWK, 2, NULL);
149 return NULL;
150
151 nocreate_failure:;
152 mawk_errmsg(MAWK, errno, "cannot open \"%s\" - it does not exist in current context and should not be created now", name);
153 mawk_exitval(MAWK, 2, NULL);
154 return NULL;
155 }
156
157 FILE_NODE *mawk_file_find_(mawk_state_t *MAWK, const char *name, int type, int create)
158 {
159 FILE_NODE *f;
160 mawk_string_t *sval = mawk_new_STRING(MAWK, name);
161 f = mawk_file_find(MAWK, sval, type, create);
162 free_STRING(sval);
163 return f;
164 }
165
166 static int mawk_file_close_lowlev(mawk_state_t *MAWK, FILE_NODE *p)
167 {
168 if (p->fin != NULL) {
169 mawk_fin_free(MAWK, p->fin);
170 p->fin = NULL;
171 }
172 if (p->vf != NULL) {
173 p->vf->refco--;
174 if (p->vf->refco == 0)
175 mawk_vio_close(MAWK, p->vf);
176 p->vf = NULL;
177 }
178 if (p->name != NULL) {
179 free_STRING(p->name);
180 }
181 return 0;
182 }
183
184 /* Close a file and delete it's node from the file_list.
185 Walk the whole list, in case a name has two nodes,
186 e.g. < "/dev/tty" and > "/dev/tty"
187 */
188 int mawk_file_close(mawk_state_t *MAWK, mawk_string_t *sval)
189 {
190 FILE_NODE dummy;
191 register FILE_NODE *p;
192 FILE_NODE *q = &dummy; /* trails p */
193 FILE_NODE *hold;
194 char *name = sval->str;
195 int retval = -1;
196
197 dummy.link = p = MAWK->file_list;
198 while (p) {
199 if (strcmp(name, p->name->str) == 0) {
200 /* found */
201 retval = mawk_file_close_lowlev(MAWK, p);
202 hold = p;
203 q->link = p = p->link;
204 MAWK_ZFREE(MAWK, hold);
205 }
206 else {
207 q = p;
208 p = p->link;
209 }
210 }
211
212 MAWK->file_list = dummy.link;
213 return retval;
214 }
215
216 /* Close a file_node and delete it's node from the file_list. */
217 int mawk_file_close_(mawk_state_t *MAWK, FILE_NODE *f)
218 {
219 FILE_NODE dummy;
220 register FILE_NODE *p;
221 FILE_NODE *q = &dummy; /* trails p */
222 FILE_NODE *hold;
223 int retval = -1;
224
225 dummy.link = p = MAWK->file_list;
226 while (p) {
227 if (p == f) {
228 /* found */
229 retval = mawk_file_close_lowlev(MAWK, p);
230 hold = p;
231 q->link = p = p->link;
232 MAWK_ZFREE(MAWK, hold);
233 }
234 else {
235 q = p;
236 p = p->link;
237 }
238 }
239
240 MAWK->file_list = dummy.link;
241 return retval;
242 }
243
244
245 /*
246 mawk_find an output file with name == sval and fflush it
247 */
248 int mawk_file_flush(mawk_state_t *MAWK, mawk_string_t *sval)
249 {
250 int ret = -1;
251 register FILE_NODE *p = MAWK->file_list;
252 unsigned len = sval->len;
253 char *str = sval->str;
254
255 if (len == 0) {
256 /* for consistency with gawk */
257 mawk_flush_all_output(MAWK);
258 return 0;
259 }
260
261 while (p) {
262 if (IS_OUTPUT(p->type) && len == p->name->len && strcmp(str, p->name->str) == 0) {
263 ret = 0;
264 mawk_vio_flush(MAWK, p->vf);
265 /* it's possible for a command and a file to have the same
266 name -- so keep looking */
267 }
268 p = p->link;
269 }
270 return ret;
271 }
272
273 void mawk_flush_all_output(mawk_state_t * MAWK)
274 {
275 FILE_NODE *p;
276
277 for (p = MAWK->file_list; p; p = p->link)
278 if (IS_OUTPUT(p->type))
279 mawk_vio_flush(MAWK, p->vf);
280 }
281
282 FILE_NODE *mawk_file_register_nofin(mawk_state_t *MAWK, const char *name, int type, mawk_vio_t *vf)
283 {
284 FILE_NODE *p;
285
286 p = MAWK_ZMALLOC(MAWK, FILE_NODE);
287 p->link = MAWK->file_list;
288 p->type = type;
289 p->name = mawk_new_STRING(MAWK, name);
290 p->vf = vf;
291 p->fin = NULL;
292 if (vf != NULL)
293 vf->refco++;
294 MAWK->file_list = p;
295
296 /* update hardwireds */
297 if (strcmp(name, "/dev/stdin") == 0)
298 MAWK->fnode_stdin = p;
299 else if (strcmp(name, "/dev/stdout") == 0)
300 MAWK->fnode_stdout = p;
301 else if (strcmp(name, "/dev/stderr") == 0)
302 MAWK->fnode_stderr = p;
303
304 return p;
305 }
306
307 FILE_NODE *mawk_file_register(mawk_state_t *MAWK, const char *name, int type, mawk_vio_t *vf)
308 {
309 FILE_NODE *fn;
310
311 fn = mawk_file_register_nofin(MAWK, name, type, vf);
312 if ((type == F_IN) || (type == PIPE_IN))
313 fn->fin = mawk_fin_alloc(MAWK, fn);
314 return fn;
315 }
316
317 void mawk_file_uninit(mawk_state_t * MAWK)
318 {
319 FILE_NODE *p, *next;
320
321 for (p = MAWK->file_list; p; p = next) {
322 next = p->link;
323 mawk_file_close_lowlev(MAWK, p);
324 MAWK_ZFREE(MAWK, p);
325 }
326 }
0
1 /********************************************
2 files.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef FILES_H
17 #define FILES_H
18
19 /* IO redirection types */
20 #define F_IN (-5)
21 #define PIPE_IN (-4)
22 #define PIPE_OUT (-3)
23 #define F_APPEND (-2)
24 #define F_TRUNC (-1)
25 #define IS_OUTPUT(type) ((type)>=PIPE_OUT)
26
27 /* look up a file:type by name; if it does not exist, create it (if create is not 0).
28 NOTE: F_APPEND and F_TRUNC are the same in file:type. */
29 FILE_NODE *mawk_file_find(mawk_state_t *MAWK, mawk_string_t *name, int type, int create);
30 FILE_NODE *mawk_file_find_(mawk_state_t *MAWK, const char *name, int type, int create);
31
32
33 int mawk_file_close(mawk_state_t *, mawk_string_t *);
34 int mawk_file_close_(mawk_state_t *MAWK, FILE_NODE *f);
35 int mawk_file_flush(mawk_state_t *, mawk_string_t *);
36 void mawk_flush_all_output(mawk_state_t * MAWK);
37
38 /* register a mawk_vio_t * as an open file - no checks are performed about
39 the name, which should be unique; the caller should use mawk_file_find
40 to make sure the file does not exist
41 nofin never sets up the file node's fin buffer, while the plain version
42 does this for input files/pipes.
43 */
44 FILE_NODE *mawk_file_register_nofin(mawk_state_t *MAWK, const char *name, int type, mawk_vio_t *vf);
45 FILE_NODE *mawk_file_register(mawk_state_t *MAWK, const char *name, int type, mawk_vio_t *vf);
46
47
48 #ifndef MAWK_NO_FORK
49 int mawk_wait_for(mawk_state_t *, int);
50 #endif
51
52
53 void mawk_file_uninit(mawk_state_t * MAWK);
54
55 #endif
0 /********************************************
1 files_children.c
2
3 libmawk changes (C) 2009-2014, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991-94. Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14 #include "conf.h"
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include "mawk.h"
21 #include "files.h"
22 #include "memory.h"
23 #include "fin.h"
24
25
26 static void add_to_child_list(mawk_state_t *, int, int);
27 static struct child *remove_from_child_list(mawk_state_t *, int);
28
29 /* we need to wait for children at the end of output pipes to
30 complete so we know any files they have created are complete */
31
32 static void add_to_child_list(mawk_state_t *MAWK, int pid, int exit_status)
33 {
34 register struct child *p = MAWK_ZMALLOC(MAWK, struct child);
35
36 p->pid = pid;
37 p->exit_status = exit_status;
38 p->link = MAWK->child_list;
39 MAWK->child_list = p;
40 }
41
42 static struct child *remove_from_child_list(mawk_state_t *MAWK, int pid)
43 {
44 struct child dummy;
45 register struct child *p;
46 struct child *q = &dummy;
47
48 dummy.link = p = MAWK->child_list;
49 while (p) {
50 if (p->pid == pid) {
51 q->link = p->link;
52 break;
53 }
54 else {
55 q = p;
56 p = p->link;
57 }
58 }
59
60 MAWK->child_list = dummy.link;
61 return p;
62 /* null return if not in the list */
63 }
64
65
66 #ifndef MAWK_NO_FORK
67 /* wait for a specific child to complete and return its
68 exit status
69
70 If pid is zero, wait for any single child and
71 put it on the dead children list
72 */
73 int mawk_wait_for(mawk_state_t *MAWK, int pid)
74 {
75 int exit_status;
76 struct child *p;
77 int id;
78
79 if (pid == 0) {
80 id = wait(&exit_status);
81 add_to_child_list(MAWK, id, exit_status);
82 }
83 /* see if an earlier wait() caught our child */
84 else if ((p = remove_from_child_list(MAWK, pid))) {
85 exit_status = p->exit_status;
86 MAWK_ZFREE(MAWK, p);
87 }
88 else {
89 /* need to really wait */
90 while ((id = wait(&exit_status)) != pid) {
91 if (id == -1) /* can't happen */
92 mawk_bozo(MAWK, "mawk_wait_for");
93 else {
94 /* we got the exit status of another child
95 put it on the child list and try again */
96 add_to_child_list(MAWK, id, exit_status);
97 }
98 }
99 }
100
101 if (exit_status & 0xff)
102 exit_status = 128 + (exit_status & 0xff);
103 else
104 exit_status = (exit_status & 0xff00) >> 8;
105
106 return exit_status;
107 }
108 #endif
109
0
1 /********************************************
2 fin.h
3
4 libmawk changes (C) 2009-2012, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* buffered, splitting input (FIN, aka mawk_input_t) */
17
18 #ifndef FIN_H
19 #define FIN_H
20 /* structure to control input files */
21
22 enum {
23 MAWK_INPF_MAIN = 1, /* part of main input stream if on */
24 MAWK_INPF_EOF = 2, /* reached EOF */
25 MAWK_INPF_START = 4, /* used when RS == "" */
26 MAWK_INPF_NO_MORE = 8, /* there's no more input */
27 MAWK_INPF_DEAD_NO_FREE = 16, /* static dead buffer - do not free */
28 MAWK_INPF_NO_MORE_INPUTS = 32 /* we are at the end of the input file list, impossible to have any more main input */
29 };
30
31 struct mawk_fin_s {
32 FILE_NODE *fn;
33 char *buf;
34 char *next; /* start of the next record, within buf; anything before this is already returned in a previous call */
35 int used; /* how much bytes are in use in buf - this includes records already used up in the beginning of the buffer */
36 int alloced; /* total allocated size of the buf */
37 int flags;
38 };
39
40
41 #define mawk_FIN_nomore (-2)
42
43 mawk_input_t *mawk_fin_alloc(mawk_state_t *MAWK, FILE_NODE *parent);
44 void mawk_fin_free(mawk_state_t *MAWK, mawk_input_t *fin);
45
46 long mawk_fillbuff(mawk_state_t *, mawk_input_t *, char *, unsigned, int interactive);
47
48 /* execution: */
49 void mawk_FINopen_main(mawk_state_t * MAWK);
50 char *mawk_FINgets(mawk_state_t *MAWK, FILE_NODE *fn, unsigned *len_p);
51
52 #endif /* FIN_H */
0
1 /********************************************
2 fin.c
3
4 libmawk changes (C) 2009-2012, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, 1992. Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include "conf.h"
16 #include <stdlib.h>
17 #include "mawk.h"
18 #include "fin.h"
19 #include "memory.h"
20 #include "bi_vars.h"
21 #include "field.h"
22 #include "symtype.h"
23 #include "scan.h"
24 #include "vio.h"
25 #include <string.h>
26
27 #ifndef NO_FCNTL_H
28 #include <fcntl.h>
29 #endif
30
31 /* This file handles input file buffering and (most important) splitting
32 files into records, mawk_FINgets().
33 */
34 mawk_input_t *mawk_fin_alloc(mawk_state_t *MAWK, FILE_NODE *parent)
35 {
36 mawk_input_t *fin;
37
38 fin = MAWK_ZMALLOC(MAWK, mawk_input_t);
39 fin->flags = MAWK_INPF_START;
40 fin->buf = NULL;
41 fin->next = NULL;
42 fin->used = 0;
43 fin->alloced = 0;
44 fin->fn = parent;
45 return fin;
46 }
47
48
49 int mawk_is_cmdline_assign(mawk_state_t *, char *); /* also used by init */
50
51 /* frees the buffer, but leaves mawk_input_t structure until
52 the user calls close() */
53 static void mawk_fin_free_buff(mawk_state_t *MAWK, register mawk_input_t *fin)
54 {
55 if (fin->buf != NULL) {
56 mawk_zfree(MAWK, fin->buf, fin->alloced);
57 fin->buf = NULL; /* marks it semi_closed */
58 fin->used = 0;
59 fin->alloced = 0;
60 }
61 }
62
63 /* user called close() on input file */
64 void mawk_fin_free(mawk_state_t *MAWK, mawk_input_t *fin)
65 {
66 if (fin->flags & MAWK_INPF_DEAD_NO_FREE)
67 return;
68 mawk_fin_free_buff(MAWK, fin);
69 MAWK_ZFREE(MAWK, fin);
70 }
71
72 /*--------
73 Attempt to read size bytes, retry until eof or no_more.
74 target is big enough to hold size + 1 chars
75 on exit the back of the target is zero terminated, unless error
76 Returns the number of bytes read or an error indication if there were no new bytes
77 Read exactly size bytes, retrying as needed, unless:
78 - eof (first eof: returns the bytes read so far; second call: returns 0)
79 - error (first error: return -1, discard the buffer(!))
80 - no_more (first no_more: returns the bytes read so far; second no_more: returns no_more)
81 *--------------*/
82 long mawk_fillbuff(mawk_state_t *MAWK, mawk_input_t *fin, register char *target, unsigned size, int interactive)
83 {
84 register int r;
85 unsigned entry_size = size;
86 {
87 while (size) {
88 errno = 0;
89 fin->flags &= ~MAWK_INPF_NO_MORE;
90 switch (r = mawk_vio_read(MAWK, fin->fn->vf, target, size)) {
91 case -2:
92 fin->flags |= MAWK_INPF_NO_MORE;
93 *target = 0;
94 if (entry_size - size > 0)
95 return entry_size - size;
96 return mawk_FIN_nomore;
97 case -1:
98 {
99 int e;
100 e = errno;
101 mawk_set_errno(MAWK, strerror(e));
102 mawk_errmsg(MAWK, e, "read error");
103 mawk_exitval(MAWK, 2, -1);
104 }
105 case 0:
106 goto out;
107
108 default:
109 target += r;
110 size -= r;
111 if (interactive)
112 goto out;
113 break;
114 }
115 }
116 }
117 out:
118 *target = 0;
119 return entry_size - size;
120 }
0 /********************************************
1 fin_comp.c
2
3 libmawk changes (C) 2009-2013, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
8
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
12
13 #include "mawk.h"
14
15 int mawk_is_cmdline_assign(mawk_state_t *MAWK, char *s)
16 {
17 return 0;
18 }
0 /********************************************
1 fin_exec.c
2
3 libmawk changes (C) 2009-2013, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991, 1992. Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14 #include "conf.h"
15 #include <stdlib.h>
16 #include <string.h>
17 #include "mawk.h"
18 #include "fin.h"
19 #include "memory.h"
20 #include "bi_vars.h"
21 #include "field.h"
22 #include "symtype.h"
23 #include "scan.h"
24 #include "vio.h"
25 #include "init.h"
26 #include "vars.h"
27 #include "cell.h"
28 #include "files.h"
29
30 #ifndef NO_FCNTL_H
31 #include <fcntl.h>
32 #endif
33
34 /* main_input is a FILE_NODE to the main input stream
35 == 0 never been opened */
36
37 static void set_main_to_stdin(mawk_state_t * MAWK)
38 {
39 FILE_NODE *fn;
40 mawk_cell_destroy(MAWK, FILENAME);
41 FILENAME->type = C_STRING;
42 FILENAME->ptr = (PTR) mawk_new_STRING(MAWK, "-");
43 mawk_cell_destroy(MAWK, FNR);
44 FNR->type = C_NUM;
45 FNR->d.dval = MAWK_NUM_ZERO;
46 MAWK->rt_fnr = 0;
47 MAWK->main_input = mawk_file_find_(MAWK, "/dev/stdin", F_IN, 1);
48 #warning TODO: abstract
49 MAWK->main_input->fin->flags |= MAWK_INPF_MAIN;
50 }
51
52 /* get the next command line file open */
53 static mawk_input_t *next_main(mawk_state_t *MAWK, int open_flag)
54 {
55 /* open_flag: called by mawk_FINopen_main() if on */
56 register mawk_cell_t *cp;
57 mawk_cell_t argc; /* copy of ARGC */
58 mawk_cell_t c_argi; /* cell copy of argi */
59 mawk_cell_t argval; /* copy of ARGV[c_argi] */
60
61
62 argval.type = C_NOINIT;
63 c_argi.type = C_NUM;
64
65 if (MAWK->main_input != NULL)
66 mawk_file_close_(MAWK, MAWK->main_input);
67 MAWK->main_input = NULL;
68 /* FILENAME and FNR don't change unless we really open
69 a new file */
70
71 /* make a copy of ARGC to avoid side effect */
72 mawk_cellcpy(MAWK, &argc, ARGC);
73 if (argc.type != C_NUM)
74 mawk_cast1_to_num(MAWK, &argc);
75
76 while (MAWK->argi < argc.d.dval) {
77 c_argi.d.dval = MAWK->argi;
78 MAWK->argi += MAWK_NUM_ONE;
79
80 if ((mawk_array_find(MAWK, MAWK->Argv, &c_argi, &argval, NO_MAWK_CREATE)) == 0)
81 continue; /* its deleted */
82
83 /* make a copy so we can mawk_cast w/o side effect */
84 cp = &argval;
85 if (cp->type < C_STRING)
86 mawk_cast1_to_str(MAWK, cp);
87 if (string(cp)->len == 0)
88 continue;
89 /* file argument is "" */
90
91 /* it might be a command line assignment */
92 if (mawk_is_cmdline_assign(MAWK, string(cp)->str))
93 continue;
94
95 /* try to open it -- we used to continue on failure,
96 but posix says we should quit */
97 if ((MAWK->main_input = mawk_file_find(MAWK, string(cp), F_IN, 1)) == NULL) {
98 mawk_errmsg(MAWK, errno, "cannot open %s", string(cp)->str);
99 mawk_exitval(MAWK, 2, NULL);
100 }
101 #warning TODO abstract this
102 MAWK->main_input->fin->flags |= MAWK_INPF_MAIN;
103
104 /* success -- set FILENAME and FNR */
105 mawk_cell_destroy(MAWK, FILENAME);
106 mawk_cellcpy(MAWK, FILENAME, cp);
107 free_STRING(string(cp));
108 mawk_cell_destroy(MAWK, FNR);
109 FNR->type = C_NUM;
110 FNR->d.dval = MAWK_NUM_ZERO;
111 MAWK->rt_fnr = 0;
112
113 return MAWK->main_input->fin;
114 }
115 /* failure */
116 mawk_cell_destroy(MAWK, &argval);
117
118 if (open_flag) {
119 /* all arguments were null or assignment */
120 set_main_to_stdin(MAWK);
121 return MAWK->main_input->fin;
122 }
123
124 /* real failure */
125 {
126 /* this is how we mark EOF on main_fin */
127 static mawk_input_t dead_main = { NULL, NULL, NULL, 0, 0,
128 MAWK_INPF_EOF | MAWK_INPF_DEAD_NO_FREE | MAWK_INPF_NO_MORE_INPUTS};
129
130 MAWK->main_input = mawk_file_register_nofin(MAWK, "DEAD_MAIN", F_IN, NULL);
131 MAWK->main_input->fin = &dead_main;
132 return MAWK->main_input->fin;
133 /* since MAWK_INPF_MAIN is not set, mawk_FINgets won't call next_main() */
134 }
135 }
136
137
138 /* this gets called once to get the input stream going.
139 It is called after the execution of the BEGIN block
140 unless there is a getline inside BEGIN {}
141 */
142 void mawk_FINopen_main(mawk_state_t * MAWK)
143 {
144 mawk_cell_t argc;
145
146 mawk_cellcpy(MAWK, &argc, ARGC);
147 if (argc.type != C_NUM)
148 mawk_cast1_to_num(MAWK, &argc);
149
150 if (argc.d.dval == MAWK_NUM_ONE)
151 set_main_to_stdin(MAWK);
152 else
153 next_main(MAWK, 1);
154 }
155
156 int mawk_is_cmdline_assign(mawk_state_t *MAWK, char *s)
157 {
158 register char *p;
159 int c;
160 mawk_cell_t *cp;
161 unsigned len;
162 mawk_cell_t *fp = (mawk_cell_t *) 0; /* ditto */
163
164 if (MAWK->scan_code[*(unsigned char *) s] != SC_IDCHAR)
165 return 0;
166
167 p = s + 1;
168 while ((c = MAWK->scan_code[*(unsigned char *) p]) == SC_IDCHAR || c == SC_DIGIT)
169 p++;
170
171 if (*p != '=')
172 return 0;
173
174 *p = 0;
175
176 cp = mawk_create_var(MAWK, s, &fp);
177 if (cp == NULL) {
178 mawk_rt_error(MAWK, "cannot command line assign to %s\n\ttype clash or keyword", s);
179 }
180
181 /* we need to keep ARGV[i] intact */
182 *p++ = '=';
183 len = strlen(p) + 1;
184 /* posix says escape sequences are on from command line */
185 p = mawk_rm_escape(MAWK, strcpy((char *) mawk_zmalloc(MAWK, len), p));
186 cp->ptr = (PTR) mawk_new_STRING(MAWK, p);
187 mawk_zfree(MAWK, p, len);
188 mawk_check_strnum(MAWK, cp); /* sets cp->type */
189 if (fp) { /* move it from cell to pfield[] */
190 mawk_field_assign(MAWK, fp, cp);
191 free_STRING(string(cp));
192 }
193 return 1;
194 }
195
196 static char *find_sep(mawk_state_t *MAWK, int at_end, char *str, unsigned int *match_len)
197 {
198 register char *q, *start;
199
200 /* set up split rule (match pattern and set match length) */
201 switch (MAWK->rs_shadow.type) {
202 case SEP_CHAR: /* single char sep */
203 start = strchr(str, MAWK->rs_shadow.c);
204 *match_len = 1;
205 break;
206
207 case SEP_STR: /* static string sep */
208 *match_len = ((mawk_string_t *) MAWK->rs_shadow.ptr)->len;
209 start = mawk_str_str(str, ((mawk_string_t *) MAWK->rs_shadow.ptr)->str, *match_len);
210 break;
211
212 /* regex or MLR sep */
213 case SEP_MLR:
214 case SEP_RE:
215 start = mawk_re_pos_match(MAWK, str, MAWK->rs_shadow.ptr, match_len);
216 /* if the match is at the end, there might still be
217 more to match in the file */
218 if (start && start[*match_len] == 0 && !at_end)
219 start = (char *) 0;
220 break;
221
222 default:
223 mawk_bozo(MAWK, "type of rs_shadow");
224 }
225 return start;
226 }
227
228 /* return one input record as determined by RS,
229 from input file (FIN) fin
230 */
231 char *mawk_FINgets(mawk_state_t *MAWK, FILE_NODE *fn, unsigned *len_p)
232 {
233 register char *p, *q;
234 char *sep_at;
235 unsigned match_len, available;
236 long r;
237
238 while(!MAWK->do_exit) { /* restart */
239 mawk_input_t *fin = fn->fin;
240
241 if (fin->flags & MAWK_INPF_NO_MORE_INPUTS)
242 return NULL;
243
244 /* at least try reading some more before giving up */
245 fin->flags &= ~MAWK_INPF_NO_MORE;
246
247 if ((fin->used == 0) && (fin->flags & MAWK_INPF_EOF)) {
248 if (fin->flags & MAWK_INPF_MAIN) {
249 fin = next_main(MAWK, 0);
250 if (fin == NULL)
251 return NULL;
252 continue; /* restart */
253 }
254 else {
255 /* eof on a non-main file: no chance to get another file, report eof and exit */
256 return NULL;
257 }
258 }
259
260 /* have to retry finding a sep even if the buffer is the same partial
261 buffer we had last time: RS may have changed between the two calls!
262 The only exception is when buffer is empty for sure */
263 if ((fin->used > 0) && (*fin->next != '\0')) {
264 sep_at = find_sep(MAWK, (fin->flags & MAWK_INPF_EOF), fin->next, &match_len);
265
266 /* did find the separator pattern, cut string and return the from the beginning of the record */
267 if (sep_at != NULL) {
268 char *start = fin->next;
269 /* the easy and normal case: found a record */
270 *sep_at = 0;
271 *len_p = sep_at - start;
272 fin->next = sep_at + match_len;
273 if (fin->next - fin->buf >= fin->used) {
274 /* the buffer got empty - update things to make it faster */
275 fin->next = fin->buf;
276 fin->used = 0;
277 }
278 *len_p = strlen(start);
279 return start;
280 }
281
282 /* no sep, but eof... */
283 if (fin->flags & MAWK_INPF_EOF) {
284 char *s;
285 /* ...last line without a record terminator! Return it anyway */
286 *len_p = r = strlen(fin->next);
287 s = fin->next + r;
288 /* WHAT? for some reason we remove the last newline here */
289 if (MAWK->rs_shadow.type == SEP_MLR && s[-1] == '\n' && r != 0) {
290 (*len_p)--;
291 *--s = 0;
292 }
293 s = fin->next;
294 fin->next = fin->buf;
295 fin->used = 0;
296 return s;
297 }
298
299 /* didn't find a separator and we are not at the end of the file */
300 if (fin->next != fin->buf) {
301 int new_len;
302 /* we are deep into the buffer, the buffer ends with a partial record.
303 Move it to the beginning of the buffer */
304 new_len = fin->used - (fin->next - fin->buf);
305 if (new_len > 0)
306 memmove(fin->buf, fin->next, new_len);
307 fin->used = new_len;
308 fin->next = fin->buf;
309 }
310 /* ... so try to read some more data */
311 }
312
313 available = fin->alloced - fin->used;
314 if (available < BUFFSZ/2) {
315 /* have to grow */
316 int next_offs = fin->next - fin->buf;
317
318 fin->buf = mawk_zrealloc(MAWK, fin->buf, fin->alloced, fin->alloced + BUFFSZ);
319 fin->alloced += BUFFSZ;
320 available += BUFFSZ;
321 fin->next = fin->buf + next_offs;
322 }
323 r = mawk_fillbuff(MAWK, fin, fin->buf + fin->used, available-1, MAWK->interactive_flag);
324 if (r == 0) {
325 fin->flags |= MAWK_INPF_EOF;
326 continue; /* may have a next file (???might be main) */
327 }
328 else if (r == mawk_FIN_nomore) {
329 /* no more to read now and we had at most a partial record in buffer */
330 return (char *)mawk_FIN_nomore;
331 }
332 else if (r < 0) {
333 return NULL;
334 }
335
336 fin->used += r;
337 fin->buf[fin->used] = '\0';
338
339 if (fin->flags & MAWK_INPF_START) {
340 if (MAWK->rs_shadow.type == SEP_MLR) {
341 char *s;
342 /* trim blank lines from front of file */
343 #warning TODO: probably accept \r as well
344 for(s = fin->next; *s == '\n'; s++) ;
345 if (*s == '\0') {
346 /* emptied the buffer with all the \n's... so get back to initial state */
347 fin->next = fin->buf;
348 fin->used = 0;
349 continue; /* restart */
350 }
351 /* found a non-'\n', use that as a potential start of the next record */
352 fin->flags &= ~MAWK_INPF_START; /* we are not at the start anymore */
353 fin->next = s;
354 continue; /* restart: read on */
355 }
356 else
357 fin->flags &= ~MAWK_INPF_START;
358 }
359 }
360
361 /* get here if MAWK -> do_exit */
362 return NULL;
363 }
0
1 define abreak
2 break mawk_breakpoint if MAWK->token_lineno == $arg0
3 end
4
5 define astep
6 set lineno = MAWK->token_lineno
7 break mawk_breakpoint if MAWK->token_lineno == $lineno
8 end
9
10 define awhere
11 call mawk_debug_where(MAWK)
12 end
13
14 echo Debugging libmawk awk code\n
15
16 abreak 2
17 run
0 gdb --args ../lmawk -Wdebug -f test.awk
0 function fun1()
1 {
2 print "q"
3 }
4
5 BEGIN {
6 fun1();
7 print 1
8 print 2
9 }
0
1 /********************************************
2 mawk_hash.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include "mawk.h"
17 #include "memory.h"
18 #include "symtype.h"
19 #include "cell.h"
20 #include <string.h>
21
22 unsigned mawk_hash(register const char *s)
23 {
24 register unsigned h = 0;
25
26 while (*s)
27 h += h + *s++;
28 return h;
29 }
30
31 static HASHNODE *delete(mawk_state_t *, const char *);
32
33 /*
34 mawk_insert a string in the symbol table.
35 Caller knows the symbol is not there
36 -- used for initialization
37 the name must persist (can not be free'd as long as symbol is in the table
38 and it won't be free'd at the end either)!
39 */
40 SYMTAB *mawk_insert(mawk_state_t *MAWK, const char *name)
41 {
42 register HASHNODE *p = MAWK_ZMALLOC(MAWK, HASHNODE);
43 register unsigned h;
44
45 p->link = MAWK->hash_table[h = mawk_hash(name) % HASH_PRIME];
46 p->symtab.name = name;
47 MAWK->hash_table[h] = p;
48 return &p->symtab;
49 }
50
51 /* Find s in the symbol table,
52 if not there and alloc !=0 mawk_insert it (s must be dup'ed) */
53
54 SYMTAB *mawk_find(mawk_state_t *MAWK, const char *s, int alloc)
55 {
56 register HASHNODE *p;
57 HASHNODE *q;
58 unsigned h;
59
60 p = MAWK->hash_table[h = mawk_hash(s) % HASH_PRIME];
61 q = (HASHNODE *) 0;
62 while (1) {
63 if (!p) {
64 if (alloc) {
65 p = MAWK_ZMALLOC(MAWK, HASHNODE);
66 p->symtab.type = ST_NONE;
67 p->symtab.name = strcpy(mawk_zmalloc(MAWK, strlen(s) + 1), s);
68 break;
69 }
70 else
71 return NULL;
72 }
73
74 if (strcmp(p->symtab.name, s) == 0) { /* found */
75 if (!q) /* already at the front */
76 return &p->symtab;
77 else { /* delete from the list */
78
79 q->link = p->link;
80 break;
81 }
82 }
83
84 q = p;
85 p = p->link;
86 }
87 /* put p on front of the list */
88 p->link = MAWK->hash_table[h];
89 MAWK->hash_table[h] = p;
90 return &p->symtab;
91 }
92
93
94 /* remove a node from the mawk_hash table
95 return a ptr to the node */
96
97 static HASHNODE *delete(mawk_state_t *MAWK, const char *s)
98 {
99 register HASHNODE *p;
100 HASHNODE *q = (HASHNODE *) 0;
101 unsigned h;
102
103 p = MAWK->hash_table[MAWK->last_hash = h = mawk_hash(s) % HASH_PRIME];
104 while (p) {
105 if (strcmp(p->symtab.name, s) == 0) { /* found */
106 if (q)
107 q->link = p->link;
108 else
109 MAWK->hash_table[h] = p->link;
110 return p;
111 }
112 else {
113 q = p;
114 p = p->link;
115 }
116 }
117
118 #ifdef DEBUG /* we should not ever get here */
119 mawk_bozo(MAWK, "delete");
120 #endif
121 return (HASHNODE *) 0;
122 }
123
124 #ifdef MAWK_MEM_PEDANTIC
125 #include <stdio.h>
126 static void mawk_delete_cell(mawk_state_t *MAWK, SYMTAB *stp)
127 {
128 switch(stp->type) {
129 case ST_NONE:
130 break;
131 case ST_VAR:
132 case ST_BUILTIN:
133 case ST_FIELD:
134 if (stp->stval.cp != NULL)
135 mawk_cell_destroy(MAWK, stp->stval.cp);
136 break;
137 case ST_ARRAY:
138 mawk_array_destroy(MAWK, stp->stval.array);
139 break;
140 case ST_FUNCT:
141 if (stp->stval.fbp->nargs > 0)
142 mawk_zfree(MAWK, stp->stval.fbp->typev, stp->stval.fbp->nargs);
143 if (stp->stval.fbp->code != NULL)
144 mawk_zfree(MAWK, stp->stval.fbp->code, stp->stval.fbp->size);
145 MAWK_ZFREE(MAWK, stp->stval.fbp);
146 break;
147 }
148 /* we should decide if name was dynamically allocated (from scan)...
149 if ((stp->name != NULL) && (stp->name_dyna)) {
150 int len = strlen(stp->name) + 1;
151 fprintf(stderr, "FR: '%s'\n", stp->name);
152 mawk_zfree(MAWK, (PTR) stp->name, len);
153 stp->name = NULL;
154 }*/
155 }
156
157 #define mawk_delete_node(p) MAWK_ZFREE(MAWK, p)
158
159 void mawk_delete(mawk_state_t *MAWK, const char *name, int cell_destroy)
160 {
161 register HASHNODE *p = delete(MAWK, name);
162 if (p != NULL) {
163 SYMTAB *stp = &p->symtab;
164 if (cell_destroy)
165 mawk_delete_cell(MAWK, stp);
166 mawk_delete_node(p);
167 }
168 }
169 #endif
170
171 /* store a global id on the save list,
172 return a ptr to the local symtab */
173 SYMTAB *mawk_save_id(mawk_state_t *MAWK, const char *s)
174 {
175 HASHNODE *p, *q;
176 unsigned h;
177
178 p = delete(MAWK, s);
179 q = MAWK_ZMALLOC(MAWK, HASHNODE);
180 q->symtab.type = ST_LOCAL_NONE;
181 q->symtab.name = p->symtab.name;
182 /* put q in the mawk_hash table */
183 q->link = MAWK->hash_table[h = MAWK->last_hash];
184 MAWK->hash_table[h] = q;
185
186 /* save p */
187 p->link = MAWK->save_list;
188 MAWK->save_list = p;
189
190 return &q->symtab;
191 }
192
193 /* restore all global indentifiers */
194 void mawk_restore_ids(mawk_state_t * MAWK)
195 {
196 register HASHNODE *p, *q;
197 register unsigned h;
198
199 q = MAWK->save_list;
200 MAWK->save_list = (HASHNODE *) 0;
201 while (q) {
202 p = q;
203 q = q->link;
204 mawk_zfree(MAWK, delete(MAWK, p->symtab.name), sizeof(HASHNODE));
205 p->link = MAWK->hash_table[h = MAWK->last_hash];
206 MAWK->hash_table[h] = p;
207 }
208 }
209
210
211 /* search the symbol table backwards for the
212 disassembler. This is slow -- so what
213 */
214
215 const char *mawk_reverse_uk = "unknown";
216
217 const char *mawk_reverse_find(mawk_state_t *MAWK, int type, PTR ptr)
218 {
219 mawk_cell_t *cp;
220 mawk_array_t array;
221
222 int i;
223 HASHNODE *p;
224
225
226 switch (type) {
227 case ST_VAR:
228 case ST_FIELD:
229 cp = *(mawk_cell_t **) ptr;
230 break;
231
232 case ST_ARRAY:
233 array = *(mawk_array_t *) ptr;
234 break;
235
236 default:
237 return mawk_reverse_uk;
238 }
239
240 for (i = 0; i < HASH_PRIME; i++) {
241 p = MAWK->hash_table[i];
242 while (p) {
243 if (p->symtab.type == type) {
244 switch (type) {
245 case ST_VAR:
246 case ST_FIELD:
247 if (cp == p->symtab.stval.cp)
248 return p->symtab.name;
249 break;
250
251 case ST_ARRAY:
252 if (array == p->symtab.stval.array)
253 return p->symtab.name;
254 break;
255 }
256 }
257
258 p = p->link;
259 }
260 }
261 return mawk_reverse_uk;
262 }
263
264 #ifdef MAWK_MEM_PEDANTIC
265 /* free global hash entries */
266 void mawk_hash_clear(mawk_state_t *MAWK)
267 {
268 register HASHNODE *p, *next;
269 int n;
270
271 for(n = 0; n < HASH_PRIME; n++) {
272 for(p = MAWK->hash_table[n]; p != NULL; p = next) {
273 next = p->link;
274 mawk_delete_cell(MAWK, &(p->symtab));
275 mawk_delete_node(p);
276 }
277 }
278 }
279 #endif
0
1 /********************************************
2 init.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include "conf.h"
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include "mawk.h"
20 #include "code.h"
21 #include "memory.h"
22 #include "symtype.h"
23 #include "init.h"
24 #include "scan.h"
25 #include "bi_vars.h"
26 #include "field.h"
27 #include "zmalloc.h"
28 #include "vio.h"
29 #include "version.h"
30 #include "da_bin_helper.h"
31 #include "cell.h"
32 #include "files.h"
33
34 static int process_cmdline(mawk_state_t *, int, char **);
35 static void set_ARGV(mawk_state_t *, int, char **, int);
36 static void bad_option(mawk_state_t *, char *);
37 static void no_program(mawk_state_t *);
38
39 extern int mawk_is_cmdline_assign(mawk_state_t *, char *);
40
41 #ifndef SET_PROGNAME
42 #define SET_PROGNAME() \
43 {char *p = strrchr(argv[0],'/') ;\
44 MAWK->progname = p ? p+1 : argv[0] ; }
45 #endif
46
47 static const mawk_string_t null_str_ = { 0, 1, "" }; /* read-only */
48
49 static const mawk_escape_t escape_test_[ET_END + 1] = /* read-only */
50 {
51 {'n', '\n'},
52 {'t', '\t'},
53 {'f', '\f'},
54 {'b', '\b'},
55 {'r', '\r'},
56 {'a', '\07'},
57 {'v', '\013'},
58 {'\\', '\\'},
59 {'\"', '\"'},
60 {0, 0}
61 };
62
63 mawk_state_t *mawk_initialize_alloc(void)
64 {
65 unsigned long mpow2[NUM_CELL_TYPES] = {
66 1LU<<0LU, 1LU<<1LU, 1LU<<2LU, 1LU<<3LU, 1LU<<4LU, 1LU<<5LU, 1LU<<6LU,
67 1LU<<7LU, 1LU<<8LU, 1LU<<9LU, 1LU<<10LU, 1LU<<11LU, 1LU<<12LU,
68 1LU<<13LU, 1LU<<14LU, 1LU<<15LU, 1LU<<16LU, 1LU<<17LU, 1LU<<18LU,
69 1LU<<19LU, 1LU<<20LU, 1LU<<21LU, 1LU<<22LU, 1LU<<23LU
70 };
71 SEPARATOR rs_ = { SEP_CHAR, '\n' };
72 mawk_cell_t fs_ = { C_SPACE };
73
74 mawk_state_t *MAWK;
75 MAWK = calloc(sizeof(mawk_state_t), 1);
76 MAWK->Argv = mawk_array_new(MAWK, NULL);
77 MAWK->scripts_loaded = mawk_array_new(MAWK, NULL);
78
79 MAWK->last_token_lineno = -1;
80
81 MAWK->null_str = null_str_;
82 MAWK->argi = MAWK_NUM_ONE;
83 MAWK->current_token = -1;
84 MAWK->execution_start = 0;
85 MAWK->ps.code_move_level = 0;
86 MAWK->stack_base = MAWK->eval_stack; /* these can move for deep recursion */
87 MAWK->stack_danger = MAWK->eval_stack + DANGER;
88 memcpy(MAWK->escape_test, escape_test_, sizeof(escape_test_));
89 MAWK->interactive_flag = 0;
90 MAWK->shell = mawk_strdup_("/bin/sh");
91 MAWK->max_field = MAX_SPLIT;
92 MAWK->rs_shadow = rs_;
93 MAWK->fs_shadow = fs_;
94 memcpy(MAWK->scan_code, mawk_scan_code, sizeof(mawk_scan_code));
95
96 /* this can be moved and enlarged by -W sprintf=num */
97 MAWK->sprintf_buff = string_buff;
98 MAWK->sprintf_limit = string_buff + sizeof(MAWK->tempbuff);
99 MAWK->mpow2 = malloc(sizeof(mpow2));
100 memcpy(MAWK->mpow2, mpow2, sizeof(mpow2));
101 MAWK->fbank[0] = MAWK->field;
102
103 mawk_bi_vars_init(MAWK); /* load the builtin variables */
104 mawk_bi_funct_init(MAWK); /* load the builtin functions */
105 #ifndef MAWK_NO_COMP
106 mawk_kw_init(MAWK); /* load the keywords */
107 #endif
108 mawk_field_init(MAWK);
109 mawk_fpe_init();
110 return MAWK;
111 }
112
113
114 mawk_state_t *mawk_initialize_argv(mawk_state_t *MAWK, int argc, char **argv)
115 {
116 SET_PROGNAME();
117
118 if (!process_cmdline(MAWK, argc, argv))
119 return NULL;
120
121 return MAWK;
122 }
123
124
125 mawk_state_t *mawk_initialize(int argc, char **argv, mawk_vio_init_t vio_init)
126 {
127 mawk_state_t *MAWK, *MAWK2;
128 MAWK = mawk_initialize_alloc();
129 if (MAWK == NULL)
130 return NULL;
131
132 MAWK->vio_init = vio_init;
133
134 MAWK2 = mawk_initialize_argv(MAWK, argc, argv);
135 if (MAWK2 == NULL) {
136 /* TODO: free MAWK */
137 return NULL;
138 }
139 mawk_code_init(MAWK2);
140 return MAWK2;
141 }
142
143
144 void mawk_hash_clear(mawk_state_t *MAWK);
145
146 void mawk_uninitialize(mawk_state_t * m)
147 {
148 FBLOCK *fb, *fbn;
149
150 #ifndef MAWK_NO_COMP
151 #ifdef MAWK_MEM_PEDANTIC
152 mawk_kw_uninit(m);
153 #endif
154 #endif
155
156 #ifdef MAWK_MEM_PEDANTIC
157 mawk_bi_funct_uninit(m);
158 #endif
159
160 /* free data of c calls compiled into the script */
161 for(fb = m->c_funcs; fb != NULL; fb = fbn) {
162 fbn = fb->c_next;
163 free((char *)fb->name);
164 free(fb);
165 }
166
167 if (m->shell != NULL)
168 free(m->shell);
169 if (m->mpow2 != NULL)
170 free(m->mpow2);
171
172 #ifdef MAWK_MEM_PEDANTIC
173 mawk_bi_vars_uninit(m);
174 mawk_field_uninit(m);
175 #endif
176
177 if (m->mawk_parser_stack != NULL)
178 free(m->mawk_parser_stack);
179
180 if (m->ps.buffer != NULL)
181 mawk_zfree(m, m->ps.buffer, BUFFSZ + 1);
182
183 if (m->scripts_loaded != NULL)
184 mawk_array_destroy(m, m->scripts_loaded);
185
186 #ifdef MAWK_MEM_PEDANTIC
187 if (m->begin_start != NULL)
188 mawk_zfree(m, m->begin_start, m->begin_size);
189
190 if (m->main_start != NULL)
191 mawk_zfree(m, m->main_start, m->main_size);
192
193 if (m->end_start_orig != NULL)
194 mawk_zfree(m, m->end_start_orig, m->end_size);
195
196 {
197 struct mawk_fdump *fdl, *next;
198 for(fdl = m->fdump_list; fdl != NULL; fdl = next) {
199 next = fdl->link;
200 mawk_delete(m, fdl->fbp->name, 1);
201 MAWK_ZFREE(m, fdl);
202 }
203 }
204
205 /* free global variables */
206 mawk_hash_clear(m);
207 #endif
208
209 /* close and free all files */
210 mawk_file_uninit(m);
211
212 mawk_free_all(m);
213 free(m);
214 }
215
216 static void bad_option(mawk_state_t *MAWK, char *s)
217 {
218 mawk_errmsg(MAWK, 0, "not an option: %s", s);
219 mawk_exit(MAWK, 2);
220 }
221
222 static void no_program(mawk_state_t * MAWK)
223 {
224 mawk_exit(MAWK, 0);
225 }
226
227 void mawk_append_input_file(mawk_state_t * MAWK, const char *fn, int bytecode)
228 {
229 /* first file goes in pfile_name ; any more go on a list */
230 if (MAWK->ps.pfile_name) {
231 if (MAWK->pfile_list_tail == NULL) {
232 MAWK->pfile_list_tail = MAWK_ZMALLOC(MAWK, PFILE);
233 MAWK->pfile_list_tail->fname = fn;
234 MAWK->pfile_list_tail->bytecode = bytecode;
235 MAWK->pfile_list = MAWK->pfile_list_tail;
236 }
237 else {
238 MAWK->pfile_list_tail->link = MAWK_ZMALLOC(MAWK, PFILE);
239 MAWK->pfile_list_tail = MAWK->pfile_list_tail->link;
240 MAWK->pfile_list_tail->fname = NULL;
241 MAWK->pfile_list_tail->bytecode = 0;
242 }
243 MAWK->pfile_list_tail->link = NULL;
244 }
245 else {
246 MAWK->ps.pfile_name = fn;
247 MAWK->ps.pfile_bytecode = bytecode;
248 }
249 }
250
251 #ifdef MAWK_NO_COMP
252 /* load a binary script; return 1 on success, 0 on failure */
253 static int mawk_load_bin(mawk_state_t *MAWK, const char *path)
254 {
255 if (mawk_load_code_bin(MAWK, path) != 0) {
256 mawk_errmsg(MAWK, 0, "failed to load or link binary script %s", path);
257 mawk_exitval(MAWK, 2, -1);
258 return 0;
259 }
260 return 1;
261 }
262
263 /* load all binary scripts; return 1 on success, 0 on failure */
264 static int mawk_load_bins(mawk_state_t *MAWK)
265 {
266 PFILE *p;
267
268 if (MAWK->ps.pfile_name != NULL)
269 if (!mawk_load_bin(MAWK, MAWK->ps.pfile_name))
270 return 0;
271
272 for(p = MAWK->pfile_list; p != NULL; p = p->link) {
273 if (!mawk_load_bin(MAWK, p->fname))
274 return 0;
275 }
276 return 1;
277 }
278 #endif
279
280 /* not a real implementation, just enough for our needs */
281 static int mawk_strcasecmp(const char *s1, const char *s2)
282 {
283 for(;;) {
284 if (tolower(*s1) != tolower(*s2))
285 return s2 - s1;
286 if (*s1 == '\0')
287 return 0;
288 s1++;
289 s2++;
290 }
291 }
292
293 static int process_cmdline(mawk_state_t *MAWK, int argc, char **argv)
294 {
295 int i, nextarg;
296 char *optarg;
297 MAWK->pfile_list = NULL;
298 MAWK->pfile_list_tail = NULL;
299
300 for (i = 1; i < argc && argv[i][0] == '-'; i = nextarg) {
301 if (argv[i][1] == 0) { /* - alone */
302 if (!MAWK->ps.pfile_name) {
303 no_program(MAWK);
304 return 0;
305 }
306 break; /* the for loop */
307 }
308 /* safe to look at argv[i][2] */
309
310 if (argv[i][2] == 0) {
311 if (i == argc - 1 && argv[i][1] != '-') {
312 if (strchr("WFvf", argv[i][1])) {
313 mawk_errmsg(MAWK, 0, "option %s lacks argument", argv[i]);
314 mawk_exit_(MAWK, 2);
315 return 0;
316 }
317 bad_option(MAWK, argv[i]);
318 }
319
320 optarg = argv[i + 1];
321 nextarg = i + 2;
322 }
323 else { /* argument glued to option */
324
325 optarg = &argv[i][2];
326 nextarg = i + 1;
327 }
328
329 switch (argv[i][1]) {
330 case 'W':
331
332 if (optarg[0] >= 'a' && optarg[0] <= 'z')
333 optarg[0] += 'A' - 'a';
334 if (optarg[0] == 'V')
335 mawk_print_version(MAWK);
336 else if (optarg[0] == 'C')
337 MAWK->dump_code_flag = 2;
338 else if (optarg[0] == 'D') {
339 if (mawk_strcasecmp(optarg, "DUMP") == 0)
340 MAWK->dump_code_flag = 1;
341 else if (mawk_strcasecmp(optarg, "DUMPSYM") == 0)
342 MAWK->dump_sym_flag = 1;
343 else if (mawk_strcasecmp(optarg, "DEBUG") == 0)
344 MAWK->debug_symbols = 1;
345 }
346 else if (optarg[0] == 'S') {
347 char *p = strchr(optarg, '=');
348 int x = p ? atoi(p + 1) : 0;
349
350 if (x > SPRINTF_SZ) {
351 MAWK->sprintf_buff = (char *) mawk_zmalloc(MAWK, x);
352 MAWK->sprintf_limit = MAWK->sprintf_buff + x;
353 }
354 }
355 else if (optarg[0] == 'P') {
356 MAWK->posix_space_flag = 1;
357 }
358 else if (optarg[0] == 'E') {
359 if (MAWK->ps.pfile_name) {
360 mawk_errmsg(MAWK, 0, "-W exec is incompatible with -f");
361 mawk_exit_(MAWK, 2);
362 return 0;
363 }
364 else if (nextarg == argc)
365 no_program(MAWK);
366
367 MAWK->ps.pfile_name = argv[nextarg];
368 MAWK->ps.pfile_bytecode = 0;
369 i = nextarg + 1;
370 goto no_more_opts;
371 }
372 else if (optarg[0] == 'I') {
373 MAWK->interactive_flag = 1;
374 }
375 else if (strncmp(optarg, "Maxmem=", 7) == 0) {
376 char *end;
377 MAWK->mm_max = strtol(optarg+7, &end, 10);
378 switch(*end) {
379 case '\0':
380 break;
381 case 'k':
382 case 'K':
383 MAWK->mm_max *= 1024;
384 break;
385 case 'm':
386 case 'M':
387 MAWK->mm_max *= 1024 * 1024;
388 break;
389 default:
390 MAWK->mm_max = 0;
391 mawk_errmsg(MAWK, 0, "invalid memory size for -Wmaxmem (must be integer with optional K or M suffix): '%s'", optarg+7);
392 }
393 }
394 else
395 mawk_errmsg(MAWK, 0, "vacuous option: -W %s", optarg);
396
397
398 break;
399
400 case 'v':
401 #ifdef MAWK_NO_EXEC
402 mawk_errmsg(MAWK, 0, "Compiler-only version of mawk can not set runtime variables with -v");
403 mawk_exit_(MAWK, 2);
404 return 0;
405 #else
406 if (!mawk_is_cmdline_assign(MAWK, optarg)) {
407 mawk_errmsg(MAWK, 0, "improper assignment: -v %s", optarg);
408 mawk_exit_(MAWK, 2);
409 return 0;
410 }
411 #endif
412 break;
413
414 case 'F':
415
416 mawk_rm_escape(MAWK, optarg); /* recognize escape sequences */
417 mawk_cell_destroy(MAWK, MAWK_FS);
418 MAWK_FS->type = C_STRING;
419 MAWK_FS->ptr = (PTR) mawk_new_STRING(MAWK, optarg);
420 mawk_cellcpy(MAWK, &MAWK->fs_shadow, MAWK_FS);
421 mawk_cast_for_split(MAWK, &MAWK->fs_shadow);
422 break;
423
424 case '-':
425 if (argv[i][2] != 0)
426 bad_option(MAWK, argv[i]);
427 i++;
428 goto no_more_opts;
429 #ifndef MAWK_NO_COMP
430 case 'f':
431 mawk_append_input_file(MAWK, optarg, 0);
432 break;
433 #endif
434 case 'b':
435 mawk_append_input_file(MAWK, optarg, 1);
436 break;
437 default:
438 bad_option(MAWK, argv[i]);
439 }
440 }
441
442 no_more_opts:
443 if (MAWK->ps.pfile_name) { /* program from -f or -b */
444 set_ARGV(MAWK, argc, argv, i);
445 #ifdef MAWK_NO_COMP
446 mawk_load_bins(MAWK);
447 #else
448 mawk_scan_init(MAWK, (char *) 0);
449 #endif
450 if (MAWK->do_exit)
451 return 0;
452 }
453 else { /* program given on command line (no -f or -b) */
454
455 if (i == argc) {
456 if (!MAWK->no_program_ok) {
457 no_program(MAWK);
458 return 0;
459 }
460 }
461 set_ARGV(MAWK, argc, argv, i + 1);
462 #ifndef MAWK_NO_COMP
463 if (i != argc)
464 mawk_scan_init(MAWK, argv[i]);
465 else
466 mawk_scan_init(MAWK, "BEGIN {}");
467 #else
468 bad_option(MAWK, argv[i]);
469 return 1;
470 #endif
471 if (MAWK->do_exit)
472 return 0;
473
474 /* #endif */
475 }
476 return 1;
477 }
478
479
480 static void set_ARGV(mawk_state_t *MAWK, int argc, char **argv, int i)
481 {
482 /* argv[i] = ARGV[i] */
483 SYMTAB *st_p;
484 mawk_cell_t idx, cl;
485
486 st_p = mawk_insert(MAWK, "ARGV");
487 st_p->type = ST_ARRAY;
488 st_p->stval.array = MAWK->Argv;
489
490 /* store progran name in ARGV[] */
491 idx.type = C_NUM;
492 idx.d.dval = MAWK_NUM_ZERO;
493 cl.type = C_STRING;
494 cl.ptr = (PTR) mawk_new_STRING(MAWK, MAWK->progname);
495 mawk_array_set(MAWK, st_p->stval.array, &idx, &cl);
496 free_STRING((mawk_string_t *)cl.ptr);
497
498 /* ARGV[0] is set, do the rest
499 The type of ARGV[1] ... should be C_MBSTRN
500 because the user might enter numbers from the command line */
501
502 for (idx.d.dval = MAWK_NUM_ONE; i < argc; i++, idx.d.dval += MAWK_NUM_ONE) {
503
504 cl.type = C_MBSTRN;
505 cl.ptr = (PTR) mawk_new_STRING(MAWK, argv[i]);
506 mawk_array_set(MAWK, st_p->stval.array, &idx, &cl);
507 free_STRING((mawk_string_t *)cl.ptr);
508 }
509 ARGC->type = C_NUM;
510 ARGC->d.dval = idx.d.dval;
511 }
512
513
514
0
1 /********************************************
2 init.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef INIT_H
17 #define INIT_H
18
19 #include <libmawk/symtype.h>
20
21 /* nodes to link file names for multiple
22 -f option */
23
24 extern char *sprintf_buff, *sprintf_limit;
25
26
27 /* high levelinit: all 3 steps in order: */
28 mawk_state_t *mawk_initialize(int argc, char **argv, mawk_vio_init_t vio_init);
29
30 /* low level init, step 1: allocate the context and init constants*/
31 mawk_state_t *mawk_initialize_alloc(void);
32
33 /* set up vio and builtins here */
34
35 /* low level init, step 2: set up args and load scripts */
36 mawk_state_t *mawk_initialize_argv(mawk_state_t *MAWK, int argc, char **argv);
37
38 /* low level init, step 3: initialize the code */
39 void code_init(mawk_state_t *);
40
41
42
43 void mawk_uninitialize(mawk_state_t * m);
44 void code_cleanup(void);
45 void compile_cleanup(void);
46 int mawk_scan_init(mawk_state_t *, char *);
47 void bi_vars_init(mawk_state_t * MAWK);
48 void bi_funct_init(mawk_state_t *);
49 void print_init(void);
50 void mawk_kw_init(mawk_state_t * MAWK);
51 #ifdef MAWK_MEM_PEDANTIC
52 void mawk_kw_uninit(mawk_state_t * MAWK);
53 #endif
54 void mawk_field_init(mawk_state_t *);
55 void mawk_fpe_init(void);
56 void mawk_set_stderr(mawk_state_t * MAWK);
57 void mawk_append_input_file(mawk_state_t * MAWK, const char *fn, int bytecode);
58
59 int mawk_is_cmdline_assign(mawk_state_t *, char *);
60
61
62 #endif /* INIT_H */
0 #define MAWK_NO_COMP
1 #include "init.c"
0
1 /********************************************
2 jmp.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* this module deals with back patching jumps, breaks and continues,
17 and with save and restoring code when we move code.
18 There are three stacks. If we encounter a compile error, the
19 stacks are frozen, i.e., we do not attempt error recovery
20 on the stacks
21 */
22
23
24 #include "mawk.h"
25 #include "symtype.h"
26 #include "jmp.h"
27 #include "code.h"
28 #include "sizes.h"
29 #include "init.h"
30 #include "memory.h"
31
32 #define error_state (MAWK->compile_error_count>0)
33
34
35 /*---------- back patching jumps ---------------*/
36
37 void mawk_code_jmp(mawk_state_t *MAWK, int jtype, INST *target)
38 {
39 if (error_state)
40 return;
41
42 /* WARNING: Don't emit any code before using target or
43 relocation might make it invalid */
44
45 if (target)
46 mawk_code2op(MAWK, jtype, target - (mawk_code_ptr + 1));
47 else {
48 register JMP *p = MAWK_ZMALLOC(MAWK, JMP);
49
50 /* stack for back patch */
51 mawk_code2op(MAWK, jtype, 0);
52 p->source_offset = mawk_code_offset - 1;
53 p->link = MAWK->jmp_top;
54 MAWK->jmp_top = p;
55 }
56 }
57
58 void mawk_patch_jmp(mawk_state_t *MAWK, INST *target) /* patch a jump on the jmp_stack */
59 {
60 register JMP *p;
61 register INST *source; /* jmp starts here */
62
63 if (!error_state) {
64 #ifdef DEBUG
65 if (!MAWK->jmp_top)
66 mawk_bozo(MAWK, "jmp stack underflow");
67 #endif
68
69 p = MAWK->jmp_top;
70 MAWK->jmp_top = p->link;
71 source = p->source_offset + mawk_code_base;
72 source->op = target - source;
73
74 MAWK_ZFREE(MAWK, p);
75 }
76 }
77
78
79 /*-- break and continue -------*/
80
81 void mawk_BC_new(mawk_state_t * MAWK)
82 { /* mark the start of a loop */
83 mawk_BC_insert(MAWK, 0, (INST *) 0);
84 }
85
86 void mawk_BC_insert(mawk_state_t *MAWK, int type, INST *address)
87 {
88 register BC *p;
89
90 if (error_state)
91 return;
92
93 if (type && !MAWK->bc_top) {
94 mawk_compile_error(MAWK, "%s statement outside of loop", type == 'B' ? "break" : "continue");
95
96 return;
97 }
98 else {
99 p = MAWK_ZMALLOC(MAWK, BC);
100 p->type = type;
101 p->source_offset = address - mawk_code_base;
102 p->link = MAWK->bc_top;
103 MAWK->bc_top = p;
104 }
105 }
106
107
108 /* patch all break and continues for one loop */
109 void mawk_BC_clear(mawk_state_t *MAWK, INST *B_address, INST *C_address)
110 {
111 register BC *p, *q;
112 INST *source;
113
114 if (error_state)
115 return;
116
117 p = MAWK->bc_top;
118 /* pop down to the mark node */
119 while (p->type) {
120 source = mawk_code_base + p->source_offset;
121 source->op = (p->type == 'B' ? B_address : C_address)
122 - source;
123
124 q = p;
125 p = p->link;
126 MAWK_ZFREE(MAWK, q);
127 }
128 /* remove the mark node */
129 MAWK->bc_top = p->link;
130 MAWK_ZFREE(MAWK, p);
131 }
132
133 /*----- moving code --------------------------*/
134
135 #define NO_SCOPE -1
136 /* means relocation of resolve list not needed */
137
138 void mawk_code_push(mawk_state_t *MAWK, INST *code, unsigned len, int scope, FBLOCK *fbp)
139 {
140 register MC *p;
141
142 if (!error_state) {
143 p = MAWK_ZMALLOC(MAWK, MC);
144 p->len = len;
145 p->link = MAWK->mc_top;
146 MAWK->mc_top = p;
147
148 if (len) {
149 p->code = (INST *) mawk_zmalloc(MAWK, sizeof(INST) * len);
150 memcpy(p->code, code, sizeof(INST) * len);
151 }
152 if (!MAWK->resolve_list)
153 p->scope = NO_SCOPE;
154 else {
155 p->scope = scope;
156 p->move_level = MAWK->ps.code_move_level;
157 p->fbp = fbp;
158 if (code != NULL)
159 p->offset = code - mawk_code_base;
160 else
161 p->offset = 0;
162 }
163 }
164 MAWK->ps.code_move_level++;
165 }
166
167 /* copy the code at the top of the mc stack to target.
168 return the number of INSTs moved */
169
170 unsigned mawk_code_pop(mawk_state_t *MAWK, INST *target)
171 {
172 register MC *p;
173 unsigned len;
174 int target_offset;
175
176 if (error_state)
177 return 0;
178
179 #ifdef DEBUG
180 if (!MAWK->mc_top)
181 mawk_bozo(MAWK, "mc underflow");
182 #endif
183
184 p = MAWK->mc_top;
185 MAWK->mc_top = p->link;
186 len = p->len;
187
188 while (target + len >= mawk_code_warn) {
189 target_offset = target - mawk_code_base;
190 mawk_code_grow(MAWK);
191 target = mawk_code_base + target_offset;
192 }
193
194 if (len) {
195 memcpy(target, p->code, len * sizeof(INST));
196 mawk_zfree(MAWK, p->code, len * sizeof(INST));
197 }
198
199 if (p->scope != NO_SCOPE) {
200 target_offset = target - mawk_code_base;
201 mawk_relocate_resolve_list(MAWK, p->scope, p->move_level, p->fbp, p->offset, len, target_offset - p->offset);
202 }
203
204 MAWK_ZFREE(MAWK, p);
205 MAWK->ps.code_move_level--;
206 return len;
207 }
0
1 /********************************************
2 jmp.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef JMP_H
17 #define JMP_H
18
19 void mawk_BC_new(mawk_state_t *);
20 void mawk_BC_insert(mawk_state_t *, int, INST *);
21 void mawk_BC_clear(mawk_state_t *, INST *, INST *);
22 void mawk_code_push(mawk_state_t *, INST *, unsigned, int, FBLOCK *);
23 unsigned mawk_code_pop(mawk_state_t *, INST *);
24 void mawk_code_jmp(mawk_state_t *, int, INST *);
25 void mawk_patch_jmp(mawk_state_t *, INST *);
26
27 #endif /* JMP_H */
0
1 /********************************************
2 kw.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include "mawk.h"
17 #include "symtype.h"
18 #include "parse.h"
19 #include "init.h"
20
21 static const struct kw {
22 char *text;
23 short kw;
24 } keywords[] = { /* read-only */
25 {"print", PRINT},
26 {"printf", PRINTF},
27 {"do", DO},
28 {"while", WHILE},
29 {"for", FOR},
30 {"break", BREAK},
31 {"continue", CONTINUE},
32 {"if", IF},
33 {"else", ELSE},
34 {"in", IN},
35 {"delete", DELETE},
36 {"split", SPLIT},
37 {"match", MATCH_FUNC},
38 {"BEGIN", BEGIN},
39 {"END", END},
40 {"include", INCLUDE},
41 {"exit", EXIT},
42 {"next", NEXT},
43 {"return", RETURN},
44 {"getline", GETLINE},
45 {"sub", SUB},
46 {"gsub", GSUB},
47 {"function", FUNCTION},
48 {NULL, 0}
49 };
50
51 /* put keywords in the symbol table */
52 void mawk_kw_init(mawk_state_t * MAWK)
53 {
54 register const struct kw *p = keywords;
55 register SYMTAB *q;
56
57 while (p->text) {
58 q = mawk_insert(MAWK, p->text);
59 q->type = ST_KEYWORD;
60 q->stval.kw = p++->kw;
61 }
62 }
63
64 #ifdef MAWK_MEM_PEDANTIC
65 void mawk_kw_uninit(mawk_state_t * MAWK)
66 {
67 register const struct kw *p = keywords;
68 register SYMTAB *q;
69
70 while (p->text) {
71 mawk_delete(MAWK, p->text, 0);
72 p++;
73 }
74 }
75 #endif
76
77 /* mawk_find a keyword to emit an error message */
78 const char *mawk_find_kw_str(int kw_token)
79 {
80 const struct kw *p;
81
82 for (p = keywords; p->text; p++)
83 if (p->kw == kw_token)
84 return p->text;
85 /* search failed */
86 return (char *) 0;
87 }
0 /********************************************
1 libmawk (C) 2009-2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include "libmawk.h"
14 #include "debug.h"
15 #include "memory.h"
16 #include "sizes.h"
17 #include "array.h"
18 #include "fin.h"
19 #include "num.h"
20 #include "vio.h"
21 #include "vars.h"
22 #include "vio.h"
23 #include "vio_fifo.h"
24 #include "vio_orig.h"
25
26 mawk_state_t *libmawk_initialize_stage1(void)
27 {
28 mawk_state_t *m;
29
30 m = mawk_initialize_alloc();
31
32 m->separate_begin = 1;
33 m->suppress_undefined_function_warning = 1;
34 m->no_program_ok = 1;
35 return m;
36 }
37
38 mawk_state_t *libmawk_initialize_stage2(mawk_state_t *m, int argc, char *argv[])
39 {
40 mawk_state_t *m2;
41 char *argv_dummy[] = {
42 "(null)",
43 "-f",
44 "/dev/null",
45 NULL
46 };
47
48 if (argv == NULL) {
49 argc = 3;
50 argv = argv_dummy;
51 }
52
53 /* load and parse */
54 m2 = mawk_initialize_argv(m, argc, argv);
55
56 if (m2 == NULL) {
57 #warning TODO: cleanup m
58 return NULL;
59 }
60 m = m2;
61
62 mawk_code_init(m);
63
64 /* if the app failed to load scripts from argv[], add a dummy
65 empty BEGIN - if later the app feeds in some script, it will
66 be appended to the empty BEGIN, but there won't be any side
67 effect of this move. */
68 if (*m->ps.buffp == '\0')
69 strcpy((char *)m->ps.buffp, "BEGIN {}\n");
70
71 mawk_parse(m);
72
73 return m;
74 }
75
76 mawk_state_t *libmawk_initialize_stage3(mawk_state_t *m)
77 {
78
79 if (m->execution_start == NULL)
80 return NULL;
81
82 m->mawk_state = EXECUTION;
83
84 if (m->debug_symbols)
85 mawk_debug_callstack_push(m, &mawk_debug_begin);
86
87 mawk_execute(m, m->execution_start, m->eval_stack - 1, 0) ;
88
89 if (m->debug_symbols)
90 mawk_debug_callstack_pop(m);
91
92 return m;
93 }
94
95 int libmawk_initialize_stdio(mawk_state_t *m, int stdin_apps, int stdout_apps, int stderr_apps)
96 {
97 mawk_vio_t *vf;
98
99 mawk_vio_orig_setup_stdio(m, stdin_apps, stdout_apps, stderr_apps);
100
101 /* stdin is a fifo */
102 if (!stdin_apps) {
103 vf = mawk_vio_fifo_open(m, NULL, MAWK_VIO_I);
104 mawk_file_register(m, "/dev/stdin", F_IN, vf);
105 }
106
107 if (!stdout_apps) {
108 vf = mawk_vio_fifo_open(m, NULL, MAWK_VIO_O_APPEND);
109 mawk_file_register(m, "/dev/stdout", F_APPEND, vf);
110 }
111
112 if (!stderr_apps) {
113 vf = mawk_vio_fifo_open(m, NULL, MAWK_VIO_O_APPEND);
114 mawk_file_register(m, "/dev/stderr", F_APPEND, vf);
115 }
116
117 /* file operation is handled by the orig vio */
118 m->vio_init = mawk_vio_orig_init;
119 return 0;
120 }
121
122 mawk_state_t *libmawk_initialize(int argc, char *argv[])
123 {
124 mawk_state_t *m;
125
126 m = libmawk_initialize_stage1();
127
128 if (m == NULL)
129 return NULL;
130
131 /* stdout and stderr are bound to the process' stdout and stderr */
132 libmawk_initialize_stdio(m, 0, 1, 1);
133
134 m = libmawk_initialize_stage2(m, argc, argv);
135 if (m != NULL)
136 m = libmawk_initialize_stage3(m);
137
138 return m;
139 }
140
141
142 void libmawk_run_main(mawk_state_t *m)
143 {
144 /* don't run empty main */
145 if (m->main_start == NULL)
146 return;
147
148 if (m->debug_symbols)
149 mawk_debug_callstack_push(m, &mawk_debug_main);
150
151 mawk_execute(m, m->main_start, m->eval_stack - 1, 0);
152
153 if (m->debug_symbols)
154 mawk_debug_callstack_pop(m);
155 }
156
157 void libmawk_uninitialize_stage1(mawk_state_t *m)
158 {
159 INST exit0 = {_EXIT0};
160 mawk_execute(m, &exit0, m->eval_stack - 1, 0);
161 }
162
163 void libmawk_uninitialize_stage2(mawk_state_t *m)
164 {
165 libmawk_close_input(m);
166
167 if (m->main_input != NULL)
168 mawk_file_close_(m, m->main_input);
169
170 mawk_uninitialize(m);
171 }
172
173
174 void libmawk_uninitialize(mawk_state_t *m)
175 {
176 libmawk_uninitialize_stage1(m);
177 libmawk_uninitialize_stage2(m);
178 }
179
180 /* callback from mawk */
181 void mawk_exit_(mawk_state_t *MAWK, int x)
182 {
183 /* we do not really exit */
184 MAWK->final_exit_code = MAWK->rt_exit_code != 0 ? MAWK->rt_exit_code : x;
185 MAWK->wants_to_exit = 1;
186 }
187
188 int libmawk_append_ninput(mawk_state_t *m, const char *input, int len)
189 {
190 mawk_vio_t *vf;
191 vf = m->fnode_stdin->vf;
192 if (vf == NULL)
193 return -1;
194 return mawk_vio_fifo_write_app(m, vf, input, len);
195 }
196
197 int libmawk_append_input(mawk_state_t *m, const char *input_str)
198 {
199 return libmawk_append_ninput(m, input_str, strlen(input_str));
200 }
201
202 int libmawk_close_input(mawk_state_t *m)
203 {
204 mawk_vio_t *vf;
205 if (m->fnode_stdin == NULL)
206 return -1;
207 vf = m->fnode_stdin->vf;
208 if (vf == NULL)
209 return -1;
210 if (vf->imp->vclose == mawk_vio_fifo_imp.vclose)
211 mawk_vio_fifo_eof_from_app(m, vf);
212 return 0;
213 }
214
215 mawk_cell_t *libmawk_set_cellv(mawk_state_t *MAWK, mawk_cell_t *cell, const char argtype, va_list *ap)
216 {
217 char *s;
218 int i;
219 mawk_num_t d;
220
221 switch(argtype) {
222 case 's':
223 s = va_arg((*ap), char *);
224 cell->type = C_STRING ;
225 cell->ptr = mawk_new_STRING(MAWK, s);
226 break;
227 case 'd':
228 i = va_arg((*ap), int);
229 cell->type = C_NUM ;
230 cell->d.dval = i;
231 break;
232 #ifndef MAWK_NO_FLOAT
233 case 'f':
234 d = va_arg((*ap), double);
235 cell->type = C_NUM;
236 cell->d.dval = d;
237 break;
238 #endif
239 default:
240 return NULL;
241 }
242 return cell;
243 }
244
245 mawk_cell_t *libmawk_set_cellp(mawk_state_t *MAWK, mawk_cell_t *cell, const char argtype, void *argp)
246 {
247 char *s;
248 int i;
249 mawk_num_t d;
250
251 switch(argtype) {
252 case 's':
253 s = (char *)argp;
254 cell->type = C_STRING ;
255 cell->ptr = mawk_new_STRING(MAWK, s);
256 break;
257 case 'd':
258 i = *(int *)argp;
259 cell->type = C_NUM ;
260 cell->d.dval = i;
261 break;
262 #ifndef MAWK_NO_FLOAT
263 case 'f':
264 d = *(double *)argp;
265 cell->type = C_NUM ;
266 cell->d.dval = d;
267 break;
268 #endif
269 default:
270 return NULL;
271 }
272 return cell;
273 }
274
275 mawk_cell_t *libmawk_set_cell(mawk_state_t *MAWK, mawk_cell_t *cell, const char argtype, ...)
276 {
277 va_list ap;
278 mawk_cell_t *ret;
279
280 va_start(ap, argtype);
281 ret = libmawk_set_cellv(MAWK, cell, argtype, &ap);
282 va_end(ap);
283 return ret;
284 }
285
286
287 mawk_exec_result_t libmawk_call_function(mawk_state_t *MAWK, const char *fname, mawk_cell_t *retc, const char *argtypes, ...)
288 {
289 va_list ap;
290 int numargs;
291 SYMTAB *fs;
292 mawk_cell_t *ret, *tmp;
293 mawk_cell_t *orig_sp;
294 FBLOCK *fbp;
295 FBLOCK fbp_c;
296
297 if (retc != NULL)
298 mawk_cell_destroy(MAWK, retc);
299
300 fs = mawk_find(MAWK, fname, 0);
301 if ((fs == NULL) || ((fs->type != ST_FUNCT) && (fs->type != ST_C_FUNCTION))) {
302 /* does not exist or not a function */
303 return -1;
304 }
305
306 if (fs->type == ST_C_FUNCTION) {
307 fbp = &fbp_c;
308 fbp_c.name = fs->name;
309 fbp_c.code = NULL;
310 }
311 else
312 fbp = fs->stval.fbp;
313
314 #warning TODO: check if we need to grow the stack
315
316 orig_sp = MAWK->sp;
317 va_start(ap, argtypes);
318 for(numargs = 0;*argtypes != '\0';argtypes++,numargs++) {
319 inc_mawksp();
320
321 if (libmawk_set_cellv(MAWK, MAWK->sp, *argtypes, &ap) == NULL)
322 goto err_cleanup;
323 }
324 va_end(ap);
325 return mawk_call(MAWK, fbp, numargs, retc);
326
327 err_cleanup:;
328 va_end(ap);
329 for(MAWK->sp--; MAWK->sp > orig_sp; MAWK->sp--)
330 mawk_cell_destroy(MAWK, MAWK->sp);
331
332 MAWK->sp = orig_sp;
333 return -1;
334 }
335
336 mawk_exec_result_t libmawk_call_functionp(mawk_state_t *MAWK, const char *fname, mawk_cell_t *retc, const char *argtypes, void **args)
337 {
338 int numargs;
339 SYMTAB *fs;
340 mawk_cell_t *ret, *tmp;
341 mawk_cell_t *orig_sp;
342 FBLOCK *fbp;
343 FBLOCK fbp_c;
344
345 if (retc != NULL)
346 mawk_cell_destroy(MAWK, retc);
347
348 fs = mawk_find(MAWK, fname, 0);
349 if ((fs == NULL) || ((fs->type != ST_FUNCT) && (fs->type != ST_C_FUNCTION))) {
350 /* does not exist or not a function */
351 return -1;
352 }
353
354 if (fs->type == ST_C_FUNCTION) {
355 fbp = &fbp_c;
356 fbp_c.name = fs->name;
357 fbp_c.code = NULL;
358 }
359 else
360 fbp = fs->stval.fbp;
361
362 #warning TODO: check if we need to grow the stack
363
364 orig_sp = MAWK->sp;
365 for(numargs = 0;*argtypes != '\0';argtypes++,numargs++,args++) {
366 inc_mawksp();
367 if (libmawk_set_cellp(MAWK, MAWK->sp, *argtypes, *args) == NULL)
368 goto err_cleanup;
369 }
370 return mawk_call(MAWK, fs->stval.fbp, numargs, retc);
371
372 err_cleanup:;
373 for(MAWK->sp--; MAWK->sp > orig_sp; MAWK->sp--)
374 mawk_cell_destroy(MAWK, MAWK->sp);
375
376 MAWK->sp = orig_sp;
377 return -1;
378
379 }
380
381 mawk_exec_result_t libmawk_call_functionc(mawk_state_t *MAWK, const char *fname, mawk_cell_t *retc, int argc, const mawk_cell_t *argv)
382 {
383 int n;
384 SYMTAB *fs;
385 mawk_cell_t *ret, *tmp;
386 mawk_cell_t *orig_sp;
387 FBLOCK *fbp;
388 FBLOCK fbp_c;
389
390 if (retc != NULL)
391 mawk_cell_destroy(MAWK, retc);
392
393 fs = mawk_find(MAWK, fname, 0);
394 if ((fs == NULL) || ((fs->type != ST_FUNCT) && (fs->type != ST_C_FUNCTION))) {
395 /* does not exist or not a function */
396 return -1;
397 }
398
399 if (fs->type == ST_C_FUNCTION) {
400 fbp = &fbp_c;
401 fbp_c.name = fs->name;
402 fbp_c.code = NULL;
403 }
404 else
405 fbp = fs->stval.fbp;
406
407 #warning TODO: check if we need to grow the stack
408
409 for(n = 0; n< argc; n++) {
410 inc_mawksp();
411 mawk_cellcpy(MAWK, MAWK->sp, &argv[n]);
412 }
413 return mawk_call(MAWK, fs->stval.fbp, argc, retc);
414 }
415
416
417 void libmawk_cell_destroy(mawk_state_t *MAWK, mawk_cell_t *c)
418 {
419 mawk_cell_destroy(MAWK, c);
420 c->type = C_NOINIT;
421 }
422
423 char *libmawk_print_cell(mawk_state_t *MAWK, const mawk_cell_t *c, char *buff, int size)
424 {
425 char tmp[128];
426 int len;
427
428 if ((buff == NULL) || (size < 1))
429 return NULL;
430 *buff = '\0';
431
432 switch(c->type) {
433 case C_NUM:
434 #ifdef MAWK_NO_FLOAT
435 len = sprintf(tmp, "%d", (int)c->d.dval);
436 #else
437 if (c->d.dval == (int)c->d.dval)
438 len = sprintf(tmp, "%d", (int)c->d.dval);
439 else
440 len = sprintf(tmp, "%f", c->d.dval);
441 #endif
442 if (len > size-1)
443 len = size-1;
444 goto copy_tmp;
445 case C_STRING:
446 strncpy(buff, ((mawk_string_t *)(c->ptr))->str, size);
447 buff[size-1] = '\0';
448 break;
449
450 case C_NOINIT:
451 /* should be empty string just as in awk */
452 break;
453 case C_STRNUM:
454 case C_MBSTRN:
455 #warning TODO: we should be able to convert the above two
456 case C_RE:
457 case C_SPACE:
458 case C_SNULL:
459 case C_REPL:
460 case C_REPLV:
461 len = sprintf(buff, "Can't convert celltype %d\n", c->type);
462 break;
463 default:
464 len = sprintf(buff, "Invalid celltype %d\n", c->type);
465 break;
466
467 }
468 return buff;
469
470 copy_tmp:;
471 memcpy(buff, tmp, len);
472 buff[len] = '\0';
473 return buff;
474 }
475
476
477 const mawk_cell_t *libmawk_get_var(mawk_state_t *MAWK, const char *vname)
478 {
479 return mawk_get_var(MAWK, vname);
480 }
481
482 static mawk_array_t array_prep_idx(mawk_state_t *MAWK, const char *arr_name, const char *idx, mawk_cell_t *idxc)
483 {
484 SYMTAB *fs;
485 fs = mawk_find(MAWK, arr_name, 0);
486
487 /* does symbol exist at all? */
488 if (fs == NULL)
489 return NULL;
490
491 /* exit if not an array */
492 if (fs->type != ST_ARRAY)
493 return NULL;
494
495 idxc->type = C_STRING;
496 idxc->ptr = (PTR) mawk_new_STRING(MAWK, idx);
497
498 return (mawk_array_t)fs->stval.cp;
499 }
500
501 int libmawk_get_array_at(mawk_state_t *MAWK, const char *arr_name, const char *idx, mawk_cell_t *result, int create)
502 {
503 mawk_array_t arr;
504 mawk_cell_t idxc;
505 int res;
506
507
508 if (result != NULL) {
509 mawk_cell_destroy(MAWK, result);
510 result->type = C_NOINIT;
511 }
512
513 arr = array_prep_idx(MAWK, arr_name, idx, &idxc);
514 if (arr == NULL)
515 return -1;
516
517 res = mawk_array_find(MAWK, arr, &idxc, result, create);
518 mawk_cell_destroy(MAWK, &idxc);
519 return res;
520 }
521
522 int libmawk_set_array_atv(mawk_state_t *MAWK, const char *arr_name, const char *idx, const char valtype, va_list *ap)
523 {
524 mawk_array_t arr;
525 mawk_cell_t idxc, valc = libmawk_empty_cell;
526
527 arr = array_prep_idx(MAWK, arr_name, idx, &idxc);
528 if (arr == NULL)
529 return -1;
530
531 libmawk_set_cellv(MAWK, &valc, valtype, ap);
532
533 mawk_array_set(MAWK, arr, &idxc, &valc);
534 mawk_cell_destroy(MAWK, &idxc);
535 mawk_cell_destroy(MAWK, &valc);
536 return 0;
537 }
538
539 int libmawk_set_array_atp(mawk_state_t *MAWK, const char *arr_name, const char *idx, const char valtype, void *val)
540 {
541 mawk_array_t arr;
542 mawk_cell_t idxc, valc = libmawk_empty_cell;
543
544 arr = array_prep_idx(MAWK, arr_name, idx, &idxc);
545 if (arr == NULL)
546 return -1;
547
548 libmawk_set_cellp(MAWK, &valc, valtype, val);
549
550 mawk_array_set(MAWK, arr, &idxc, &valc);
551 mawk_cell_destroy(MAWK, &idxc);
552 mawk_cell_destroy(MAWK, &valc);
553 return 0;
554 }
555
556 int libmawk_set_array_at(mawk_state_t *MAWK, const char *arr_name, const char *idx, const char valtype, ...)
557 {
558 va_list ap;
559 int ret;
560
561 va_start(ap, valtype);
562 ret = libmawk_set_array_atv(MAWK, arr_name, idx, valtype, &ap);
563 va_end(ap);
564 return ret;
565 }
566
567 int libmawk_set_scalarv(mawk_state_t *MAWK, const char *var_name, const char valtype, va_list *ap)
568 {
569 mawk_cell_t *c;
570 c = mawk_get_var(MAWK, var_name);
571 if (c == NULL)
572 return -1;
573 libmawk_set_cellv(MAWK, c, valtype, ap);
574 return 0;
575 }
576
577 int libmawk_set_scalarp(mawk_state_t *MAWK, const char *var_name, const char valtype, void *val)
578 {
579 mawk_cell_t *c;
580 c = mawk_get_var(MAWK, var_name);
581 if (c == NULL)
582 return -1;
583 libmawk_set_cellp(MAWK, c, valtype, val);
584 return 0;
585 }
586
587 int libmawk_set_scalar(mawk_state_t *MAWK, const char *var_name, const char valtype, ...)
588 {
589 va_list ap;
590 int ret;
591
592 va_start(ap, valtype);
593 ret = libmawk_set_scalarv(MAWK, var_name, valtype, &ap);
594 va_end(ap);
595 return ret;
596 }
597
598
599 int libmawk_register_function(mawk_state_t *MAWK, const char *fname, libmawk_c_function *callback)
600 {
601 SYMTAB *sym;
602 sym = mawk_find(MAWK, fname, 0);
603
604 if (sym != NULL) {
605 /* special case: we already know symbol is a function but body is empty (typical for c calls) */
606 if ((sym->type == ST_FUNCT) && (sym->stval.fbp->code == NULL))
607 sym->type = ST_NONE;
608
609 /* if symbol is already defined as something else, return error */
610 if (sym->type != ST_NONE)
611 return 1;
612 }
613 else
614 sym = mawk_find(MAWK, mawk_strdup(MAWK, fname), 1);
615
616 sym->type = ST_C_FUNCTION;
617 sym->stval.c_function.callback = callback;
618 sym->stval.c_function.func_userdata = MAWK->func_userdata;
619 return 0;
620 }
621
622 mawk_cell_t *libmawk_cfunc_arg(mawk_cell_t *sp, int num_args, int n)
623 {
624 if ((n >= 0) && (n < num_args))
625 return sp - (num_args - n - 1);
626 return NULL;
627 }
628
629 mawk_cell_t *libmawk_cfunc_ret(mawk_cell_t *sp, int num_args)
630 {
631 return sp - num_args + 1;
632 }
633
634 SYMTAB *libmawk_register_array(mawk_state_t *MAWK, const char *name, array_imp_t *arr_imp)
635 {
636 SYMTAB *s;
637
638 /* register a variable only if it's not already in the hash */
639 s = mawk_find(MAWK, name, 0);
640 if (s != NULL)
641 return NULL;
642
643 s = mawk_insert(MAWK, mawk_strdup(MAWK, name));
644 memset(&(s->stval), 0, sizeof(s->stval));
645 s->type = ST_ARRAY;
646 s->offset = 0;
647 s->stval.array = mawk_array_new(MAWK, arr_imp);
648 return s;
649 }
650
651 SYMTAB *libmawk_register_scalar(mawk_state_t *MAWK, const char *name, mawk_celltype_t type, void *val)
652 {
653 SYMTAB *s;
654
655 switch(type) {
656 case C_NUM:
657 case C_STRING:
658 break;
659 default:
660 return NULL;
661 }
662
663 /* register a variable only if it's not already in the hash */
664 s = mawk_find(MAWK, name, 0);
665 if (s != NULL)
666 return NULL;
667
668 s = mawk_insert(MAWK, mawk_strdup(MAWK, name));
669 memset(&(s->stval), 0, sizeof(s->stval));
670 s->type = ST_VAR;
671 s->offset = 0;
672 s->stval.cp = MAWK_ZMALLOC(MAWK, mawk_cell_t);
673 s->stval.cp->type = type;
674 switch(type) {
675 case C_NUM:
676 if (val != NULL)
677 s->stval.cp->d.dval = *(mawk_num_t *)val;
678 else
679 s->stval.cp->d.dval = MAWK_NUM_ZERO;
680 break;
681 case C_STRING:
682 if (val != NULL)
683 s->stval.cp->ptr = (void *)mawk_new_STRING(MAWK, (char *)val);
684 else
685 s->stval.cp->ptr = (void *)mawk_new_STRING(MAWK, "");
686 break;
687 default:
688 mawk_bozo(MAWK, "libmawk_register_scalar: unsupported type");
689 }
690 return s;
691 }
692
693 mawk_num_t libmawk_cell2num(mawk_state_t *MAWK, const mawk_cell_t *cp)
694 {
695 mawk_cell_t tmp;
696 mawk_cellcpy(MAWK, &tmp, cp);
697 mawk_cast1_to_num(MAWK, &tmp);
698 /* NOTE: no need to destroy tmp: it's a number for sure, numbers are not allocated */
699 return tmp.d.dval;
700 }
701
702
703 int libmawk_cell2int(mawk_state_t *MAWK, const mawk_cell_t *cp)
704 {
705 return (int)libmawk_cell2num(MAWK, cp);
706 }
707
708 double libmawk_cell2double(mawk_state_t *MAWK, const mawk_cell_t *cp)
709 {
710 return (double)libmawk_cell2num(MAWK, cp);
711 }
712
0 #include <stdarg.h>
1 #include <libmawk/mawk.h>
2 #include <libmawk/init.h>
3 #include <libmawk/code.h>
4 #include <libmawk/files.h>
5 #include <libmawk/array_generic.h>
6 #include <libmawk/vio.h>
7 #include <libmawk/vio_orig.h>
8 #include <libmawk/vio_fifo.h>
9 #include <libmawk/execute.h>
10
11 /* initialize a new maw_state_t, load script, run BEGIN blocks */
12 mawk_state_t *libmawk_initialize(int argc, char *argv[]);
13
14 /* Or the same in 3 stages:
15 - stage 1 creates mawk state
16 - stage 2 processes CLI args and loads and parses scripts
17 - stage 3 runs BEGIN blocks
18
19 Creating "builtins" should happen between stage 1 and 2.
20 Injecting script (from elsewhere than argv[]) should happen between
21 stage 1 and 2. It is okay to not specify any script (or any argument)
22 in stage2.
23 */
24 mawk_state_t *libmawk_initialize_stage1(void);
25 int libmawk_initialize_stdio(mawk_state_t *m, int stdin_apps, int stdout_apps, int stderr_apps); /* set up stdio; where *_apps is zero use a pipe, where non-zero bind to app's */
26 mawk_state_t *libmawk_initialize_stage2(mawk_state_t *m, int argc, char *argv[]);
27 mawk_state_t *libmawk_initialize_stage3(mawk_state_t *m);
28
29 /* execute exit(0) in the script and free up all memory used by m */
30 void libmawk_uninitialize(mawk_state_t *m);
31
32 /* Or the same in 3 stages:
33 - stage 1 executes exit(0) (executing END { } if not already within END)
34 - stage 2 free m
35 Between stage 1 and stage 2 the application may read states changed by
36 the script in END
37 */
38 void libmawk_uninitialize_stage1(mawk_state_t *m);
39 void libmawk_uninitialize_stage2(mawk_state_t *m);
40
41
42
43 /* run all main blocks until input runs out */
44 void libmawk_run_main(mawk_state_t *m);
45
46 /* append \0 terminated string to the input buffer; returns -1 on error */
47 int libmawk_append_input(mawk_state_t *m, const char *input_str);
48
49 /* append data to the input buffer; returns -1 on error */
50 int libmawk_append_ninput(mawk_state_t *m, const char *input, int len);
51
52 /* close the input buffer (eof to the script) in case it was a pipe
53 between the app and awk - else don't do anything */
54 int libmawk_close_input(mawk_state_t *m);
55
56
57 /* set value of a cell */
58 mawk_cell_t *libmawk_set_cell(mawk_state_t *MAWK, mawk_cell_t *cell, const char argtype, ...);
59
60 /* set value of a cell from a pointer */
61 mawk_cell_t *libmawk_set_cellp(mawk_state_t *MAWK, mawk_cell_t *cell, const char argtype, void *argp);
62
63 /* call an awk function; argtype is a string consists of a character for
64 each argument depending on the argument type:
65 - d for integer
66 - f for float
67 - s for string
68 If res is not NULL, it is destroyed (regardless of the return value)
69 and the result cell is copied in res and res needs to be cell_destroyed
70 by the caller.
71 Returns 0 on success or -1 on error.
72 */
73 mawk_exec_result_t libmawk_call_function(mawk_state_t *MAWK, const char *fname, mawk_cell_t *retc, const char *argtypes, ...);
74
75 /* Same as libmawk_call_function, except this one takes an array of pointer to the arguments */
76 mawk_exec_result_t libmawk_call_functionp(mawk_state_t *MAWK, const char *fname, mawk_cell_t *retc, const char *argtypes, void **args);
77
78 /* Same as libmawk_call_function, except this one takes an array of pointer to read-only cells */
79 mawk_exec_result_t libmawk_call_functionc(mawk_state_t *MAWK, const char *fname, mawk_cell_t *retc, int argc, const mawk_cell_t *argv);
80
81 /* free an allocated cell (use after libmawk_call_function */
82 void libmawk_cell_destroy(mawk_state_t *MAWK, mawk_cell_t *c);
83
84
85 /* convert a cell to string in buff, return pointer to buff */
86 char *libmawk_print_cell(mawk_state_t *MAWK, const mawk_cell_t *c, char *buff, int buffsize);
87
88 /* resolve a variable by name; the caller shouldn't change anything on the cell because of
89 the possible side effects required on write. The variable is not necessarily
90 scalar. */
91 const mawk_cell_t *libmawk_get_var(mawk_state_t *MAWK, const char *vname);
92
93 /* resolve an element of an array by array name and index and returns 1
94 if the element is found. If result is non-NULL, the member mawk_cell_t is copied
95 there. Changing result will not affect the value in the actual array and
96 the caller is responsible for destroying the cell.
97 If arr_name doesn't name an array or upon other error, return value is -1
98 On succes returns 1
99 NOTE: if result is non-NULL, it is destroyed.
100 If create is non-zero, create non-existing element with empty value
101 */
102 int libmawk_get_array_at(mawk_state_t *MAWK, const char *arr_name, const char *idx, mawk_cell_t *result, int create);
103
104 /* set array at a specific index; valtype/val semantics are the same as for
105 the libmawk_cell_set*() */
106 int libmawk_set_array_atv(mawk_state_t *MAWK, const char *arr_name, const char *idx, const char valtype, va_list *ap);
107 int libmawk_set_array_atp(mawk_state_t *MAWK, const char *arr_name, const char *idx, const char valtype, void *val);
108 int libmawk_set_array_at(mawk_state_t *MAWK, const char *arr_name, const char *idx, const char valtype, ...);
109
110 /* same for scalars */
111 int libmawk_set_scalarv(mawk_state_t *MAWK, const char *var_name, const char valtype, va_list *ap);
112 int libmawk_set_scalarp(mawk_state_t *MAWK, const char *var_name, const char valtype, void *val);
113 int libmawk_set_scalar(mawk_state_t *MAWK, const char *var_name, const char valtype, ...);
114
115 /* register a new function implemented in callback. Returns 0 on success. */
116 int libmawk_register_function(mawk_state_t *MAWK, const char *fname, libmawk_c_function *callback);
117
118 /* calculate the cell pointer of arugmnet number n on the stack from within
119 a C function called back from awk */
120 mawk_cell_t *libmawk_cfunc_arg(mawk_cell_t *sp, int num_args, int n);
121
122 /* calculate the cell pointer of the return value on the stack from within
123 a C function called back from awk */
124 mawk_cell_t *libmawk_cfunc_ret(mawk_cell_t *sp, int num_args);
125
126 /* *** register new variables _before stage2_ *** */
127 /* register a new array; if arr_imp is NULL, the generic (_orig) array
128 implementation is used, else the virtualized array hooks provided by imp */
129 SYMTAB *libmawk_register_array(mawk_state_t *MAWK, const char *name, array_imp_t *arr_imp);
130 /* register a scalar; type must be C_STRING (val is a char *) or C_NUM (val
131 is a mawk_num_t *) */
132 SYMTAB *libmawk_register_scalar(mawk_state_t *MAWK, const char *name, mawk_celltype_t type, void *val);
133
134
135 /* return the numeric value of a cell in mawk's internal number type or
136 int or double */
137 mawk_num_t libmawk_cell2num(mawk_state_t *MAWK, const mawk_cell_t *cp);
138 int libmawk_cell2int(mawk_state_t *MAWK, const mawk_cell_t *cp);
139 double libmawk_cell2double(mawk_state_t *MAWK, const mawk_cell_t *cp);
140
141 /* empty mawk_cell_t initializer - cells should start out with this value */
142 #define libmawk_empty_cell {0, NULL, {0}}
0
1 /********************************************
2 main.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include "mawk.h"
16 #include "init.h"
17 #include "code.h"
18 #include "files.h"
19 #include "debug.h"
20 #include "viohack.h"
21 #include "vio_orig.h"
22
23 int main(int argc, char **argv)
24 {
25 mawk_state_t *m;
26 int err = 0;
27 m = mawk_initialize(argc, argv, mawk_vio_orig_init);
28 if (m != NULL) {
29 mawk_vio_orig_setup_stdio(m, 1, 1, 1);
30 mawk_detect_interactive(m);
31 #ifndef MAWK_NO_COMP
32 mawk_parse(m);
33 if (m->compile_error_count != 0)
34 err = 1;
35 m->mawk_state = EXECUTION;
36 #ifndef MAWK_NO_EXEC
37 if (m->debug_symbols)
38 mawk_debug_callstack_push(m, &mawk_debug_begin);
39 #endif
40 if ((m->compile_error_count == 0) && (!m->do_exit))
41 #endif
42 #ifndef MAWK_NO_EXEC
43 mawk_execute(m, m->execution_start, m->eval_stack - 1, 0);
44 #endif
45
46 #ifndef MAWK_NO_EXEC
47 if (m->debug_symbols)
48 mawk_debug_callstack_pop(m);
49 #endif
50
51 err = m->final_exit_code;
52 mawk_uninitialize(m);
53 }
54 else
55 err = 1;
56
57 return err;
58 }
59
60 void mawk_exit_(mawk_state_t *MAWK, int x)
61 {
62 MAWK->do_exit = 1;
63 MAWK->final_exit_code = MAWK->rt_exit_code != 0 ? MAWK->rt_exit_code : x;
64 }
0
1 /********************************************
2 makescan.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* source for makescan.exe which builds the scancode[]
17 via: makescan.exe > scancode.c
18 */
19
20 #define MAKESCAN
21
22 #include "scan.h"
23 #include "mawk.h"
24
25 void mawk_scan_init(mawk_state_t * MAWK)
26 {
27 register char *p;
28
29 memset(MAWK->scan_code, SC_UNEXPECTED, sizeof(MAWK->scan_code));
30 for (p = MAWK->scan_code + '0'; p <= MAWK->scan_code + '9'; p++)
31 *p = SC_DIGIT;
32 MAWK->scan_code[0] = 0;
33 MAWK->scan_code[' '] = MAWK->scan_code['\t'] = MAWK->scan_code['\f'] = SC_SPACE;
34 MAWK->scan_code['\r'] = MAWK->scan_code['\013'] = SC_SPACE;
35
36 MAWK->scan_code[';'] = SC_SEMI_COLON;
37 MAWK->scan_code['\n'] = SC_NL;
38 MAWK->scan_code['{'] = SC_LBRACE;
39 MAWK->scan_code['}'] = SC_RBRACE;
40 MAWK->scan_code['+'] = SC_PLUS;
41 MAWK->scan_code['-'] = SC_MINUS;
42 MAWK->scan_code['*'] = SC_MUL;
43 MAWK->scan_code['/'] = SC_DIV;
44 MAWK->scan_code['%'] = SC_MOD;
45 MAWK->scan_code['^'] = SC_POW;
46 MAWK->scan_code['('] = SC_LPAREN;
47 MAWK->scan_code[')'] = SC_RPAREN;
48 MAWK->scan_code['_'] = SC_IDCHAR;
49 MAWK->scan_code['='] = SC_EQUAL;
50 MAWK->scan_code['#'] = SC_COMMENT;
51 MAWK->scan_code['\"'] = SC_DQUOTE;
52 MAWK->scan_code[','] = SC_COMMA;
53 MAWK->scan_code['!'] = SC_NOT;
54 MAWK->scan_code['<'] = SC_LT;
55 MAWK->scan_code['>'] = SC_GT;
56 MAWK->scan_code['|'] = SC_OR;
57 MAWK->scan_code['&'] = SC_AND;
58 MAWK->scan_code['?'] = SC_QMARK;
59 MAWK->scan_code[':'] = SC_COLON;
60 MAWK->scan_code['['] = SC_LBOX;
61 MAWK->scan_code[']'] = SC_RBOX;
62 MAWK->scan_code['\\'] = SC_ESCAPE;
63 MAWK->scan_code['.'] = SC_DOT;
64 MAWK->scan_code['~'] = SC_MATCH;
65 MAWK->scan_code['$'] = SC_DOLLAR;
66
67 for (p = MAWK->scan_code + 'A'; p <= MAWK->scan_code + 'Z'; p++)
68 *p = *(p + 'a' - 'A') = SC_IDCHAR;
69
70 }
71
72 void scan_print(mawk_state_t * MAWK)
73 {
74 register char *p = MAWK->scan_code;
75 register int c; /* column */
76 register int r; /* row */
77
78 printf("\n\n/* scancode.c */\n\n\n");
79 printf("const char mawk_scan_code[256] = {\n");
80
81 for (r = 1; r <= 16; r++) {
82 for (c = 1; c <= 16; c++) {
83 printf("%2d", *p++);
84 if (r != 16 || c != 16)
85 putchar(',');
86 }
87 putchar('\n');
88 }
89
90 printf("} ;\n");
91 }
92
93
94 int main(int argc, char **argv)
95 {
96 mawk_state_t m, *MAWK = &m;
97 mawk_scan_init(MAWK);
98 scan_print(MAWK);
99 return 0;
100 }
0 #!/bin/sh
1 docdir=../../../doc
2 PAGES="example.7libmawk
3 libmawk_append_input.3libmawk
4 libmawk_call_function.3libmawk
5 libmawk_cell_destroy.3libmawk
6 libmawk_get_var.3libmawk
7 libmawk_initialize.3libmawk
8 libmawk_initialize_stage.3libmawk
9 libmawk_register_function.3libmawk
10 libmawk_run_main.3libmawk
11 libmawk_set_cell.3libmawk
12 libmawk_uninitialize.3libmawk
13 lmawk.1"
14
15 cat input/example1 ../../testapp/main.c input/example2 > example.7libmawk
16
17 for n in $PAGES
18 do
19 groff -c -Tlatin1 -mandoc $n > $docdir/$n.txt
20 groff -c -Thtml -mandoc $n > $docdir/$n.html
21 done
22
0 .\" Copyright 2009 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH EXAMPLE 7 2009-08-10 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk example \- how to use the library
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .SH DESCRIPTION
22 Libmawk is a library that lets applications to embed awk scripts using the
23 code of the popular implementation
24 .B mawk.
25 The normal process is to call libmawk_initialize() to set up a new mawk
26 context (with script(s) loaded), then in the main loop feed it using
27 libmawk_append_input(). For "out of band" communication, the program
28 may also call functions implemented in awk and read (or modify) global
29 variables of the awk script. The hos tapplication usally will also bind
30 some of its functions to the context using libmawk_register_function, which
31 allows the awk script to call the host applicaiton's functions directly as
32 they were awk builtins or user defined functions. After the main loop, the
33 application destroys the context freeing up all memory allocated for
34 the script(s).
35 .sp
36 One context is for one awk program. One awk program may consist of multiple
37 script files (just as with command line awk, with multiple -f filename
38 arguments). Libmawk is instance safe, the host application may create
39 multiple instances of contexts with the same or with different set of
40 awk scripts loaded. These contexts are totally separate, no variables,
41 functions or any sort of states are shared. However, the host application
42 may provide means of communication between those scripts by custom functions
43 or by copying variable contents between them.
44 .SH Example application
45 The following example application creates a single context to demonstrate
46 all the above mentioned functionality.
47 .nf
0 .\" Copyright 2009 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH LIBMAWK_APPEND_INPUT 3 2009-08-10 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk_append_input \- append a string to an input buffer
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .BI "void libmawk_append_input(mawk_state_t *" m ", const char *" input_str );
22 .fi
23 .sp
24 .BI "void libmawk_append_ninput(mawk_state_t *" m ", const char *" input ", int" len );
25 .fi
26 .sp
27 .SH DESCRIPTION
28 The
29 .BR libmawk_append_input ()
30 and
31 .BR libmawk_append_ninput ()
32 functions allow the application to fill the input buffer of a libmawk context.
33 No record separator is appended, only the bytes donated by input_str or input,
34 thus it is possible to append partial records. Appending to
35 the input doesn't have the side effect of any script being run. There may be
36 multiple libmawk_append_input() calls before a call to libmawk_run_main(). The
37 latter all is used to let the script process the input buffer.
38 .sp
39 The only difference between the two calls are the input format:
40 .BR libmawk_append_input ()
41 expects a nul-terminated string, whereas
42 .BR libmawk_append_ninput ()
43 takes an arbitrary binary data and its length.
44 .sp
45 Argument m is a libmawk context previously returned by libmawk_initialize()
46 or libmawk_initialize_stage3().
47 .SH "SEE ALSO"
48 .BR libmawk_initialize_stage (3libmawk),
49 .BR libmawk_initialize (3libmawk),
50 .BR libmawk_run_main (3libmawk).
51
0 .\" Copyright 2009 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH LIBMAWK_CALL_FUNCTION 3 2009-08-10 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk_call_function \- call an user defined (script) function
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .BI "int libmawk_call_function(mawk_state_t *" MAWK ", const char *" fname ", CELL *" res ", const char *" argtpes ", ...);"
22 .fi
23 .BI "int libmawk_call_functionp(mawk_state_t *" MAWK ", const char *" fname ", CELL *" res ", const char *" argtpes ", void **args);"
24 .fi
25 .sp
26 .SH DESCRIPTION
27 The
28 .BR libmawk_call_function ()
29 function looks up an user defined awk function called
30 .I fname
31 , fills the stack with arguments converted from the varargs and calls
32 the function.
33 The
34 .BR libmawk_call_functionp ()
35 performs the same action but avoids using vararg by requiring an array of
36 generic pointers to the function arguments.
37 .sp
38 Argtype is a zero terminated string for both functions, each character corresponding
39 to an argument. Type characters are described in libmawk_set_cell() manual page.
40 .sp
41 If res is non-NULL, it is cell_destroyed (regardless of errors) and the
42 return value of the user function is copied into it. The caller shall
43 run libmawk_cell_destroy on it.
44 .sp
45 Argument m is a libmawk context previously returned by libmawk_initialize()
46 or libmawk_initialize_stage3().
47
48 .SH "RETURN VALUE"
49 A pointer to the cell returned by the user function. The cell returned\
50 must be destroyed by the application using libmawk_cell_destroy.
51 .SH "SEE ALSO"
52 .BR libmawk_initialize_stage (3libmawk),
53 .BR libmawk_initialize (3libmawk),
54 .BR libmawk_cell_destroy (3libmawk),
55 .BR libmawk_set_cell (3libmawk),
0 .\" Copyright 2009 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH LIBMAWK_CELL_DESTROY 3 2009-08-12 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk_cell_destroy \- free all memory associated with a cell
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .BI "void libmawk_cell_destroy(mawk_state_t *" m ", CELL *" c ");"
22 .fi
23 .sp
24 .SH DESCRIPTION
25 The
26 .BR libmawk_cell_destroy ()
27 function frees all memory allocated to store a mawk cell. It is useful
28 with some of the libmawk calls that return a newly allocated cell, such as
29 the libmawk_call_function() call.
30 .sp
31 Argument m is a libmawk context previously returned by libmawk_initialize()
32 or libmawk_initialize_stage3().
33
34 .SH "SEE ALSO"
35 .BR libmawk_initialize_stage (3libmawk),
36 .BR libmawk_initialize (3libmawk),
37 .BR libmawk_call_function (3libmawk).
38
0 .\" Copyright 2009..2014 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH LIBMAWK_GET_VAR 3 2009-08-12 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk_get_var \- returns a pointer to a mawk variable
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .BI "const CELL *libmawk_get_var(mawk_state_t *" m ", const char *" vname ");"
22 .BI "int libmawk_get_array_at(mawk_state_t *" m ", const char *" arr_name ",
23 .BI " const char *" idx ", const char *" res ", int " alloc ");"
24 .fi
25 .sp
26 .SH DESCRIPTION
27 The
28 .BR libmawk_get_var ()
29 function returns a pointer to a mawk cell that represents the global variable
30 with name passed in
31 .I vname
32 in the given context. The returned CELL should never be free'd or destroyed
33 or modified.
34 Function libmawk_print_cell may be used for converting the cell to string.
35 .sp
36 Function
37 .BR libmawk_get_array_at ()
38 performs the same operation for an element of an array. -1 is returned if
39 .I arr_name
40 is not an array or upon an error. If
41 .I idx
42 is not an existing index in the array it is allocated if
43 .I alloc
44 is non-zero. If
45 .I res
46 is not NULL, it is destroyed (regardless of the return value) and if
47 the index exists (or is created by the call), is loaded with the value.
48 The caller needs to destroy
49 .I res
50 after use. Since
51 .I res
52 is destroyed when non-NULL, it must be a valid cell with valid type.
53 .sp
54 Argument m is a libmawk context previously returned by libmawk_initialize()
55 or libmawk_initialize_stage3().
56
57 .SH "SEE ALSO"
58 .BR libmawk_initialize_stage (3libmawk),
59 .BR libmawk_initialize (3libmawk),
60 .BR libmawk_call_function (3libmawk),
61 .BR libmawk_print_cell (3libmawk).
62
63
0 .\" Copyright 2009 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH LIBMAWK_INITIALIZE 3 2009-08-10 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk_initialize \- create a new libmawk context
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .BI "mawk_state_t *libmawk_initialize(int " s ", char *" argv[] );
22 .fi
23 .sp
24 .SH DESCRIPTION
25 The
26 .BR libmawk_initialize ()
27 function returns a pointer to a newly created libmawk context. Any amount
28 of libmawk contexts can live in parallel in an application. Arguments are the
29 same as for a command line mawk session. Scripts are loaded (either from command
30 line or from files using -f), variables are set (with -v), special options
31 are set (with -W), etc.
32 .SH "RETURN VALUE"
33 A pointer to a new libmawk context or NULL on error.
34 .SH "SEE ALSO"
35 .BR libmawk_initialize_stage (3libmawk),
36 .BR libmawk_uninitialize (3libmawk),
0 .\" Copyright 2009 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH LIBMAWK_INITIALIZE_STAGE 3 2009-08-10 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk_initialize_stage* \- create a new libmawk context in 3 stages
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .BI "mawk_state_t *libmawk_initialize_stage1(void);
22 .sp
23 .BI "mawk_state_t *libmawk_initialize_stage2(mawk_state_t * " m, int " s ", char *" argv[] );
24 .sp
25 .BI "mawk_state_t *libmawk_initialize_stage3(mawk_state_t * " m );
26 .fi
27 .sp
28 .SH DESCRIPTION
29 The
30 .BR libmawk_initialize_stage* ()
31 functions together do the same as libmawk_initialize() but allows
32 the application to take actions between different stages.
33 .BR libmawk_initialize_stage1 ()
34 returns a pointer to a newly created libmawk context. Any amount
35 of libmawk contexts can live in parallel in an application.
36 .sp
37 .BR libmawk_initialize_stage2 ()
38 can be called after a succesful stage1 call.
39 Stage2 is responsible for processing the command line arguments and
40 loading any script.
41
42 Arguments are the
43 same as for a command line mawk session. Scripts are loaded (either from command
44 line or from files using -f), variables are set (with -v), special options
45 are set (with -W), etc. Unlike with libmawk_initialize(), the application may
46 decide not to provide any script at this stage. All command line arguments
47 are processed.
48
49 The most common case is that
50 the application calls stage1 with no script, then already having a context
51 makes some manipulations on it (for example registers some C functions that
52 would be already called in the BEGIN part of the script that will be later
53 loaded). Optionally before calling stage2 the application loads the actual
54 script(s) using mawk_append_input_file().
55 .sp
56 .BR libmawk_initialize_stage3 ()
57 is called as a final step of the three-stage initialization process. Stage3
58 is responsible for running all the BEGIN parts of all scripts loaded at
59 stage1 or stage2. It is useful to have stage3 in a separate call to allow
60 applications to manipulate the context right before initializing the scripts.
61 .sp
62 Stage2 gets the pointer returned by stage1 and stage3 gets the pointer
63 returned by stage2. Subsequent calls to libmawk functions should get
64 the pointer returned by stage3.
65
66 .SH "RETURN VALUE"
67 At stage 1 a pointer to a new libmawk context or NULL on error. Subsequent
68 stages will return the same pointer or NULL on error.
69 .SH "SEE ALSO"
70 .BR libmawk_initialize_stage (3libmawk),
71 .BR libmawk_uninitialize (3libmawk),
72 .BR mawk_append_input_file(3libmawk).
0 .\" Copyright 2009 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH LIBMAWK_REGISTER_FUNCTION 3 2009-08-12 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk_register_function \- registers a C function with a callback
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .BI "typedef CELL *libmawk_c_function(mawk_state_t *" m ", CELL *" sp ", int " a_args ");"
22 .fi
23 .BI "int libmawk_register_function(mawk_state_t *" MAWK ", const char *" fname ", libmawk_c_function *" callback ");"
24 .fi
25 .BI "CELL *libmawk_stackret(CELL *" original_sp ");"
26 .fi
27 .sp
28 .SH DESCRIPTION
29 The
30 .BR libmawk_register_function ()
31 call registers an user defined function donated by the host application in
32 a mawk context so that it acts exactly like user defined functions in
33 written in awk. The name of the new function is given in
34 .I fname
35 and should not match any of the user defined function names in the awk
36 script.
37 .sp
38 When the user function is called back, argument
39 .I sp
40 is the stack pointer and
41 .I a_args
42 holds the number of arguments. The user function is responsible for managing
43 the stack: it should pop all arguments before returning.
44 .sp
45 The user function should also generate a return value, which is done by
46 calling libmawk_set_cell() on the stack slot returned by libmawk_stackret.
47 Libmawk_stackret should be called with the modified
48 .I sp
49 after popping all arguments.
50 .sp
51 Argument m is a libmawk context previously returned by libmawk_initialize()
52 or libmawk_initialize_stage3().
53 .sp
54 For more information about user function callbacks, especially on stack handling,
55 see manual page example(3libmawk).
56 .SH "RETURN VALUE"
57 The user function should return the stack pointer after popping all arguments.
58 .sp
59 The libmawk_register_function call returns 0 on success.
60 .sp
61 Call libmawk_stackret returns a stack pointer to the slot where the user function should store its return value.
62
63 .SH "SEE ALSO"
64 .BR libmawk_initialize_stage (3libmawk),
65 .BR libmawk_initialize (3libmawk),
66 .BR libmawk_set_cell (3libmawk),
67 .BR libmawk_print_cell (3libmawk).
68
69
0 .\" Copyright 2009 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH LIBMAWK_RUN_MAIN 3 2009-08-10 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk_run_main \- run main parts of a script
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .BI "void libmawk_run_main(mawk_state_t *" m );
22 .fi
23 .sp
24 .SH DESCRIPTION
25 The
26 .BR libmawk_run_main ()
27 attempts to take and parse the next input record and runs all main
28 parts of the script that matches. If there are multiple full records
29 in the input buffer, the process repeats until the buffer becomes empty
30 or contains a partial record. If there is no full record in the buffer,
31 the call returns with nothing done. The call itself never blocks, but the
32 script may. The input buffer may be filled using the libmawk_append_input()
33 call.
34 .sp
35 Argument m is a libmawk context previously returned by libmawk_initialize()
36 or libmawk_initialize_stage3().
37 .SH "SEE ALSO"
38 .BR libmawk_initialize_stage (3libmawk),
39 .BR libmawk_initialize (3libmawk),
40 .BR libmawk_append_input (3libmawk),
0 .\" Copyright 2009 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH LIBMAWK_SET_CELL 3 2009-08-10 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk_set_cell \- set the value of a mawk cell.
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .BI "CELL *libmawk_set_cell(mawk_state_t *" m ", CELL *" cell ", const char" argtype "," ... );
22 .fi
23 .BI "CELL *libmawk_set_cellp(mawk_state_t *" m ", CELL *" cell ", const char" argtype ", void *" argp );
24 .sp
25 .SH DESCRIPTION
26 The
27 .BR libmawk_set_cell ()
28 function modifies the value of a mawk cell (variable). Argumetn argtype is a
29 format character that describes the type of the payload (accessed trough vararg).
30 .sp
31 The
32 .BR libmawk_set_cellp ()
33 function performs the same action but accepts a generic pointer to the payload.
34 .sp
35 .B "Format character"
36 is one of the followings:
37 .in +4n
38 .TP
39 'd' for int payload
40 .TP
41 'f' for double payload
42 .TP
43 's' for (zero terminated) char * payload.
44 .in
45 .sp
46 Argument m is a libmawk context previously returned by libmawk_initialize()
47 or libmawk_initialize_stage3().
48
49 .SH "RETURN VALUE"
50 A pointer to the cell modified.
51 .SH "SEE ALSO"
52 .BR libmawk_initialize_stage (3libmawk),
53 .BR libmawk_initialize (3libmawk),
54 .BR libmawk_get_var (3libmawk).
0 .\" Copyright 2009 Tibor Palinkas (mawk@inno.bme.hu)
1 .\"
2 .\" Permission is granted to make and distribute verbatim copies of this
3 .\" manual provided the copyright notice and this permission notice are
4 .\" preserved on all copies.
5 .\"
6 .\" Permission is granted to copy and distribute modified versions of this
7 .\" manual under the conditions for verbatim copying, provided that the
8 .\" entire resulting derived work is distributed under the terms of a
9 .\" permission notice identical to this one.
10 .\"
11 .\" Formatted or processed versions of this manual, if unaccompanied by
12 .\" the source, must acknowledge the copyright and authors of this work.
13 .\"
14 .TH LIBMAWK_UNINITIALIZE 3 2009-08-10 "libmawk" "libmawk manual"
15 .SH NAME
16 libmawk_uninitialize \- destroy a libmawk context
17 .SH SYNOPSIS
18 .nf
19 .B #include <libmawk.h>
20 .sp
21 .BI "void libmawk_uninitialize(mawk_state_t * " m );
22 .fi
23 .sp
24 .SH DESCRIPTION
25 The
26 .BR libmawk_uninitialize ()
27 function destroys a context previously created using libmawk_initialize()
28 or libmawk_initialize_stage1() call. It unloads scripts and frees all memory
29 of the context.
30 .SH "SEE ALSO"
31 .BR libmawk_initialize_stage (3libmawk),
32 .BR libmawk_initialize (3libmawk),
0 .TH LMAWK 1 "Dec 12 2010" "Version 1.2" "USER COMMANDS"
1 .\" strings
2 .ds ex \fIexpr\fR
3 .SH NAME
4 lmawk \- pattern scanning and text processing language
5 .SH SYNOPSIS
6 .B lmawk
7 [\-\fBW
8 .IR option ]
9 [\-\fBF
10 .IR value ]
11 [\-\fBv
12 .IR var=value ]
13 [\-\|\-] 'program text' [file ...]
14 .br
15 .B lmawk
16 [\-\fBW
17 .IR option ]
18 [\-\fBF
19 .IR value ]
20 [\-\fBv
21 .IR var=value ]
22 [\-\fBf
23 .IR program-file ]
24 [\-\|\-] [file ...]
25 .SH DESCRIPTION
26 .B lmawk
27 is an interpreter for the AWK Programming Language derived from mawk.
28 The AWK language
29 is useful for manipulation of data files,
30 text retrieval and processing,
31 and for prototyping and experimenting with algorithms.
32 .B lmawk
33 is a \fInew awk\fR meaning it implements the AWK language as
34 defined in Aho, Kernighan and Weinberger,
35 .I "The AWK Programming Language,"
36 Addison-Wesley Publishing, 1988. (Hereafter referred to as
37 the AWK book.)
38 .B mawk
39 conforms to the Posix 1003.2
40 (draft 11.3)
41 definition of the AWK language
42 which contains a few features not described in the AWK
43 book, and
44 .B mawk
45 provides a small number of extensions.
46 .PP
47 An AWK program is a sequence of \fIpattern {action}\fR pairs and
48 function definitions.
49 Short programs are entered on the command line
50 usually enclosed in ' ' to avoid shell
51 interpretation.
52 Longer programs can be read in from a
53 file with the \-f option.
54 Data input is read from the list of files on
55 the command line or from standard input when the list is empty.
56 The input is broken into records as determined by the
57 record separator variable, \fBRS\fR. Initially,
58 .B RS
59 = "\en" and records are synonymous with lines.
60 Each record is compared against each
61 .I pattern
62 and if it matches, the program text for
63 .I "{action}"
64 is executed.
65 .SH OPTIONS
66 .TP \w'\-\fBW'u+\w'\fRsprintf=\fInum\fR'u+2n
67 \-\fBF \fIvalue\fP
68 sets the field separator, \fBFS\fR, to
69 .IR value .
70 .TP
71 \-\fBf \fIfile
72 Program text is read from \fIfile\fR instead of from the
73 command line. Multiple
74 .B \-f
75 options are allowed. As a libmawk extension, if file name starts with
76 plus ('+'), it is not loaded if the same file has been loaded already
77 by a previous -f or include from any of the scripts already loaded.
78 .TP
79 \-\fBb \fIfile
80 Program bytecode is read from \fIfile\fR . Multiple
81 .B \-b
82 options are allowed. Bytecode can be generated using -Wcompile. Libmawk
83 may refuse to load bytecode generated on a different system if byte order,
84 type sizes or dump version differs.
85 .TP
86 \-\fBv \fIvar=value\fR
87 assigns
88 .I value
89 to program variable
90 .IR var .
91 .TP
92 \-\|\-
93 indicates the unambiguous end of options.
94 .PP
95 The above options will be available with any Posix compatible
96 implementation of AWK, and implementation specific options are
97 prefaced with
98 .BR \-W .
99 .B lmawk
100 provides six:
101 .TP \w'\-\fBW'u+\w'\fRsprintf=\fInum\fR'u+2n
102 \-\fBW \fRversion
103 .B lmawk
104 writes its version and copyright
105 to stdout and compiled limits to
106 stderr and exits 0.
107 .TP
108 \-\fBW \fRdebug
109 include location info in the compiled code; location information is visible
110 in the dump and when debugging libmawk.
111 .TP
112 \-\fBW \fRdump
113 writes an assembler like listing of the internal
114 representation of the program to stdout and exits 0
115 (on successful compilation).
116 .TP
117 \-\fBW \fRdumpsym
118 writes a list of global symbols to stdout and exits 0
119 (on successful compilation).
120 .TP
121 \-\fBW \fRcompile
122 writes a binary dump of the bytecode to stdout. This bytecode can be
123 loaded using the
124 \-\fBb \fRswitch.
125 .TP
126 \-\fBW \fRinteractive
127 sets unbuffered writes to stdout and line buffered reads from stdin.
128 Records from stdin are lines regardless of the value of
129 .BR RS .
130 .TP
131 \-\fBW \fRmaxmem=\fInum\fR
132 limit dynamic memory allocation during compilation and execution to
133 .I num
134 bytes and exit with out-of-the-memory error if more memory is to be allocated.
135 Optional suffixes are k for kilobyte and m for megabyte. 0 means unlimited,
136 which is also the default.
137 .TP
138 \-\fBW \fRexec \fIfile
139 Program text is read from
140 .I file
141 and this is the last option. Useful on systems that support the
142 .B #!
143 "magic number" convention for executable scripts.
144 .TP
145 \-\fBW \fRsprintf=\fInum\fR
146 adjusts the size of
147 .B lmawk's
148 internal sprintf buffer to
149 .I num
150 bytes. More than rare use of this option indicates
151 .B lmawk
152 should be recompiled.
153 .TP
154 \-\fBW \fRposix_space
155 forces
156 .B lmawk
157 not to consider '\en' to be space.
158 .PP
159 The short forms
160 .BR \-W [vdiesp]
161 are recognized and on some systems \fB\-W\fRe is mandatory to avoid
162 command line length limitations.
163 .SH "THE AWK LANGUAGE"
164 .SS "\fB1. Program structure"
165 An AWK program is a sequence of
166 .I "pattern {action}"
167 pairs and user
168 function definitions.
169 .PP
170 A pattern can be:
171 .nf
172 .RS
173 \fBBEGIN
174 END\fR
175 expression
176 expression , expression
177 .sp
178 .RE
179 .fi
180 One, but not both,
181 of \fIpattern {action}\fR can be omitted. If
182 .I {action}
183 is omitted it is implicitly { print }. If
184 .I pattern
185 is omitted, then it is implicitly matched.
186 .B BEGIN
187 and
188 .B END
189 patterns require an action.
190 .PP
191 Statements are terminated by newlines, semi-colons or both.
192 Groups of statements such as
193 actions or loop bodies are blocked via { ... } as in C. The
194 last statement in a block doesn't need a terminator. Blank lines
195 have no meaning; an empty statement is terminated with a
196 semi-colon. Long statements
197 can be continued with a backslash, \e\|. A statement can be broken
198 without a backslash after a comma, left brace, &&, ||,
199 .BR do ,
200 .BR else ,
201 the right parenthesis of an
202 .BR if ,
203 .B while
204 or
205 .B for
206 statement, and the
207 right parenthesis of a function definition.
208 A comment starts with # and extends to, but does not include
209 the end of line.
210 .PP
211 The following statements control program flow inside blocks.
212 .RS
213 .PP
214 .B if
215 ( \*(ex )
216 .I statement
217 .PP
218 .B if
219 ( \*(ex )
220 .I statement
221 .B else
222 .I statement
223 .PP
224 .B while
225 ( \*(ex )
226 .I statement
227 .PP
228 .B do
229 .I statement
230 .B while
231 ( \*(ex )
232 .PP
233 .B for
234 (
235 \fIopt_expr\fR ;
236 \fIopt_expr\fR ;
237 \fIopt_expr\fR
238 )
239 .I statement
240 .PP
241 .B for
242 ( \fIvar \fBin \fIarray\fR )
243 .I statement
244 .PP
245 .B continue
246 .PP
247 .B break
248 .RE
249 .\"
250 .SS "\fB2. Data types, conversion and comparison"
251 There are two basic data types, numeric and string.
252 Numeric constants can be integer like \-2,
253 decimal like 1.08, or in scientific notation like
254 \-1.1e4 or .28E\-3. All numbers are represented internally and all
255 computations are done in floating point arithmetic.
256 So for example, the expression
257 0.2e2 == 20
258 is true and true is represented as 1.0.
259 .PP
260 String constants are enclosed in double quotes.
261 .sp
262 .ce
263 "This is a string with a newline at the end.\en"
264 .sp
265 Strings can be continued across a line by escaping (\e) the newline.
266 The following escape sequences are recognized.
267 .nf
268 .sp
269 \e\e \e
270 \e" "
271 \ea alert, ascii 7
272 \eb backspace, ascii 8
273 \et tab, ascii 9
274 \en newline, ascii 10
275 \ev vertical tab, ascii 11
276 \ef formfeed, ascii 12
277 \er carriage return, ascii 13
278 \eddd 1, 2 or 3 octal digits for ascii ddd
279 \exhh 1 or 2 hex digits for ascii hh
280 .sp
281 .fi
282 If you escape any other character \ec, you get \ec, i.e.,
283 .B lmawk
284 ignores the escape.
285 .PP
286 There are really three basic data types; the third is
287 .I "number and string"
288 which has both a numeric value and a string value
289 at the same time.
290 User defined variables come into existence when first referenced
291 and are initialized to
292 .IR null ,
293 a number and string value which has numeric value 0 and string value
294 "".
295 Non-trivial number and string typed data come from input
296 and are typically stored in fields. (See section 4).
297 .PP
298 The type of an expression is determined by its context and automatic
299 type conversion occurs if needed. For example, to evaluate the
300 statements
301 .nf
302 .sp
303 y = x + 2 ; z = x "hello"
304 .sp
305 .fi
306 The value stored in variable y will be typed numeric.
307 If x is not numeric,
308 the value read from x is converted to numeric before it is added to
309 2 and stored in y. The value stored in variable z will be typed
310 string, and the value of x will be converted to string if necessary
311 and concatenated with "hello". (Of course, the value and type
312 stored in x is not changed by any conversions.)
313 A string expression is converted to numeric using its longest
314 numeric prefix as with
315 .IR atof (3).
316 A numeric expression is converted to string by replacing
317 .I expr
318 with
319 .BR sprintf(CONVFMT ,
320 .IR expr ),
321 unless
322 .I expr
323 can be represented on the host machine as an exact integer then
324 it is converted to \fBsprintf\fR("%d", \*(ex).
325 .B Sprintf()
326 is an AWK built-in that duplicates the functionality of
327 .IR sprintf (3),
328 and
329 .B CONVFMT
330 is a built-in variable used for internal conversion
331 from number to string and initialized to "%.6g".
332 Explicit type conversions can be forced,
333 \*(ex ""
334 is string and
335 .IR expr +0
336 is numeric.
337 .PP
338 To evaluate,
339 \*(ex\d1\u \fBrel-op \*(ex\d2\u,
340 if both operands are numeric or number and string then the comparison
341 is numeric; if both operands are string the comparison is string;
342 if one operand is string, the non-string operand is converted and
343 the comparison is string. The result is numeric, 1 or 0.
344 .PP
345 In boolean contexts such as,
346 \fBif\fR ( \*(ex ) \fIstatement\fR,
347 a string expression evaluates true if and only if it is not the
348 empty string "";
349 numeric values if and only if not numerically zero.
350 .\"
351 .SS "\fB3. Regular expressions"
352 In the AWK language, records, fields and strings are often
353 tested for matching a
354 .IR "regular expression" .
355 Regular expressions are enclosed in slashes, and
356 .nf
357 .sp
358 \*(ex ~ /\fIr\fR/
359 .sp
360 .fi
361 is an AWK expression that evaluates to 1 if \*(ex "matches"
362 .IR r ,
363 which means a substring of \*(ex is in the set of strings
364 defined by
365 .IR r .
366 With no match the expression evaluates to 0; replacing
367 ~ with the "not match" operator, !~ , reverses the meaning.
368 As pattern-action pairs,
369 .nf
370 .sp
371 /\fIr\fR/ { \fIaction\fR } and\
372 \fB$0\fR ~ /\fIr\fR/ { \fIaction\fR }
373 .sp
374 .fi
375 are the same,
376 and for each input record that matches
377 .IR r ,
378 .I action
379 is executed.
380 In fact, /\fIr\fR/ is an AWK expression that is
381 equivalent to (\fB$0\fR ~ /\fIr\fR/) anywhere except when on the
382 right side of a match operator or passed as an argument to
383 a built-in function that expects a regular expression
384 argument.
385 .PP
386 AWK uses extended regular expressions as with
387 .IR egrep (1).
388 The regular expression metacharacters, i.e., those with special
389 meaning in regular expressions are
390 .nf
391 .sp
392 \ ^ $ . [ ] | ( ) * + ?
393 .sp
394 .fi
395 Regular expressions are built up from characters as follows:
396 .RS
397 .TP \w'[^c\d1\uc\d2\uc\d3\u...]'u+1n
398 \fIc\fR
399 matches any non-metacharacter
400 .IR c .
401 .TP
402 \e\fIc\fR
403 matches a character defined by the same escape sequences used
404 in string constants or the literal
405 character
406 .I c
407 if
408 \e\fIc\fR
409 is not an escape sequence.
410 .TP
411 \&\.
412 matches any character (including newline).
413 .TP
414 ^
415 matches the front of a string.
416 .TP
417 $
418 matches the back of a string.
419 .TP
420 [c\d1\uc\d2\uc\d3\u...]
421 matches any character in the class
422 c\d1\uc\d2\uc\d3\u... . An interval of characters is denoted
423 c\d1\u\-c\d2\u inside a class [...].
424 .TP
425 [^c\d1\uc\d2\uc\d3\u...]
426 matches any character not in the class
427 c\d1\uc\d2\uc\d3\u...
428 .RE
429 .sp
430 Regular expressions are built up from other regular expressions
431 as follows:
432 .RS
433 .TP \w'[^c\d1\uc\d2\uc\d3\u...]'u+1n
434 \fIr\fR\d1\u\fIr\fR\d2\u
435 matches
436 \fIr\fR\d1\u
437 followed immediately by
438 \fIr\fR\d2\u
439 (concatenation).
440 .TP
441 \fIr\fR\d1\u | \fIr\fR\d2\u
442 matches
443 \fIr\fR\d1\u or
444 \fIr\fR\d2\u
445 (alternation).
446 .TP
447 \fIr\fR*
448 matches \fIr\fR repeated zero or more times.
449 .TP
450 \fIr\fR+
451 matches \fIr\fR repeated one or more times.
452 .TP
453 \fIr\fR?
454 matches \fIr\fR zero or once.
455 .TP
456 (\fIr\fR)
457 matches \fIr\fR, providing grouping.
458 .RE
459 .sp
460 The increasing precedence of operators is alternation,
461 concatenation and
462 unary (*, + or ?).
463 .PP
464 For example,
465 .nf
466 .sp
467 /^[_a\-zA-Z][_a\-zA\-Z0\-9]*$/ and
468 /^[\-+]?([0\-9]+\e\|.?|\e\|.[0\-9])[0\-9]*([eE][\-+]?[0\-9]+)?$/
469 .sp
470 .fi
471 are matched by AWK identifiers and AWK numeric constants
472 respectively. Note that . has to be escaped to be
473 recognized as a decimal point, and that metacharacters are not
474 special inside character classes.
475 .PP
476 Any expression can be used on the right hand side of the ~ or !~
477 operators or
478 passed to a built-in that expects
479 a regular expression.
480 If needed, it is converted to string, and then interpreted
481 as a regular expression. For example,
482 .nf
483 .sp
484 BEGIN { identifier = "[_a\-zA\-Z][_a\-zA\-Z0\-9]*" }
485
486 $0 ~ "^" identifier
487 .sp
488 .fi
489 prints all lines that start with an AWK identifier.
490 .PP
491 .B lmawk
492 recognizes the empty regular expression, //\|, which matches the
493 empty string and hence is matched by any string at the front,
494 back and between every character. For example,
495 .nf
496 .sp
497 echo abc | lmawk { gsub(//, "X") ; print }
498 XaXbXcX
499 .sp
500 .fi
501 .\"
502 .SS "\fB4. Records and fields"
503 Records are read in one at a time, and stored in the
504 .I field
505 variable
506 .BR $0 .
507 The record is split into
508 .I fields
509 which are stored in
510 .BR $1 ,
511 .BR $2 ", ...,"
512 .BR $NF .
513 The built-in variable
514 .B NF
515 is set to the number of fields,
516 and
517 .B NR
518 and
519 .B FNR
520 are incremented by 1.
521 Fields above
522 .B $NF
523 are set to "".
524 .PP
525 Assignment to
526 .B $0
527 causes the fields and
528 .B NF
529 to be recomputed.
530 Assignment to
531 .B NF
532 or to a field
533 causes
534 .B $0
535 to be reconstructed by
536 concatenating the
537 .B $i's
538 separated by
539 .BR OFS .
540 Assignment to a field with index greater than
541 .BR NF ,
542 increases
543 .B NF
544 and causes
545 .B $0
546 to be reconstructed.
547 .PP
548 Data input stored in fields
549 is string, unless the entire field has numeric
550 form and then the type is number and string.
551 For example,
552 .sp
553 .nf
554 echo 24 24E |
555 lmawk '{ print($1>100, $1>"100", $2>100, $2>"100") }'
556 0 1 1 1
557 .fi
558 .sp
559 .B $0
560 and
561 .B $2
562 are string and
563 .B $1
564 is number and string. The first comparison is numeric,
565 the second is string, the third is string
566 (100 is converted to "100"),
567 and the last is string.
568 .\"
569 .SS "\fB5. Expressions and operators"
570 .PP
571 The expression syntax is
572 similar to C. Primary expressions are numeric constants,
573 string constants, variables, fields, arrays and function calls.
574 The identifier
575 for a variable, array or function can be a sequence of
576 letters, digits and underscores, that does
577 not start with a digit.
578 Variables are not declared; they exist when first referenced and
579 are initialized to
580 .IR null .
581 .PP
582 New
583 expressions are composed with the following operators in
584 order of increasing precedence.
585 .PP
586 .RS
587 .nf
588 .vs +2p \" open up a little
589 \fIassignment\fR = += \-= *= /= %= ^=
590 \fIconditional\fR ? :
591 \fIlogical or\fR ||
592 \fIlogical and\fR &&
593 \fIarray membership\fR \fBin
594 \fImatching\fR ~ !~
595 \fIrelational\fR < > <= >= == !=
596 \fIconcatenation\fR (no explicit operator)
597 \fIadd ops\fR + \-
598 \fImul ops\fR * / %
599 \fIunary\fR + \-
600 \fIlogical not\fR !
601 \fIexponentiation\fR ^
602 \fIinc and dec\fR ++ \-\|\- (both post and pre)
603 \fIfield\fR $
604 .vs
605 .RE
606 .PP
607 .fi
608 Assignment, conditional and exponentiation associate right to
609 left; the other operators associate left to right. Any
610 expression can be parenthesized.
611 .\"
612 .SS "\fB6. Arrays"
613 .ds ae \fIarray\fR[\fIexpr\fR]
614 Awk provides one-dimensional arrays. Array elements are expressed
615 as \*(ae.
616 .I Expr
617 is internally converted to string type, so, for example,
618 A[1] and A["1"] are the same element and the actual
619 index is "1".
620 Arrays indexed by strings are called associative arrays.
621 Initially an array is empty; elements exist when first accessed.
622 An expression,
623 \fIexpr\fB in\fI array\fR
624 evaluates to 1 if
625 \*(ae
626 exists, else to 0.
627 .PP
628 There is a form of the
629 .B for
630 statement that loops over each index of an array.
631 .nf
632 .sp
633 \fBfor\fR ( \fIvar\fB in \fIarray \fR) \fIstatement\fR
634 .sp
635 .fi
636 sets
637 .I var
638 to each index of
639 .I array
640 and executes
641 .IR statement .
642 The order that
643 .I var
644 transverses the indices of
645 .I array
646 is not defined.
647 .PP
648 The statement,
649 .B delete
650 \*(ae,
651 causes
652 \*(ae
653 not to exist.
654 .B lmawk
655 supports an extension,
656 .B delete
657 .IR array ,
658 which deletes all elements of
659 .IR array .
660 .PP
661 Multidimensional arrays are synthesized with concatenation using
662 the built-in variable
663 .BR SUBSEP .
664 \fIarray\fR[\fIexpr\fR\d1\u,\|\fIexpr\fR\d2\u]
665 is equivalent to
666 \fIarray\fR[\fIexpr\fR\d1\u \fBSUBSEP \fIexpr\fR\d2\u].
667 Testing for a multidimensional element uses a parenthesized index,
668 such as
669 .sp
670 .nf
671 if ( (i, j) in A ) print A[i, j]
672 .fi
673 .sp
674 .\"
675 .SS "\fB7. Builtin-variables\fR"
676 .PP
677 The following variables are built-in and initialized before program
678 execution.
679 .RS
680 .TP \w'FILENAME'u+2n
681 .B ARGC
682 number of command line arguments.
683 .TP
684 .B ARGV
685 array of command line arguments, 0..ARGC-1.
686 .TP
687 .B CONVFMT
688 format for internal conversion of numbers to string,
689 initially = "%.6g".
690 .TP
691 .B ENVIRON
692 array indexed by environment variables. An environment string,
693 \fIvar=value\fR is stored as
694 \fBENVIRON\fR[\fIvar\fR] =
695 .IR value .
696 .TP
697 .B FILENAME
698 name of the current input file.
699 .TP
700 .B FNR
701 current record number in
702 .BR FILENAME .
703 .TP
704 .B FS
705 splits records into fields as a regular expression.
706 .TP
707 .B NF
708 number of fields in the current record.
709 .TP
710 .B NR
711 current record number in the total input stream.
712 .TP
713 .B OFMT
714 format for printing numbers; initially = "%.6g".
715 .TP
716 .B OFS
717 inserted between fields on output, initially = " ".
718 .TP
719 .B ORS
720 terminates each record on output, initially = "\en".
721 .TP
722 .B RLENGTH
723 length set by the last call to the built-in function,
724 .BR match() .
725 .TP
726 .B RS
727 input record separator, initially = "\en".
728 .TP
729 .B RSTART
730 index set by the last call to
731 .BR match() .
732 .TP
733 .B SUBSEP
734 used to build multiple array subscripts, initially = "\e034".
735 .TP
736 .B ERRNO
737 misc built-in functions (libmawk extensions) use this variable to
738 rerport error. All extension calls will set this variable before returning,
739 therefor ERRNO holds the result of the last call. An empty string value
740 means no error. Error messages are formatted in a way that the first word
741 is an unique integer, followed by a human readable error message from the
742 second word. int(ERRNO) can be used to acquire the error code, which then
743 can be used as a secondary output from the extension function. For example,
744 an awk program can use valueof() to determine if a global symbol exists and
745 is a function or a variable or anything else.
746 .TP
747 .B LIBPATH
748 is a semicolon separated list of search paths. When loading an awk script by file
749 name (-f command line argument or include from another awk script) these
750 paths are inserted before the file name, in order, one by one, until the first
751 path that allows opening the file. An empty path is equivalent to the current
752 working directory. LIBPATH can be modified from the command line using -v, as
753 arguments are scanned before loading the scripts. Setting LIBPATH to
754 empty string results in the original behaviour of mawk. LIBPATH is ignored
755 for script file names starting with slash ('/') as those are assumed to be
756 absolute paths.
757 .RE
758 .\"
759 .SS "\fB8. Built-in functions"
760 String functions
761 .RS
762 .TP
763 gsub(\fIr,s,t\fR) gsub(\fIr,s\fR)
764 Global substitution, every match of regular expression
765 .I r
766 in variable
767 .I t
768 is replaced by string
769 .IR s .
770 The number of replacements is returned.
771 If
772 .I t
773 is omitted,
774 .B $0
775 is used. An & in the replacement string
776 .I s
777 is replaced by the matched substring of
778 .IR t .
779 \e& and \e\e put literal & and \e, respectively,
780 in the replacement string.
781 .TP
782 index(\fIs,t\fR)
783 If
784 .I t
785 is a substring of
786 .IR s ,
787 then the position where
788 .I t
789 starts is returned, else 0 is returned.
790 The first character of
791 .I s
792 is in position 1.
793 .TP
794 length(\fIs\fR)
795 Returns the length of string
796 .IR s .
797 .TP
798 match(\fIs,r\fR)
799 Returns the index of the first longest match of regular expression
800 .I r
801 in string
802 .IR s .
803 Returns 0 if no match.
804 As a side effect,
805 .B RSTART
806 is set to the return value.
807 .B RLENGTH
808 is set to the length of the match or \-1 if no match. If the
809 empty string is matched,
810 .B RLENGTH
811 is set to 0, and 1 is returned if the match is at the front, and
812 length(\fIs\fR)+1 is returned if the match is at the back.
813 .TP
814 split(\fIs,A,r\fR) split(\fIs,A\fR)
815 String
816 .I s
817 is split into fields by regular expression
818 .I r
819 and the fields are loaded into array
820 .IR A .
821 The number of fields
822 is returned. See section 11 below for more detail.
823 If
824 .I r
825 is omitted,
826 .B FS
827 is used.
828 .TP
829 sprintf(\fIformat,expr-list\fR)
830 Returns a string constructed from
831 .I expr-list
832 according to
833 .IR format .
834 See the description of printf() below.
835 .TP
836 sub(\fIr,s,t\fR) sub(\fIr,s\fR)
837 Single substitution, same as gsub() except at most one substitution.
838 .TP
839 substr(\fIs,i,n\fR) substr(\fIs,i\fR)
840 Returns the substring of string
841 .IR s ,
842 starting at index
843 .IR i ,
844 of length
845 .IR n .
846 If
847 .I n
848 is omitted, the suffix of
849 .IR s ,
850 starting at
851 .I i
852 is returned.
853 .TP
854 tolower(\fIs\fR)
855 Returns a copy of
856 .I s
857 with all upper case characters converted to lower case.
858 .TP
859 toupper(\fIs\fR)
860 Returns a copy of
861 .I s
862 with all lower case characters converted to upper case.
863 .RE
864 .PP
865 Arithmetic functions
866 .RS
867 .PP
868 .nf
869 atan2(\fIy,x\fR) Arctan of \fIy\fR/\fIx\fR between -PI and PI.
870 .PP
871 cos(\fIx\fR) Cosine function, \fIx\fR in radians.
872 .PP
873 exp(\fIx\fR) Exponential function.
874 .PP
875 int(\fIx\fR) Returns \fIx\fR truncated towards zero.
876 .PP
877 log(\fIx\fR) Natural logarithm.
878 .PP
879 rand() Returns a random number between zero and one.
880 .PP
881 sin(\fIx\fR) Sine function, \fIx\fR in radians.
882 .PP
883 sqrt(\fIx\fR) Returns square root of \fIx\fR.
884 .fi
885 .TP
886 srand(\fIexpr\fR) srand()
887 Seeds the random number generator, using the clock if
888 .I expr
889 is omitted, and returns the value of the previous seed.
890 .B lmawk
891 seeds the random number generator from the clock at startup
892 so there is no real need to call srand(). Srand(\fIexpr\fR)
893 is useful for repeating pseudo random sequences.
894 .RE
895 .PP
896 Misc functions (libmawk extensions)
897 .RS
898 .PP
899 .TP
900 call(\fIfname,arg1,arg2,...\fR)
901 Call awk function \fIfname\fR with the supplied arguments. If the call fails,
902 empty value, else the return value of the callee is returned. Built-in variable
903 ERRNO is always set.
904 .TP
905 acall(\fIfname,arrname\fR)
906 Call awk function \fIfname\fR with arguments supplied in array named \fIarrname\fR
907 (both arguments are strings naming an existing object).
908 The array should be indexed from 1. Number of arguments is determined by
909 looking for the first empty (non-existing) index in the array. If the call fails,
910 empty value, else the return value of the callee is returned. Built-in variable
911 ERRNO is always set.
912 .TP
913 valueof(\fIvname [,idx]\fR)
914 Return the value of variable \fIfname\fR; if the variable is an array, return
915 the element indexed by \fIidx\fR (which must be present in this case). If index
916 is not present or is empty (""), the variable is expected to be scalar. Built-in variable
917 ERRNO is always set. NOTE: valueof() has access to the global symbol table only.
918 It will fail to resolve anything else than global objects; most notably it
919 will fail on local variables, $ arguments and on most of the built-in variables.
920 .RE
921 .\"
922 .SS "\fB9. Input and output"
923 There are two output statements,
924 .B print
925 and
926 .BR printf .
927 .RS
928 .TP
929 print
930 writes
931 .B "$0 ORS"
932 to standard output.
933 .TP
934 print \*(ex\d1\u, \*(ex\d2\u, ..., \*(ex\dn\u
935 writes
936 \*(ex\d1\u \fBOFS \*(ex\d2\u \fBOFS\fR ... \*(ex\dn\u
937 .B ORS
938 to standard output. Numeric expressions are converted to
939 string with
940 .BR OFMT .
941 .TP
942 printf \fIformat, expr-list\fR
943 duplicates the printf C library function writing to standard output.
944 The complete ANSI C format specifications are recognized with
945 conversions %c, %d, %e, %E, %f, %g, %G,
946 %i, %o, %s, %u, %x, %X and %%,
947 and conversion qualifiers h and l.
948 .RE
949 .PP
950 The argument list to print or printf can optionally be enclosed in
951 parentheses.
952 Print formats numbers using
953 .B OFMT
954 or "%d" for exact integers.
955 "%c" with a numeric argument prints the corresponding 8 bit
956 character, with a string argument it prints the first character of
957 the string.
958 The output of print and printf can be redirected to a file or
959 command by appending >
960 .IR file ,
961 >>
962 .I file
963 or
964 |
965 .I command
966 to the end of the print statement.
967 Redirection opens
968 .I file
969 or
970 .I command
971 only once, subsequent redirections append to the already open stream.
972 By convention,
973 .B lmawk
974 associates the filename "/dev/stderr" with stderr which allows
975 print and printf to be redirected to stderr.
976 .B lmawk
977 also associates "\-" and "/dev/stdout" with stdin and stdout which
978 allows these streams to be passed to functions.
979 Opening /dev/fd/N will do an fdopen() on file descriptor N, where
980 N is an integer - this is a libmawk extension. If any of the
981 /dev heuristics needs to be bypassed (i.e. the script wants to
982 open the real /dev/stdout or the real /dev/fd/5), the leading
983 slash should be doubled (e.g. //dev/fd/5).
984 .PP
985 The input function
986 .B getline
987 has the following variations.
988 .RS
989 .TP
990 getline
991 reads into
992 .BR $0 ,
993 updates the fields,
994 .BR NF ,
995 .B NR
996 and
997 .BR FNR .
998 .TP
999 getline < \fIfile\fR
1000 reads into
1001 .B $0
1002 from \fIfile\fR,
1003 updates the fields and
1004 .BR NF .
1005 .TP
1006 getline \fIvar
1007 reads the next record into
1008 .IR var ,
1009 updates
1010 .B NR
1011 and
1012 .BR FNR .
1013 .TP
1014 getline \fIvar\fR < \fIfile
1015 reads the next record of
1016 .I file
1017 into
1018 .IR var .
1019 .TP
1020 \fI command\fR | getline
1021 pipes a record from
1022 .I command
1023 into
1024 .B $0
1025 and updates the fields and
1026 .BR NF .
1027 .TP
1028 \fI command\fR | getline \fIvar
1029 pipes a record from
1030 .I command
1031 into
1032 .IR var .
1033 .RE
1034 .PP
1035 Getline returns 0 on end-of-file, \-1 on error, otherwise 1.
1036 .PP
1037 Commands on the end of pipes are executed by /bin/sh.
1038 .PP
1039 The function \fBclose\fR(\*(ex) closes the file or pipe
1040 associated with
1041 .IR expr .
1042 Close returns 0 if
1043 .I expr
1044 is an open file,
1045 the exit status if
1046 .I expr
1047 is a piped command, and \-1 otherwise.
1048 Close is used to reread a file or command, make sure the other
1049 end of an output pipe is finished or conserve file resources.
1050 .PP
1051 The function \fBfflush\fR(\*(ex) flushes the output file or pipe
1052 associated with
1053 .IR expr .
1054 Fflush returns 0 if
1055 .I expr
1056 is an open output stream else \-1.
1057 Fflush without an argument flushes stdout.
1058 Fflush with an empty argument ("") flushes all open output.
1059 .PP
1060 The function
1061 \fBsystem\fR(\fIexpr\fR)
1062 uses
1063 /bin/sh
1064 to execute
1065 .I expr
1066 and returns the exit status of the command
1067 .IR expr .
1068 Changes made to the
1069 .B ENVIRON
1070 array are not passed to commands executed with
1071 .B system
1072 or pipes.
1073 .SS \fB10. User defined functions
1074 The syntax for a user defined function is
1075 .nf
1076 .sp
1077 \fBfunction\fR name( \fIargs\fR ) { \fIstatements\fR }
1078 .sp
1079 .fi
1080 The function body can contain a return statement
1081 .nf
1082 .sp
1083 \fBreturn\fI opt_expr\fR
1084 .sp
1085 .fi
1086 A return statement is not required.
1087 Function calls may be nested or recursive.
1088 Functions are passed expressions by value
1089 and arrays by reference.
1090 Extra arguments serve as local variables
1091 and are initialized to
1092 .IR null .
1093 For example, csplit(\fIs,\|A\fR) puts each character of
1094 .I s
1095 into array
1096 .I A
1097 and returns the length of
1098 .IR s .
1099 .nf
1100 .sp
1101 function csplit(s, A, n, i)
1102 {
1103 n = length(s)
1104 for( i = 1 ; i <= n ; i++ ) A[i] = substr(s, i, 1)
1105 return n
1106 }
1107 .sp
1108 .fi
1109 Putting extra space between passed arguments and local
1110 variables is conventional.
1111 Functions can be referenced before they are defined, but the
1112 function name and the '(' of the arguments must touch to
1113 avoid confusion with concatenation.
1114 .\"
1115 .SS "\fB11. Splitting strings, records and files"
1116 Awk programs use the same algorithm to
1117 split strings into arrays with split(), and records into fields
1118 on
1119 .BR FS .
1120 .B lmawk
1121 uses essentially the same algorithm to split files into
1122 records on
1123 .BR RS .
1124 .PP
1125 Split(\fIexpr,\|A,\|sep\fR) works as follows:
1126 .RS
1127 .TP
1128 (1)
1129 If
1130 .I sep
1131 is omitted, it is replaced by
1132 .BR FS .
1133 .I Sep
1134 can be an expression or regular expression. If it is an
1135 expression of non-string type, it is converted to string.
1136 .TP
1137 (2)
1138 If
1139 .I sep
1140 = " " (a single space),
1141 then <SPACE> is trimmed from the front and back of
1142 .IR expr ,
1143 and
1144 .I sep
1145 becomes <SPACE>.
1146 .B lmawk
1147 defines <SPACE> as the regular expression
1148 /[\ \et\en]+/.
1149 Otherwise
1150 .I sep
1151 is treated as a regular expression, except that meta-characters
1152 are ignored for a string of length 1,
1153 e.g.,
1154 split(x, A, "*") and split(x, A, /\e*/) are the same.
1155 .TP
1156 (3)
1157 If \*(ex is not string, it is converted to string.
1158 If \*(ex is then the empty string "", split() returns 0
1159 and
1160 .I A
1161 is set empty.
1162 Otherwise,
1163 all non-overlapping, non-null and longest matches of
1164 .I sep
1165 in
1166 .IR expr ,
1167 separate
1168 .I expr
1169 into fields which are loaded into
1170 .IR A .
1171 The fields are placed in
1172 A[1], A[2], ..., A[n] and split() returns n, the number
1173 of fields which is the number
1174 of matches plus one.
1175 Data placed in
1176 .I A
1177 that looks numeric is typed number and string.
1178 .RE
1179 .PP
1180 Splitting records into fields works the same except the
1181 pieces are loaded into
1182 .BR $1 ,
1183 \fB$2\fR,...,
1184 .BR $NF .
1185 If
1186 .B $0
1187 is empty,
1188 .B NF
1189 is set to 0 and all
1190 .B $i
1191 to "".
1192 .PP
1193 .B lmawk
1194 splits files into records by the same algorithm, but with the
1195 slight difference that
1196 .B RS
1197 is really a terminator instead of a separator.
1198 (\fBORS\fR is really a terminator too).
1199 .RS
1200 .PP
1201 E.g., if
1202 .B FS
1203 = ":+" and
1204 .B $0
1205 = "a::b:" , then
1206 .B NF
1207 = 3 and
1208 .B $1
1209 = "a",
1210 .B $2
1211 = "b" and
1212 .B $3
1213 = "", but
1214 if "a::b:" is the contents of an input file and
1215 .B RS
1216 = ":+", then
1217 there are two records "a" and "b".
1218 .RE
1219 .PP
1220 .B RS
1221 = " " is not special.
1222 .PP
1223 If
1224 .B FS
1225 = "", then
1226 .B lmawk
1227 breaks the record into individual characters, and, similarly,
1228 split(\fIs,A,\fR"") places the individual characters of
1229 .I s
1230 into
1231 .IR A .
1232 .\"
1233 .SS "\fB12. Multi-line records"
1234 Since
1235 .B lmawk
1236 interprets
1237 .B RS
1238 as a regular expression, multi-line
1239 records are easy. Setting
1240 .B RS
1241 = "\en\en+", makes one or more blank
1242 lines separate records. If
1243 .B FS
1244 = " " (the default), then single
1245 newlines, by the rules for <SPACE> above, become space and
1246 single newlines are field separators.
1247 .RS
1248 .PP
1249 For example, if a file is "a\ b\enc\en\en",
1250 .B RS
1251 = "\en\en+" and
1252 .B FS
1253 = "\ ", then there is one record "a\ b\enc" with three
1254 fields "a", "b" and "c". Changing
1255 .B FS
1256 = "\en", gives two
1257 fields "a b" and "c"; changing
1258 .B FS
1259 = "", gives one field
1260 identical to the record.
1261 .RE
1262 .PP
1263 If you want lines with spaces or tabs to be considered blank,
1264 set
1265 .B RS
1266 = "\en([\ \et]*\en)+".
1267 For compatibility with other awks, setting
1268 .B RS
1269 = "" has the same
1270 effect as if blank lines are stripped from the
1271 front and back of files and then records are determined as if
1272 .B RS
1273 = "\en\en+".
1274 Posix requires that "\en" always separates records when
1275 .B RS
1276 = "" regardless of the value of
1277 .BR FS .
1278 .B lmawk
1279 does not support this convention, because defining
1280 "\en" as <SPACE> makes it unnecessary.
1281 .\"
1282 .PP
1283 Most of the time when you change
1284 .B RS
1285 for multi-line records, you
1286 will also want to change
1287 .B ORS
1288 to "\en\en" so the record spacing is preserved on output.
1289 .\"
1290 .SS "\fB13. Program execution"
1291 This section describes the order of program execution.
1292 First
1293 .B ARGC
1294 is set to the total number of command line arguments passed to
1295 the execution phase of the program.
1296 .B ARGV[0]
1297 is set the name of the AWK interpreter and
1298 \fBARGV[1]\fR ...
1299 .B ARGV[ARGC-1]
1300 holds the remaining command line arguments exclusive of
1301 options and program source.
1302 For example with
1303 .nf
1304 .sp
1305 lmawk \-f prog v=1 A t=hello B
1306 .sp
1307 .fi
1308 .B ARGC
1309 = 5 with
1310 .B ARGV[0]
1311 = "lmawk",
1312 .B ARGV[1]
1313 = "v=1",
1314 .B ARGV[2]
1315 = "A",
1316 .B ARGV[3]
1317 = "t=hello" and
1318 .B ARGV[4]
1319 = "B".
1320 .PP
1321 Next, each
1322 .B BEGIN
1323 block is executed in order.
1324 If the program consists
1325 entirely of
1326 .B BEGIN
1327 blocks, then execution terminates, else
1328 an input stream is opened and execution continues.
1329 If
1330 .B ARGC
1331 equals 1,
1332 the input stream is set to stdin,
1333 else the command line arguments
1334 .BR ARGV[1] " ...
1335 .B ARGV[ARGC-1]
1336 are examined for a file argument.
1337 .PP
1338 The command line arguments divide into three sets:
1339 file arguments, assignment arguments and empty strings "".
1340 An assignment has the form
1341 \fIvar\fR=\fIstring\fR.
1342 When an
1343 .B ARGV[i]
1344 is examined as a possible file argument,
1345 if it is empty it is skipped;
1346 if it is an assignment argument, the assignment to
1347 .I var
1348 takes place and
1349 .B i
1350 skips to the next argument;
1351 else
1352 .B ARGV[i]
1353 is opened for input.
1354 If it fails to open, execution terminates with exit code 2.
1355 If no command line argument is a file argument, then input
1356 comes from stdin.
1357 Getline in a
1358 .B BEGIN
1359 action opens input. "\-" as a file argument denotes stdin.
1360 .PP
1361 Once an input stream is open, each input record is tested
1362 against each
1363 .IR pattern ,
1364 and if it matches, the associated
1365 .I action
1366 is executed.
1367 An expression pattern matches if it is boolean true (see
1368 the end of section 2).
1369 A
1370 .B BEGIN
1371 pattern matches before any input has been read, and
1372 an
1373 .B END
1374 pattern matches after all input has been read.
1375 A range pattern,
1376 \fIexpr\fR1,\|\fIexpr\fR2 ,
1377 matches every record between the match of
1378 .IR expr 1
1379 and the match
1380 .IR expr 2
1381 inclusively.
1382 .PP
1383 When end of file occurs on the input stream, the remaining
1384 command line arguments are examined for a file argument, and
1385 if there is one it is opened, else the
1386 .B END
1387 .I pattern
1388 is considered matched
1389 and all
1390 .B END
1391 .I actions
1392 are executed.
1393 .PP
1394 In the example, the assignment
1395 v=1
1396 takes place after the
1397 .B BEGIN
1398 .I actions
1399 are executed, and
1400 the data placed in
1401 v
1402 is typed number and string.
1403 Input is then read from file A.
1404 On end of file A,
1405 t
1406 is set to the string "hello",
1407 and B is opened for input.
1408 On end of file B, the
1409 .B END
1410 .I actions
1411 are executed.
1412 .PP
1413 Program flow at the
1414 .I pattern
1415 .I {action}
1416 level can be changed with the
1417 .nf
1418 .sp
1419 \fBnext
1420 \fBexit \fIopt_expr\fR
1421 .sp
1422 .fi
1423 statements.
1424 A
1425 .B next
1426 statement
1427 causes the next input record to be read and pattern testing
1428 to restart with the first
1429 .I "pattern {action}"
1430 pair in the program.
1431 An
1432 .B exit
1433 statement
1434 causes immediate execution of the
1435 .B END
1436 actions or program termination if there are none or
1437 if the
1438 .B exit
1439 occurs in an
1440 .B END
1441 action.
1442 The
1443 .I opt_expr
1444 sets the exit value of the program unless overridden by
1445 a later
1446 .B exit
1447 or subsequent error.
1448
1449 .SS "\fB14. include"
1450
1451 .nf
1452 libmawk introduces source inclusion feature. Syntax is:
1453
1454 include "filename"
1455
1456 Include statements must be on top level (outside of blocks). If file name
1457 starts with a plus sign ('+'), the script file is not loaded if it has
1458 been already loaded (by another include or -f command line argument).
1459
1460
1461 .SH EXAMPLES
1462 .nf
1463 1. emulate cat.
1464
1465 { print }
1466
1467 2. emulate wc.
1468
1469 { chars += length($0) + 1 # add one for the \en
1470 words += NF
1471 }
1472
1473 END{ print NR, words, chars }
1474
1475 3. count the number of unique "real words".
1476
1477 BEGIN { FS = "[^A-Za-z]+" }
1478
1479 { for(i = 1 ; i <= NF ; i++) word[$i] = "" }
1480
1481 END { delete word[""]
1482 for ( i in word ) cnt++
1483 print cnt
1484 }
1485
1486 .fi
1487 4. sum the second field of
1488 every record based on the first field.
1489 .nf
1490
1491 $1 ~ /credit\||\|gain/ { sum += $2 }
1492 $1 ~ /debit\||\|loss/ { sum \-= $2 }
1493
1494 END { print sum }
1495
1496 5. sort a file, comparing as string
1497
1498 { line[NR] = $0 "" } # make sure of comparison type
1499 # in case some lines look numeric
1500
1501 END { isort(line, NR)
1502 for(i = 1 ; i <= NR ; i++) print line[i]
1503 }
1504
1505 #insertion sort of A[1..n]
1506 function isort( A, n, i, j, hold)
1507 {
1508 for( i = 2 ; i <= n ; i++)
1509 {
1510 hold = A[j = i]
1511 while ( A[j\-1] > hold )
1512 { j\-\|\- ; A[j+1] = A[j] }
1513 A[j] = hold
1514 }
1515 # sentinel A[0] = "" will be created if needed
1516 }
1517
1518 .fi
1519 .SH "COMPATIBILITY ISSUES"
1520 The Posix 1003.2(draft 11.3) definition of the AWK language
1521 is AWK as described in the AWK book with a few extensions
1522 that appeared in SystemVR4 nawk. The extensions are:
1523 .sp
1524 .RS
1525 New functions: toupper() and tolower(); libmawk extensions: call(), acall(), valueof().
1526
1527 New variables: ENVIRON[\|] and CONVFMT; libmawk extension: ERRNO, LIBPATH.
1528 As a libmawk extension, ENVIRON affects the environment of children processes.
1529
1530 As a libmawk extension, new built-in variable LIBPATH is used as a list
1531 of search paths while loading scripts from the command line or from include.
1532
1533 If a script name starts with plus ('+'), the file is not loaded if it has
1534 been loaded earlier (to avoid double loading libs trough -f and/or include).
1535 This is a libmawk extension.
1536
1537 It is possible to include a script from another script using keyword
1538 include "scriptname.awk" (libmawk extension).
1539
1540 ANSI C conversion specifications for printf() and sprintf().
1541
1542 New command options: \-v var=value, multiple -f options and
1543 implementation options as arguments to \-W.
1544 .RE
1545 .sp
1546
1547 Posix AWK is oriented to operate on files a line at
1548 a time.
1549 .B RS
1550 can be changed from "\en" to another single character,
1551 but it
1552 is hard to find any use for this \(em there are no
1553 examples in the AWK book.
1554 By convention, \fBRS\fR = "", makes one or more blank lines
1555 separate records, allowing multi-line records. When
1556 \fBRS\fR = "", "\en" is always a field separator
1557 regardless of the value in
1558 .BR FS .
1559 .PP
1560 .BR lmawk ,
1561 on the other hand,
1562 allows
1563 .B RS
1564 to be a regular expression.
1565 When "\en" appears in records, it is treated as space, and
1566 .B FS
1567 always determines fields.
1568 .PP
1569 Removing the line at a time paradigm can make some programs
1570 simpler and can
1571 often improve performance. For example,
1572 redoing example 3 from above,
1573 .nf
1574 .sp
1575 BEGIN { RS = "[^A-Za-z]+" }
1576
1577 { word[ $0 ] = "" }
1578
1579 END { delete word[ "" ]
1580 for( i in word ) cnt++
1581 print cnt
1582 }
1583 .sp
1584 .fi
1585 counts the number of unique words by making each word a record.
1586 On moderate size files,
1587 .B lmawk
1588 executes twice as fast, because of the simplified inner loop.
1589 .PP
1590 The following program replaces each comment by a single space in
1591 a C program file,
1592 .nf
1593 .sp
1594 BEGIN {
1595 RS = "/\|\e*([^*]\||\|\e*+[^/*])*\e*+/"
1596 # comment is record separator
1597 ORS = " "
1598 getline hold
1599 }
1600
1601 { print hold ; hold = $0 }
1602
1603 END { printf "%s" , hold }
1604 .sp
1605 .fi
1606 Buffering one record is needed to avoid terminating the last
1607 record with a space.
1608 .PP
1609 With
1610 .BR lmawk ,
1611 the following are all equivalent,
1612 .nf
1613 .sp
1614 x ~ /a\e+b/ x ~ "a\e+b" x ~ "a\e\e+b"
1615 .sp
1616 .fi
1617 The strings get scanned twice, once as string and once as
1618 regular expression. On the string scan,
1619 .B lmawk
1620 ignores the escape on non-escape characters while the AWK
1621 book advocates
1622 .I \ec
1623 be recognized as
1624 .I c
1625 which necessitates the double escaping of meta-characters in
1626 strings.
1627 Posix explicitly declines to define the behavior which passively
1628 forces programs that must run under a variety of awks to use
1629 the more portable but less readable, double escape.
1630 .PP
1631 Posix AWK does not recognize "/dev/std{out,err}" or \ex hex escape
1632 sequences in strings. Unlike ANSI C,
1633 .B lmawk
1634 limits the number of digits that follows \ex to two as the current
1635 implementation only supports 8 bit characters.
1636 The built-in
1637 .B fflush
1638 first appeared in a recent (1993) AT&T awk released to netlib, and is
1639 not part of the posix standard. Aggregate deletion with
1640 .B delete
1641 .I array
1642 is not part of the posix standard.
1643 .PP
1644 Posix explicitly leaves the behavior of
1645 .B FS
1646 = "" undefined, and mentions splitting the record into characters as
1647 a possible interpretation, but currently this use is not portable
1648 across implementations.
1649 .PP
1650 Finally, here is how
1651 .B lmawk
1652 handles exceptional cases not discussed in the
1653 AWK book or the Posix draft. It is unsafe to assume
1654 consistency across awks and safe to skip to
1655 the next section.
1656 .PP
1657 .RS
1658 substr(s, i, n) returns the characters of s in the intersection
1659 of the closed interval [1, length(s)] and the half-open interval
1660 [i, i+n). When this intersection is empty, the empty string is
1661 returned; so substr("ABC", 1, 0) = "" and
1662 substr("ABC", \-4, 6) = "A".
1663 .PP
1664 Every string, including the empty string, matches the empty string
1665 at the
1666 front so, s ~ // and s ~ "", are always 1 as is match(s, //) and
1667 match(s, ""). The last two set
1668 .B RLENGTH
1669 to 0.
1670 .PP
1671 index(s, t) is always the same as match(s, t1) where t1 is the
1672 same as t with metacharacters escaped. Hence consistency
1673 with match requires that
1674 index(s, "") always returns 1.
1675 Also the condition, index(s,t) != 0 if and only t is a substring
1676 of s, requires index("","") = 1.
1677 .PP
1678 If getline encounters end of file, getline var, leaves var
1679 unchanged. Similarly, on entry to the
1680 .B END
1681 actions,
1682 .BR $0 ,
1683 the fields and
1684 .B NF
1685 have their value unaltered from the last record.
1686 .SH SEE ALSO
1687 .IR egrep (1),
1688 .IR mawk (1)
1689 .PP
1690 Aho, Kernighan and Weinberger,
1691 .IR "The AWK Programming Language" ,
1692 Addison-Wesley Publishing, 1988, (the AWK book),
1693 defines the language, opening with a tutorial
1694 and advancing to many interesting programs that delve into
1695 issues of software design and analysis relevant to programming
1696 in any language.
1697 .PP
1698 .IR "The GAWK Manual" ,
1699 The Free Software Foundation, 1991, is a tutorial
1700 and language reference
1701 that does not attempt the depth of the AWK book
1702 and assumes the reader may be a novice programmer.
1703 The section on AWK arrays is excellent. It also
1704 discusses Posix requirements for AWK.
1705 .SH BUGS
1706 .B lmawk
1707 cannot handle ascii NUL \e0 in the source or data files. You
1708 can output NUL using printf with %c, and any other 8 bit
1709 character is acceptable input.
1710 .PP
1711 .B lmawk
1712 implements printf() and sprintf() using the C library functions,
1713 printf and sprintf, so full ANSI compatibility requires an ANSI
1714 C library. In practice this means the h conversion qualifier may
1715 not be available. Also
1716 .B lmawk
1717 inherits any bugs or limitations of the library functions.
1718 .PP
1719 Implementors of the AWK language have shown a consistent lack
1720 of imagination when naming their programs.
1721 .SH AUTHOR
1722 .PP
1723 .B mawk:
1724 Mike Brennan (brennan@whidbey.com).
1725 .PP
1726 .B libmawk extensions:
1727 Tibor Palinkas (libmawk@igor2.repo.hu).
0 /********************************************
1 libmawk (C) 2009-2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9
10 #include <math.h>
11 #include <errno.h>
12 #include "math_wrap.h"
13
14 int PM_errno;
15
16 double P_log_(double x, int *perrno)
17 {
18 double ret;
19 #ifdef P_MBROKEN_LOG_M_0
20 if (x == -0.0) {
21 *perrno = -1;
22 return 0;
23 }
24 #endif
25
26 #ifdef P_MBROKEN_LOG_P_0
27 if (x == +0.0) {
28 *perrno = -1;
29 return 0;
30 }
31 #endif
32
33 #ifdef P_MBROKEN_LOG_P_1
34 if (x == +1.0) {
35 *perrno = -1;
36 return 0;
37 }
38 #endif
39
40 /* we don't have portable NaN, scconfig doesn't yet detect FP_NAN, we
41 have to emulate one by hand */
42 if (x < 0) {
43 *perrno = -123;
44 return 0;
45 }
46 ret = log(x);
47 if (errno != 0)
48 *perrno = errno;
49 return ret;
50 }
51
52
53 double P_divf_(double x, double y, int *perrno)
54 {
55 if (y == 0) {
56 *perrno = -123;
57 return 0;
58 }
59 return x/y;
60 }
0 /* fallback for the case when the P_ math funcitons are used outside of
1 PM_ macros; not thread safe, should be avoided
2
3 Options:
4
5 1. single thread
6 a. use PM_BEGIN/PM_ERROR/PM_END
7 b. use P_log() and manually check PM_errno after the call
8 2. multithread
9 a. use PM_BEGIN/PM_ERROR/PM_END
10 b. use P_log_() with local variable errno, manually check it after the call
11
12 Doesn't protect against 1/0 - use P_divf() for secure division.
13 */
14
15 #ifndef MAWK_MATH_WRAP
16 #define MAWK_MATH_WRAP
17
18 #include "num.h"
19
20 extern int PM_errno;
21
22 #define P_EFPE -1234
23
24 #define PM_BEGIN \
25 { \
26 int PM_errno = 0; \
27
28 #define PM_ERROR \
29 ; \
30 if (PM_errno != 0)
31
32 #define PM_END \
33 ;\
34 } \
35
36 #define PM_ENDERR(errhandling) \
37 ; \
38 if (PM_errno != 0) { errhandling ; } \
39 }
40
41
42 double P_log_(double x, int *perrno);
43
44 #define P_log(x) P_log_(x, &PM_errno)
45 #define P_divf(x, y) P_divf_(x, y, &PM_errno)
46
47 #ifdef MAWK_NO_FLOAT
48 /* integer variant - no nan */
49 #define P_nansafe1(dest, operation, operand) \
50 (dest) = (operation); \
51
52 #else
53 #ifdef MAWK_HAVE_SAFE_NAN
54 /* proper NAN support - don't do extra checks */
55 # define P_nansafe1(dest, operation, operand) \
56 (dest) = (operation); \
57
58 # define P_isnan_manual(x) 0
59
60 #else
61 /* broken or missing NAN support, always have to check manually */
62 # define P_nansafe1(dest, operation, operand) \
63 do { \
64 if (P_isnan(operand) || P_isnan(dest)) (dest) = P_nan(); \
65 else (dest) = (operation); \
66 } while(0)
67 # define P_isnan_manual P_isnan
68 #endif
69
70
71 #endif
72
73 /* forced check - for both cases */
74 #define P_nansafe_exp1(exp, operand) (P_isnan(operand) ? P_nan() : (exp))
75
76 #endif
0
1 /********************************************
2 mawk_matherr.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include "mawk.h"
16 #include "num.h"
17
18 struct exception {
19 int dummy;
20 };
21
22 /* Sets up NetBSD 1.0A for ieee floating point */
23 #if defined(_LIB_VERSION_TYPE) && defined(_LIB_VERSION) && defined(_IEEE_)
24 _LIB_VERSION_TYPE _LIB_VERSION = _IEEE_;
25 #endif
26
27 #ifdef USE_IEEEFP_H
28 #include <ieeefp.h>
29 #endif
30
31 #ifndef TURN_OFF_FPE_TRAPS
32 #define TURN_OFF_FPE_TRAPS() /* nothing */
33 #endif
34
35 #ifndef TURN_ON_FPE_TRAPS
36 #define TURN_ON_FPE_TRAPS() /* nothing */
37 #endif
38
39 #ifdef SV_SIGINFO
40 #include <siginfo.h>
41 #define FPE_ZERODIVIDE FPE_FLTDIV
42 #define FPE_OVERFLOW FPE_FLTOVF
43 #endif
44
45 #ifdef FPE_TRAPS_ON
46 #include <signal.h>
47
48 /* machine dependent changes might be needed here */
49
50 #ifdef SV_SIGINFO
51 static void fpe_catch(int signal, siginfo_t *sip)
52 {
53 int why = sip->si_code;
54
55 #else
56
57 static void fpe_catch(int signal, int why)
58 {
59 #endif /* SV_SIGINFO */
60
61 #if NOINFO_SIGFPE
62 mawk_rt_error("floating point exception, probably mawk_overflow");
63 /* does not return */
64 #else
65
66 switch (why) {
67 case FPE_ZERODIVIDE:
68 mawk_rt_error("division by zero");
69
70 case FPE_OVERFLOW:
71 mawk_rt_error("floating point mawk_overflow");
72
73 default:
74 mawk_rt_error("floating point exception");
75 }
76 #endif /* noinfo_sigfpe */
77 }
78
79 void mawk_fpe_init(void)
80 {
81 return;
82 TURN_ON_FPE_TRAPS();
83
84 #ifndef SV_SIGINFO
85 signal(SIGFPE, fpe_catch);
86
87 #else
88 {
89 struct sigaction x;
90
91 memset(&x, 0, sizeof(x));
92 x.sa_handler = fpe_catch;
93 x.sa_flags = SA_SIGINFO;
94
95 sigaction(SIGFPE, &x, (struct sigaction *) 0);
96 }
97 #endif
98
99 #ifdef HAVE_STRTOD_OVF_BUG
100 /* we've already turned the traps on */
101 working_mask = fpgetmask();
102 MAWK->entry_mask = working_mask & ~FP_X_DZ & ~FP_X_OFL;
103 #endif
104 }
105
106 #else /* FPE_TRAPS not defined */
107
108 void mawk_fpe_init(void)
109 {
110 return;
111 TURN_OFF_FPE_TRAPS();
112 }
113 #endif
114
115 #ifndef NO_MATHERR
116
117 #ifndef FPE_TRAPS_ON
118
119 /* If we are not trapping math errors, we will shutup the library calls
120 */
121
122 int mawk_matherr(struct exception *e)
123 {
124 return 1;
125 }
126
127 #else /* print error message and exit */
128
129 int mawk_matherr(struct exception *e)
130 {
131 char *error;
132
133 switch (e->type) {
134 case DOMAIN:
135 case SING:
136 error = "domain error";
137 break;
138
139 case OVERFLOW:
140 error = "mawk_overflow";
141 break;
142
143 case TLOSS:
144 case PLOSS:
145 error = "loss of significance";
146 break;
147
148 case UNDERFLOW:
149 e->retval = MAWK_NUM_ZERO;
150 return 1; /* ignore it */
151 }
152
153 if (strcmp(e->name, "atan2") == 0)
154 mawk_rt_error("atan2(%g,%g) : %s", e->arg1, e->arg2, error);
155 else
156 mawk_rt_error("%s(%g) : %s", e->name, e->arg1, error);
157
158 /* won't get here */
159 return 0;
160 }
161 #endif /* FPE_TRAPS_ON */
162
163 #endif /* ! no mawk_matherr */
164
165
166 /* this is how one gets the libm calls to do the right
167 thing on bsd43_vax */
168
169 #ifdef BSD43_VAX
170
171 #include <errno.h>
172
173 double infnan(int arg)
174 {
175 switch (arg) {
176 case ERANGE:
177 errno = ERANGE;
178 return HUGE;
179 case -ERANGE:
180 errno = EDOM;
181 return -HUGE;
182 default:
183 errno = EDOM;
184 }
185 return MAWK_NUM_ZERO;
186 }
187
188 #endif /* BSD43_VAX */
189
190 /* This routine is for XENIX-68K 2.3A.
191 Error check routine to be called after fp arithmetic.
192 */
193
194 #if SW_FP_CHECK
195 /* Definitions of bit values in iserr() return value */
196
197 #define OVFLOW 2
198 #define UFLOW 4
199 #define ZERODIV 8
200 #define OVFLFIX 32
201 #define INFNAN 64
202
203 void fpcheck(void)
204 {
205 register int fperrval;
206 char *errdesc;
207
208 if ((fperrval = iserr()) == 0)
209 return; /* no error */
210
211 errdesc = (char *) 0;
212
213 if (fperrval & INFNAN)
214 errdesc = "arg is infinity or NAN";
215 else if (fperrval & ZERODIV)
216 errdesc = "division by zero";
217 else if (fperrval & OVFLOW)
218 errdesc = "mawk_overflow";
219 else if (fperrval & UFLOW); /* ignored */
220
221 if (errdesc)
222 mawk_rt_error("%s", errdesc);
223 }
224
225 #endif
226
227 #ifdef HAVE_STRTOD_OVF_BUG
228 /* buggy strtod in solaris, probably any sysv with ieee754
229 strtod can generate an fpe */
230
231 double strtod_with_ovf_bug(const char *s, char **ep)
232 {
233 double ret;
234
235 fpsetmask(MAWK->entry_mask); /* traps off */
236 #undef strtod /* make real strtod visible */
237 ret = strtod(s, ep);
238 fpsetmask(working_mask); /* traps on */
239 return ret;
240 }
241 #endif
0
1 /********************************************
2 mawk.h
3
4 libmawk changes (C) 2009-2012, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991-94, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef MAWK_H
17 #define MAWK_H
18
19 #include <libmawk/conf.h>
20 #include <stdlib.h>
21 #include <libmawk/nstd.h>
22
23 typedef struct mawk_vio_s mawk_vio_t;
24
25
26 typedef enum mawk_errno_e {
27 MAWK_ESUCCES = 0,
28 MAWK_ECANTOPEN = -1,
29 MAWK_EHDRSIZE = -2,
30 MAWK_EFILEMAGIC = -3,
31 MAWK_EBYTEORDER = -4,
32 MAWK_EVERSION = -5,
33 MAWK_EINSTSIZE = -6,
34 MAWK_ENUMSIZE = -7,
35 MAWK_EALLOC = -8,
36 MAWK_EWRONGVAL = -9,
37
38 MAWK_Elast = -9
39 } mawk_errno_t;
40 const char *mawk_strerror(mawk_errno_t err);
41
42 typedef struct mawk_state_s mawk_state_t;
43 typedef struct fcall FCALL_REC;
44
45 #include <libmawk/types.h>
46 #include <libmawk/bi_vars.h>
47 #include <libmawk/vio.h>
48
49 #define NUM_PFIELDS 5
50
51 #define SPRINTF_SZ sizeof(MAWK->tempbuff)
52
53 typedef struct pfile {
54 struct pfile *link;
55 const char *fname;
56 char bytecode; /* 1 if file is expected to be bytecode */
57 } PFILE;
58
59 typedef struct mawk_fin_s mawk_input_t;
60
61 typedef struct array *mawk_array_t;
62
63 /* array implementation callbacks; default implementation is in array_orig.c */
64
65 /* look up index mawk_cell_t in mawk_array_t and return 1 if it exists. If result is non-NULL,
66 it is first destroyed (regardless of whether the index exists in the array)
67 and if the index exists, its value is copied into result. The caller has to
68 destroy result after the call. Modifications to result will not affect the array.
69 NOTE: idx may be the same pointer as result: it's guaranteed that result is
70 destroyed after indexing.
71
72 If create is 1, a non-existing member is created with empty value
73 */
74 typedef int mawk_array_find_t(mawk_state_t *MAWK, mawk_array_t arr, const mawk_cell_t *idx, mawk_cell_t *result, int create);
75
76 /* set a member of the mawk_array_t at idx to val */
77 typedef void mawk_array_set_t(mawk_state_t *MAWK, mawk_array_t arr, const mawk_cell_t *idx, mawk_cell_t *val);
78
79 /* delete a single index (mawk_cell_t) from the array; called by "delete A[i]" */
80 typedef void mawk_array_delete_t(mawk_state_t *MAWK, mawk_array_t arr, const mawk_cell_t *idx);
81
82 /* free all elements of the array and clean the array; the array should
83 be a valid empty array after the operation */
84 typedef void mawk_array_clear_t(mawk_state_t *MAWK, mawk_array_t arr);
85
86 /* list and return all indices in a string array; used by "for(a in ARR)"
87 must return a pointer alloced by mawk_malloc() or NULL if the array is empty */
88 typedef mawk_string_t **mawk_array_loop_vector_t(mawk_state_t *MAWK, mawk_array_t arr, unsigned *vsize);
89
90 /* load the array from MAWK->split_ov_list (called exclusively from split()) */
91 typedef void mawk_array_load_t(mawk_state_t *MAWK, mawk_array_t arr, int cnt);
92
93 /* optional call for _generic: iteration; no change is done to the array during
94 the iteration, except for deleting the last returned element in clear() */
95 /* start iterating over all members, returns iterator */
96 typedef void *mawk_array_it_start_t(mawk_state_t *MAWK, mawk_array_t arr);
97 /* get index of the next member; returns NULL at the end */
98 typedef const mawk_cell_t *mawk_array_it_next_t(mawk_state_t *MAWK, mawk_array_t arr, void *iterator);
99 /* called after the last element or if the iteration is to be stopped */
100 typedef void mawk_array_it_stop_t(mawk_state_t *MAWK, mawk_array_t arr, void *iterator);
101
102
103 /* a whole implementation conists of all of the above: */
104 typedef struct array_imp_s {
105 /* any array implementation has to provide these: */
106 mawk_array_find_t *find;
107 mawk_array_set_t *set;
108 mawk_array_delete_t *delet;
109 /* option A: manual implementation of these: */
110 mawk_array_clear_t *clear;
111 mawk_array_loop_vector_t *loop_vect;
112 mawk_array_load_t *load;
113 /* option B: use array_generic and provide an iterator: */
114 mawk_array_it_start_t *it_start;
115 mawk_array_it_next_t *it_next;
116 mawk_array_it_stop_t *it_stop;
117 } array_imp_t;
118
119 /* an actual array */
120 struct array {
121 array_imp_t imp; /* implementation */
122 PTR ptr; /* What this points to depends on the type and implementation */
123 unsigned size; /* number of elts in the table */
124 unsigned limit; /* Meaning depends on type and implementation */
125 unsigned hmask; /* bitwise and with hash value to get table index */
126 short type; /* values in AY_NULL .. AY_SPLIT */
127
128 union { /* state for custom (non-orig) impelementations; 0;NULL by default */
129 int i;
130 void *p;
131 } state;
132 };
133
134 typedef struct {
135 INST *base, *limit, *warn, *ptr;
136 } CODEBLOCK;
137
138 /*------------------------
139 user defined functions
140 ------------------------*/
141
142 typedef struct fblock FBLOCK;
143
144 struct fblock {
145 const char *name;
146 INST *code;
147 unsigned size; /* allocated size for proper cleanup with zfree() */
148 unsigned short nargs;
149 char *typev; /* array of size nargs holding types */
150
151 FBLOCK *c_next; /* linked list of all c function call blocks compiled into the code so they can be free'd at the end; see also: MAWK->c_calls */
152 }; /* function block */
153
154 typedef struct jmp {
155 struct jmp *link;
156 int source_offset;
157 } JMP;
158
159 typedef struct bc {
160 struct bc *link; /* stack as linked list */
161 int type; /* 'B' or 'C' or mark start with 0 */
162 int source_offset; /* position of _JMP */
163 } BC;
164
165 /* a stack to hold some pieces of code while
166 reorganizing loops .
167 */
168
169 typedef struct mc { /* mc -- move code */
170 struct mc *link;
171 INST *code; /* the save code */
172 unsigned len; /* its length */
173 int scope; /* its scope */
174 int move_level; /* size of this stack when coded */
175 FBLOCK *fbp; /* if scope FUNCT */
176 int offset; /* distance from its code base */
177 } MC;
178
179 struct child {
180 int pid;
181 int exit_status;
182 struct child *link;
183 };
184
185 #define SAFETY 16
186 #define DANGER (EVAL_STACK_SIZE-SAFETY)
187
188 #define ET_END 9
189 typedef struct {
190 char in, out;
191 } mawk_escape_t;
192
193 struct mawk_fdump {
194 struct mawk_fdump *link;
195 FBLOCK *fbp;
196 };
197
198 /* We store dynamically created files on a linked linear
199 list with move to the front (big surprise) */
200
201 typedef struct file_node_s {
202 struct file_node_s *link;
203 mawk_string_t *name;
204 short type;
205
206 /* direct file IO for output or direct input */
207 mawk_vio_t *vf;
208
209 /* .. or buffered (FIN) */
210 mawk_input_t *fin;
211 } FILE_NODE;
212
213 typedef struct {
214 char type;
215 char c;
216 PTR ptr; /* mawk_string_t* or RE machine* */
217 } SEPARATOR;
218
219 /* struct to hold info about builtins */
220 typedef struct {
221 char *name;
222 PF_CP fp; /* ptr to function that does the builtin */
223 unsigned char min_args, max_args;
224 /* info for parser to check correct number of arguments */
225 } BI_REC;
226
227 typedef struct {
228 const char *name;
229 char type;
230 unsigned char offset; /* offset in stack frame for local vars */
231 union {
232 mawk_cell_t *cp;
233 int kw;
234 PF_CP fp;
235 const BI_REC *bip;
236 mawk_array_t array;
237 FBLOCK *fbp;
238 struct {
239 mawk_cell_t *(*callback) (mawk_state_t * context, mawk_cell_t * sp, int a_args);
240 void *func_userdata;
241 } c_function;
242 } stval;
243 } SYMTAB;
244
245 typedef struct hash {
246 struct hash *link;
247 SYMTAB symtab;
248 } HASHNODE;
249
250 #define POOLSZ 16
251 #define ZBLOCKSZ 8
252 #define ZSHIFT 3
253 typedef union zblock {
254 char dummy[ZBLOCKSZ];
255 union zblock *link;
256 } ZBLOCK;
257
258 /* ZBLOCKS of sizes 1, 2, ... 16
259 which is bytes of sizes 8, 16, ... , 128
260 are stored on the linked linear lists in
261 pool[0], pool[1], ... , pool[15]
262 */
263
264 typedef struct re_node {
265 mawk_string_t *sval;
266 PTR re;
267 struct re_node *link;
268 } RE_NODE;
269
270 typedef struct repl_node {
271 struct repl_node *link;
272 mawk_string_t *sval; /* the input */
273 mawk_cell_t *cp; /* the output */
274 } REPL_NODE;
275
276 typedef struct spov {
277 struct spov *link;
278 mawk_string_t *sval;
279 } SPLIT_OV;
280
281 /* ---------------------------------------------------------------------- */
282
283 typedef struct mawk_debug_callstack_s mawk_debug_callstack_t;
284
285 struct mawk_debug_callstack_s {
286 FBLOCK *f;
287 mawk_debug_callstack_t *next;
288 };
289
290 typedef struct mawk_parse_state_s {
291 const char *pfile_name; /* program input file */
292 char pfile_bytecode; /* 1 if program input file is expected to be bytecode */
293 int code_move_level; /* used as part of unique identification of context when moving code. Global for communication with parser. */
294 mawk_string_t *program_string;
295 unsigned char *buffer;
296 unsigned char *buffp;
297 /* unsigned so it works with 8 bit chars */
298 FILE_NODE *program_fin;
299 int eof_flag;
300 } mawk_parse_state_t;
301
302
303 typedef struct mawk_mm_s mawk_mm_t;
304
305 struct mawk_mm_s {
306 mawk_mm_t *prev, *next;
307 int size;
308 char data[1]; /* actual data */
309 } ;
310
311
312 /* regex lib */
313 typedef unsigned char mawk_BV[32]; /* bit vector */
314
315 typedef struct {
316 char type;
317 unsigned char len; /* used for M_STR */
318 union {
319 char *str; /* string */
320 mawk_BV *bvp; /* class */
321 int jump;
322 } data;
323 } mawk_RESTATE;
324
325 /* function callback type: this how execute() can call external C functions */
326 typedef mawk_cell_t *libmawk_c_function(mawk_state_t *context, mawk_cell_t * sp, int a_args);
327
328 /* struct for the run time stack */
329 typedef struct {
330 mawk_RESTATE *m; /* save the machine ptr */
331 int u; /* save the u_flag */
332 char *s; /* save the active string ptr */
333 char *ss; /* save the match start -- only used by mawk_REmatch */
334 } mawk_RT_STATE; /* run time state */
335
336 struct mawk_state_s {
337
338 #ifdef DEBUG
339 #define YYDEBUG 1
340 int yydebug; /* print parse if on */
341 int dump_RE;
342 #endif
343
344 short posix_space_flag, interactive_flag;
345
346 /* a well known string */
347 mawk_string_t null_str;
348
349 /* a useful scratch area */
350 union {
351 mawk_string_t *_split_buff[MAX_SPLIT];
352 char _string_buff[MIN_SPRINTF];
353 } tempbuff;
354
355
356 /* help with casts */
357 unsigned long *mpow2;
358
359 mawk_cell_t field[FBANK_SZ + NUM_PFIELDS];
360 /* $0, $1 ... $(MAX_SPLIT), NF, RS, RS, CONVFMT, OFMT */
361
362 /* more fields if needed go here */
363 mawk_cell_t *fbank[NUM_FBANK]; /* fbank[0] == field */
364
365
366 /* these are used by the parser, scanner and error messages
367 from the compile */
368
369 PFILE *pfile_list, *pfile_list_tail;
370
371 int current_token;
372 unsigned token_lineno; /* lineno of current token */
373 unsigned compile_error_count;
374 int paren_cnt, brace_cnt;
375 int print_flag, getline_flag;
376 short mawk_state;
377 char *progname; /* for error messages */
378 unsigned rt_nr, rt_fnr; /* ditto */
379
380 /* this can be moved and enlarged by -W sprintf=num */
381 char *sprintf_buff;
382 char *sprintf_limit;
383
384 FILE_NODE *main_input;
385 mawk_array_t Argv; /* to the user this is ARGV */
386 mawk_num_t argi; /* index of next ARGV[argi] to try to open */
387 unsigned lineno;
388 int NR_flag; /* are we tracking NR */
389
390 CODEBLOCK active_code;
391 CODEBLOCK *main_code_p, *begin_code_p, *end_code_p;
392 INST *begin_start, *main_start, *end_start, *end_start_orig;
393 unsigned begin_size, main_size, end_size;
394 INST *execution_start;
395
396 int dump_code_flag; /* if on dump internal code */
397 int dump_sym_flag; /* if on dump internal symbols */
398
399 INST *restart_label; /* control flow labels */
400 INST *next_label;
401 mawk_cell_t tc; /*useful temp */
402 int scope;
403 FBLOCK *active_funct; /* when scope is SCOPE_FUNCT */
404 JMP *jmp_top;
405 BC *bc_top;
406 MC *mc_top;
407
408 mawk_parse_state_t ps; /* current parse state */
409 mawk_array_t scripts_loaded; /* a hash indeced by full paths of scripts already loaded */
410 mawk_parse_state_t *mawk_parser_stack; /* parse state stack for "include" */
411 int pstack_alloced, pstack_used;
412
413 int check_progress; /* flag that indicates call_arg_check() was able to type check some call arguments */
414 struct child *child_list; /* dead children are kept on this list */
415 unsigned repl_cnt; /* number of global replacements */
416 long seed; /* must be >=1 and < 2^31-1 */
417 mawk_cell_t cseed; /* argument of last call to srand() */
418 mawk_cell_t eval_stack[EVAL_STACK_SIZE];
419 mawk_cell_t *sp;
420 mawk_cell_t *stack_base; /* these can move for deep recursion */
421 mawk_cell_t *stack_danger;
422 int exit_code, final_exit_code, rt_exit_code;
423 # ifdef HAVE_STRTOD_OVF_BUG
424 fp_except entry_mask;
425 fp_except working_mask;
426 # endif
427 mawk_escape_t escape_test[ET_END + 1];
428 struct mawk_fdump *fdump_list; /* linked list of all user functions */
429 FILE_NODE *file_list;
430 char *shell; /* hardwire to /bin/sh for portability of programs */
431
432 int max_field; /* maximum field actually created */
433 /* a description of how to split based on RS.
434 If RS is changed, so is rs_shadow */
435 SEPARATOR rs_shadow;
436 /* a splitting mawk_cell_t version of FS */
437 mawk_cell_t fs_shadow;
438 int nf; /* nf holds the true value of NF. If nf < 0 , then NF has not been computed, i.e., $0 has not been split */
439 HASHNODE *hash_table[HASH_PRIME];
440 HASHNODE *save_list; /* when processing user functions, global ids which are replaced by local ids are saved on this list */
441 unsigned last_hash;
442
443 /* large block allocator (memory accounting and free-later mechanism) */
444 mawk_mm_t *mawk_mm_head;
445 int mm_used, mm_max;
446
447 /* small block allocator in zmalloc.[ch] (pooling) */
448 ZBLOCK *pool[POOLSZ]; /* pool of blocks already free'd, indexed by size (in blocks) */
449 unsigned amt_avail; /* how many blocks are unclaimed at the end of ->avail */
450 ZBLOCK *avail; /* the chunk we split up for new allocations */
451
452 RE_NODE *re_list; /* a list of compiled regular expressions */
453 REPL_NODE *repl_list; /* here's our old friend linked linear list with move to the front for compilation of replacement CELLs */
454 char scan_code[256];
455 SPLIT_OV *split_ov_list;
456
457 libmawk_c_function *func_being_called; /* the C function that's being called back from execute() */
458
459 void *func_userdata; /* during calls to C functions, func_userdata has the value that it had during registration of that function (it's saved and restored) */
460 void *ctx_userdata; /* set by the user, never touched by libmawk */
461
462 int last_token_lineno; /* last token line number to detect source line change for adding debug info */
463 mawk_debug_callstack_t *debug_callstack;
464
465 FCALL_REC *resolve_list;
466 void *lvalp;
467 mawk_cell_t code_call_id_dummy;
468
469 mawk_cell_t bi_vars[NUM_BI_VAR];
470
471
472 /* regex lib state */
473 int REerrno;
474 mawk_RT_STATE *RE_run_stack_base;
475 mawk_RT_STATE *RE_run_stack_limit;
476 mawk_RT_STATE *RE_run_stack_empty; /* Large model DOS segment arithemetic breaks the current stack. This hack fixes it without rewriting the whole thing, 5/31/91 */
477 mawk_BV **REbv_base, **REbv_limit;
478 mawk_BV **REbv_next; /* next empty slot in the array */
479 int REbv_alloced;
480 int REprev;
481 unsigned RElen;
482 char *RElp; /* ptr to reg exp string */
483
484 unsigned long runlimit; /* how many instructions to run before returning; 0 means "unlimited" (2^32) */
485
486 /* should be a bitfield! */
487 int debug_symbols; /* add location infoand other debug symbol data to the code */
488 int separate_begin; /* if not zero, after running BEGIN blocks, no main block is automaticly executed */
489 int suppress_undefined_function_warning; /* if not zero, do not warn about functions undefined */
490 int no_program_ok; /* it is ok if there's no program after processing argv[] */
491
492 int do_exit; /* non-zero if we should exit immediately (added for exiting from the parser) */
493 int wants_to_exit; /* non-zero if a script decied to exit but libmawk didn't really stop it (doesn't happen in main.c but happens with libmawk.c) */
494 int binary_loaded; /* non-zero if no text parsing is required (binary file has been loaded) */
495
496 /* hooks */
497 const char *(*file_name_rewrite)(const char *orig_name, char *buff, int buff_size, int type); /* called any time the script wants to open a new file (print redirection or getline); return orig_name or buff after filling in a new file name there or another string const (won't be freed); return NULL to deny opening the file */
498 mawk_vio_init_t vio_init;
499
500 FILE_NODE *fnode_stdin, *fnode_stdout, *fnode_stderr;
501 FBLOCK *c_funcs; /* list of c function calls - to be free'd on uninit */
502 };
503
504 #define EXECUTION 1 /* other state is 0 compiling */
505
506 /* anonymous union */
507 #define string_buff MAWK->tempbuff._string_buff
508 #define split_buff MAWK->tempbuff._split_buff
509
510
511 /* prototypes */
512
513 void mawk_cast1_to_str(mawk_state_t *, mawk_cell_t *);
514 void mawk_cast1_to_num(mawk_state_t *, mawk_cell_t *);
515 void mawk_cast2_to_str(mawk_state_t *, mawk_cell_t *);
516 void mawk_cast2_to_num(mawk_state_t *, mawk_cell_t *);
517 void mawk_cast_to_RE(mawk_state_t *, mawk_cell_t *);
518 void mawk_cast_for_split(mawk_state_t *, mawk_cell_t *);
519 void mawk_check_strnum(mawk_state_t *, mawk_cell_t *);
520 void mawk_cast_to_REPL(mawk_state_t *, mawk_cell_t *);
521
522 #define d_to_i(d) ((int)mawk_d_to_I(d))
523
524
525 int test(mawk_state_t *, mawk_cell_t *); /* test for null non-null */
526 mawk_cell_t *repl_cpy(mawk_cell_t *, mawk_cell_t *);
527 void DB_cell_destroy(mawk_state_t *, mawk_cell_t *);
528 void overflow(mawk_state_t *, char *, unsigned);
529 void mawk_rt_overflow(mawk_state_t * MAWK, char *, unsigned);
530 void mawk_rt_error(mawk_state_t *, const char *, ...);
531 void mawk_set_errno(mawk_state_t * MAWK, const char *error);
532
533
534 void mawk_exit_(mawk_state_t *, int);
535 #define mawk_exitval(MAWK, x, RETVAL) \
536 do { \
537 mawk_exit_(MAWK, x); \
538 return RETVAL; \
539 } while(0);
540
541 #define mawk_exit(MAWK, x) \
542 do { \
543 mawk_exit_(MAWK, x); \
544 return; \
545 } while(0);
546
547 void mawk_da(mawk_state_t *, INST *, void *);
548 char *mawk_str_str(char *, char *, unsigned);
549 char *mawk_rm_escape(mawk_state_t *, char *);
550 char *mawk_re_pos_match(mawk_state_t *, char *, PTR, unsigned *);
551 int mawk_binmode(void);
552
553
554 void mawk_bozo(mawk_state_t *, char *);
555 void mawk_errmsg(mawk_state_t *, int, char *, ...);
556 void mawk_compile_error(mawk_state_t *, const char *, ...);
557
558 void mawk_execute(mawk_state_t *, INST *, mawk_cell_t *, mawk_cell_t *);
559 const char *mawk_find_kw_str(int);
560
561 void mawk_overflow(mawk_state_t * MAWK, char *s, unsigned size);
562 void mawk_bi_vars_init(mawk_state_t * MAWK);
563 void mawk_bi_funct_init(mawk_state_t * MAWK);
564 #ifdef MAKW_MEM_PEDANTIC
565 void mawk_bi_funct_uninit(mawk_state_t *MAWK)
566 #endif
567 void mawk_code_init(mawk_state_t *MAWK);
568 void mawk_parse(mawk_state_t *);
569
570 #ifndef MAWK_NO_FLOAT
571 # ifdef HAVE_STRTOD_OVF_BUG
572 double strtod_with_ovf_bug(const char *, char **);
573 # define strtod strtod_with_ovf_bug
574 # endif
575 #endif
576
577 #endif /* MAWK_H */
0
1 /********************************************
2 memory.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, 1992 Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include "mawk.h"
17 #include "memory.h"
18
19 static mawk_string_t *xnew_STRING(mawk_state_t *, unsigned);
20
21
22 static mawk_string_t *xnew_STRING(mawk_state_t *MAWK, unsigned len)
23 {
24 mawk_string_t *sval = (mawk_string_t *) mawk_zmalloc(MAWK, len + STRING_OH);
25
26 sval->len = len;
27 sval->ref_cnt = 1;
28 return sval;
29 }
30
31 /* allocate space for a mawk_string_t */
32
33 mawk_string_t *mawk_new_STRING0(mawk_state_t *MAWK, unsigned len)
34 {
35 if (len == 0) {
36 MAWK->null_str.ref_cnt++;
37 return &MAWK->null_str;
38 }
39 else {
40 mawk_string_t *sval = xnew_STRING(MAWK, len);
41 sval->str[len] = 0;
42 return sval;
43 }
44 }
45
46 /* convert char* to mawk_string_t* */
47
48 mawk_string_t *mawk_new_STRING(mawk_state_t *MAWK, const char *s)
49 {
50 if (s[0] == 0) {
51 MAWK->null_str.ref_cnt++;
52 return &MAWK->null_str;
53 }
54 else {
55 mawk_string_t *sval = xnew_STRING(MAWK, strlen(s));
56 strcpy(sval->str, s);
57 return sval;
58 }
59 }
60
61
62 #ifdef DEBUG
63
64 void DB_free_STRING(mawk_state_t *MAWK, register mawk_string_t *sval)
65 {
66 if (--sval->ref_cnt == 0)
67 mawk_zfree(MAWK, sval, sval->len + STRING_OH);
68 }
69
70 #endif
71
72
73 /**************************************************************************
74 large block allocation: collect all allocation in a double linked list in
75 MAWK so they can be easily free'd without any leak at the end of script
76 execution. Also do memory accounting and don't allocate over preset limit.
77 ***************************************************************************/
78
79 #define OVERHEAD ((char *)&(r->data) - (char *)(r))
80 static void *mawk_mm_link(mawk_state_t *MAWK, mawk_mm_t *r)
81 {
82 r->next = MAWK->mawk_mm_head;
83 r->prev = NULL;
84 if (r->next != NULL)
85 r->next->prev = r;
86 MAWK->mawk_mm_head = r;
87 return &r->data;
88 }
89
90 static void mawk_mm_unlink(mawk_state_t *MAWK, mawk_mm_t *r)
91 {
92 if (r->prev != NULL)
93 r->prev->next = r->next;
94 else
95 MAWK->mawk_mm_head = r->next;
96 if (r->next != NULL)
97 r->next->prev = r->prev;
98 }
99
100 /* store a pointer in the mawk_mm_head list */
101 void *mawk_malloc(mawk_state_t *MAWK, int size)
102 {
103 mawk_mm_t *r;
104
105 if ((MAWK->mm_max > 0) && (MAWK->mm_used + size > MAWK->mm_max))
106 return NULL;
107
108 r = malloc(OVERHEAD + size);
109 r->size = OVERHEAD + size;
110 MAWK->mm_used += r->size;
111 return mawk_mm_link(MAWK, r);
112 }
113
114 void *mawk_realloc(mawk_state_t *MAWK, void *ptr, int size)
115 {
116 mawk_mm_t *r;
117
118 /* emulate mawk_malloc() for simpler implementation of growing buff */
119 if (ptr == NULL)
120 return mawk_malloc(MAWK, size);
121
122 r = (mawk_mm_t *)((char *)ptr - OVERHEAD);
123
124 mawk_mm_unlink(MAWK, r);
125
126 if ((MAWK->mm_max > 0) && (MAWK->mm_used - r->size + size > MAWK->mm_max))
127 return NULL;
128
129 MAWK->mm_used -= r->size;
130 r = realloc(r, OVERHEAD + size);
131 if (r == NULL)
132 return NULL;
133 r->size = OVERHEAD + size;
134 MAWK->mm_used += r->size;
135 return mawk_mm_link(MAWK, r);
136 }
137
138 void mawk_free(mawk_state_t *MAWK, void *ptr)
139 {
140 mawk_mm_t *r = (mawk_mm_t *)((char *)ptr - OVERHEAD);
141 mawk_mm_unlink(MAWK, r);
142 MAWK->mm_used -= r->size;
143 free(r);
144 }
145
146 void mawk_free_all(mawk_state_t *MAWK)
147 {
148 mawk_mm_t *r, *n;
149 for(r = MAWK->mawk_mm_head; r != NULL; r = n) {
150 n = r->next;
151 free(r);
152 }
153 MAWK->mawk_mm_head = NULL;
154 MAWK->mm_used = 0;
155 }
156
157 char *mawk_strdup(mawk_state_t *MAWK, const char *s)
158 {
159 int l;
160 char *r;
161
162 if (s == NULL)
163 return NULL;
164
165 l = strlen(s);
166 r = mawk_malloc(MAWK, l+1);
167 memcpy(r, s, l+1);
168 return r;
169 }
170
171 char *mawk_strdup_(const char *s)
172 {
173 int l;
174 char *r;
175
176 if (s == NULL)
177 return NULL;
178
179 l = strlen(s);
180 r = malloc(l+1);
181 memcpy(r, s, l+1);
182 return r;
183 }
184
0
1 /********************************************
2 memory.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef MEMORY_H
17 #define MEMORY_H
18
19 #include <libmawk/zmalloc.h>
20
21
22 mawk_string_t *mawk_new_STRING(mawk_state_t *, const char *);
23 mawk_string_t *mawk_new_STRING0(mawk_state_t *, unsigned);
24
25 #ifdef DEBUG
26 void DB_free_STRING(mawk_state_t *, mawk_string_t *);
27
28 #define free_STRING(s) DB_free_STRING(MAWK, s)
29
30 #else
31
32 #define free_STRING(sval) if ( -- (sval)->ref_cnt == 0 )\
33 mawk_zfree(MAWK, sval, (sval)->len+STRING_OH) ; else
34 #endif
35
36 #ifdef DEBUG
37 void DB_mawk_eval_overflow(mawk_state_t * MAWK);
38
39 #define inc_sp() if( ++sp == MAWK->eval_stack+EVAL_STACK_SIZE )\
40 DB_mawk_eval_overflow(MAWK)
41 #define inc_mawksp() if( ++(MAWK->sp) == MAWK->eval_stack+EVAL_STACK_SIZE )\
42 DB_mawk_eval_overflow(MAWK)
43 #else
44
45 /* If things are working, the eval stack should not mawk_overflow */
46
47 #define inc_sp() sp++
48 #define inc_mawksp() (MAWK->sp)++
49 #endif
50
51
52 /* large block allocation */
53 void *mawk_malloc(mawk_state_t *MAWK, int size);
54 void *mawk_realloc(mawk_state_t *MAWK, void *ptr, int size);
55 void mawk_free(mawk_state_t *MAWK, void *ptr);
56 void mawk_free_all(mawk_state_t *MAWK);
57 char *mawk_strdup(mawk_state_t *MAWK, const char *s);
58
59 /* plain malloc() wrappers */
60 char *mawk_strdup_(const char *s);
61
62
63 #endif /* MEMORY_H */
0
1 /* missing.c */
2
3 #include "nstd.h"
4
5 #ifdef NO_STRCHR
6 char *strchr(char *s, int c)
7 {
8 if (c == 0)
9 return s + strlen(s);
10
11 while (*s) {
12 if (*s == c)
13 return s;
14 s++;
15 }
16 return (char *) 0;
17 }
18
19 char *strrchr(char *s, int c)
20 {
21 char *ret = (char *) 0;
22
23 if (c == 0)
24 return s + strlen(s);
25
26 while (*s) {
27 if (*s == c)
28 ret = s;
29 s++;
30 }
31 return ret;
32 }
33 #endif /* NO_STRCHR */
34
35 #ifdef NO_STRERROR
36 extern int sys_nerr;
37 extern char *sys_errlist[];
38 char *strerror(int n)
39 {
40 return n > 0 & n < sys_nerr ? sys_errlist[n] : "";
41 }
42 #endif
43
44
45 #ifdef NO_MEMCPY
46 PTR memcpy(PTR t, PTR s, size_t n)
47 {
48 char *tt = t;
49 char *ss = s;
50
51 while (n > 0) {
52 n--;
53 *tt++ = *ss++;
54 }
55 return t;
56 }
57
58 int memcmp(PTR t, PTR s, size_t n)
59 {
60 char *tt = t;
61 char *ss = s;
62
63 while (n > 0) {
64 if (*tt < *ss)
65 return -1;
66 if (*tt > *ss)
67 return 1;
68 tt++;
69 ss++;
70 n--;
71 }
72 return 0;
73 }
74
75 PTR memset(PTR t, int c, size_t n)
76 {
77 char *tt = (char *) t;
78
79 while (n > 0) {
80 n--;
81 *tt++ = c;
82 }
83 return t;
84 }
85 #endif /* NO_MEMCPY */
86
87 #ifndef MAWK_NO_FLOAT
88 #ifdef NO_STRTOD
89
90 /* don't use this unless you really don't have strtod() because
91 (1) its probably slower than your real strtod()
92 (2) atof() may call the real strtod()
93 */
94
95 double strtod(const char *s, char **endptr)
96 {
97 register unsigned char *p;
98 int flag;
99 double atof();
100
101 if (endptr) {
102 p = (unsigned char *) s;
103
104 flag = 0;
105 while (*p == ' ' || *p == '\t')
106 p++;
107 if (*p == '-' || *p == '+')
108 p++;
109 while (scan_code[*p] == SC_DIGIT) {
110 flag++;
111 p++;
112 }
113 if (*p == '.') {
114 p++;
115 while (scan_code[*p] == SC_DIGIT) {
116 flag++;
117 p++;
118 }
119 }
120 /* done with number part */
121 if (flag == 0) { /* no number part */
122 *endptr = s;
123 return MAWK_NUM_ZERO;
124 }
125 else
126 *endptr = (char *) p;
127
128 /* now look for exponent */
129 if (*p == 'e' || *p == 'E') {
130 flag = 0;
131 p++;
132 if (*p == '-' || *p == '+')
133 p++;
134 while (scan_code[*p] == SC_DIGIT) {
135 flag++;
136 p++;
137 }
138 if (flag)
139 *endptr = (char *) p;
140 }
141 }
142 return atof(s);
143 }
144 #endif /* no strtod() */
145
146 #endif /* MAWK_NO_FLOAT */
0 /* Never Standard.h
1
2 This has all the prototypes that are supposed to
3 be in a standard place but never are, and when they are
4 the standard place isn't standard
5 */
6
7 #ifndef NSTD_H
8 #define NSTD_H 1
9
10
11 /* types */
12 typedef void *PTR;
13
14 #include "conf.h"
15
16 /* stdlib.h */
17 #ifndef MAWK_NO_FLOAT
18 double strtod(const char *, char **);
19 #endif
20
21 #ifdef MAWK_BROKEN_STDLIB
22 void free(void *);
23 PTR malloc(size_t);
24 PTR realloc(void *, size_t);
25 void exit(int);
26 #endif
27
28 char *getenv(const char *);
29
30 /* string.h */
31
32 int memcmp(const void *, const void *, size_t);
33 PTR memcpy(void *, const void *, size_t);
34 PTR memset(void *, int, size_t);
35 char *strcpy(char *, const char *);
36 size_t strlen(const char *);
37 char *strerror(int);
38
39
40 #ifdef NO_ERRNO_H
41 extern int errno;
42 #else
43 #include <errno.h>
44 #endif
45
46 /* math.h */
47 /* if have to diddle with errno to get errors from the math library */
48 #ifndef STDC_MATHERR
49 #define STDC_MATHERR (FPE_TRAPS_ON && NO_MATHERR)
50 #endif
51
52 #endif /* NSTD_H */
0 #ifndef NUM_H
1 #define NUM_H
2
3 #include "conf.h"
4 #include "sizes.h"
5
6 typedef enum { /* fixed numbers are important because of the file format */
7 MAWK_NUM_ID_DOUBLE = 'd',
8 MAWK_NUM_ID_INT = 'i'
9 } mawk_num_id_t;
10
11 extern const mawk_num_id_t mawk_num_id;
12
13 #ifdef MAWK_NO_FLOAT
14 # include <libmawk/num_int.h>
15 #else
16 # include <math.h>
17 # include <libmawk/num_double.h>
18 #endif
19
20 Int mawk_d_to_I(mawk_num_t);
21 const char *mawk_num_print_spec(mawk_num_t d);
22
23
24 #endif /* NUM_H */
0 /********************************************
1 libmawk (C) 2009-2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9
10 #include "mawk.h"
11 #include "num.h"
12 #include "math_wrap.h"
13
14 const mawk_num_id_t mawk_num_id = MAWK_NUM_ID_DOUBLE;
15
16 /* convert a number to Int (this is not as simple as a
17 mawk_cast because the results are undefined if it won't fit).
18 Truncate large values to +Max_Int or -Max_Int
19 Send nans to -Max_Int
20 */
21
22 Int mawk_d_to_I(mawk_num_t d)
23 {
24 if (d >= Max_Int)
25 return Max_Int;
26 if (d > -Max_Int)
27 return (Int) d;
28 return -Max_Int;
29 }
30
31 const char *mawk_num_print_spec(mawk_num_t d)
32 {
33 if (P_isnan(d))
34 return "nan";
35 return NULL;
36 }
37
38 double P_fmod(double x, double y)
39 {
40 double modf();
41 double ipart;
42
43 if (y == 0)
44 return P_nan();
45 PM_BEGIN
46 modf(x / y, &ipart);
47 PM_ERROR
48 return P_nan();
49 PM_END
50 return x - ipart * y;
51 }
52
53 double mawk_num_pow(double x, double y)
54 {
55 double r;
56
57 if (P_isnan(x) || P_isnan(y))
58 return P_nan();
59 if ((x < 0.0) && (y != (double)((int)(y+0.5))))
60 return P_nan();
61 PM_BEGIN
62 r = pow(x, y);
63 PM_ERROR
64 return P_nan();
65 PM_END
66 return r;
67 }
0 /* number type */
1 typedef double mawk_num_t;
2
3 /* constant format differ for floating point and int */
4 #define MAWK_NUM_ZERO 0.0
5 #define MAWK_NUM_ONE 1.0
6
7 /* default printf format */
8 #define NUM_FMT "%g"
9
10 /* format for the disassembler */
11 #define NUM_FMT_DA "%.6g"
12
13 #define mawk_num_sqrt sqrt
14 #define mawk_num_int(d) ((d) >= MAWK_NUM_ZERO ? floor(d) : ceil(d))
15
16 #ifdef MAWK_HAVE_SAFE_NAN
17 #define P_isnan(x) isnan(x)
18 #define P_nan() nan("nan")
19 #else
20 #define NUM_NAN HUGE_VAL
21 #define P_isnan(x) ((x) == NUM_NAN)
22 #define P_nan() (NUM_NAN)
23 #endif
24
25 double mawk_num_pow(double x, double y);
26 double P_fmod(double x, double y);
27
28 #define strtonum(nptr, endptr) strtod(nptr, endptr)
29
0 /********************************************
1 libmawk (C) 2009-2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9
10 #include "mawk.h"
11 #include "num.h"
12
13 const mawk_num_id_t mawk_num_id = MAWK_NUM_ID_INT;
14
15 /* convert a number to Int; Int is int */
16
17 Int mawk_d_to_I(mawk_num_t d)
18 {
19 return (Int) d;
20 }
21
22 const char *mawk_num_print_spec(mawk_num_t d)
23 {
24 if (P_isnan(d))
25 return "nan";
26 return NULL;
27 }
28
29 /* slow implementstion */
30 mawk_num_t mawk_num_pow(mawk_num_t x, mawk_num_t y)
31 {
32 mawk_num_t a = 1;
33
34 for(; y > 0; y--)
35 a = a * x;
36 return a;
37 }
38
39
40 #define abs_macro(x) ((x) < 0 ? -(x) : (x))
41
42 mawk_num_t mawk_num_sqrt(mawk_num_t x)
43 {
44 mawk_num_t old_guess, guess;
45 if (P_isnan(x) || (x == 0))
46 return x;
47 if (x < 0)
48 return P_nan();
49
50 /* Babylonian method */
51 guess = 1;
52 old_guess = -1;
53 while(abs_macro(old_guess - guess) > 1) {
54 old_guess = guess;
55 guess = (guess + x/guess) / 2;
56 }
57 return guess;
58 }
0 /* number type */
1 typedef int mawk_num_t;
2
3 /* constant format differ for floating point and int */
4 #define MAWK_NUM_ZERO 0
5 #define MAWK_NUM_ONE 1
6 #define NUM_NAN 0x80000000
7
8 /* default printf format */
9 #define NUM_FMT "%d"
10
11 /* format for the disassembler */
12 #define NUM_FMT_DA "%d"
13
14 mawk_num_t mawk_num_pow(mawk_num_t x, mawk_num_t y);
15 mawk_num_t mawk_num_sqrt(mawk_num_t x);
16 #define mawk_num_int(d) (d)
17
18 #define P_isnan(x) ((x) == NUM_NAN)
19 #define P_nan(x) (NUM_NAN)
20
21 #define P_isnan_manual(x) P_isnan(x)
22
23 #define strtonum(nptr, endptr) strtol(nptr, endptr, 10)
24
0 /* A Bison parser, made by GNU Bison 3.0.2. */
1
2 /* Bison implementation for Yacc-like parsers in C
3
4 Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 /* As a special exception, you may create a larger work that contains
20 part or all of the Bison parser skeleton and distribute that work
21 under terms of your choice, so long as that work isn't itself a
22 parser generator using the skeleton or a modified version thereof
23 as a parser skeleton. Alternatively, if you modify or redistribute
24 the parser skeleton itself, you may (at your option) remove this
25 special exception, which will cause the skeleton and the resulting
26 Bison output files to be licensed under the GNU General Public
27 License without this special exception.
28
29 This special exception was added by the Free Software Foundation in
30 version 2.2 of Bison. */
31
32 /* C LALR(1) parser skeleton written by Richard Stallman, by
33 simplifying the original so-called "semantic" parser. */
34
35 /* All symbols defined below should begin with yy or YY, to avoid
36 infringing on user name space. This should be done even for local
37 variables, as they might otherwise be expanded by user macros.
38 There are some unavoidable exceptions within include files to
39 define necessary library symbols; they are noted "INFRINGES ON
40 USER NAME SPACE" below. */
41
42 /* Identify Bison output. */
43 #define YYBISON 1
44
45 /* Bison version. */
46 #define YYBISON_VERSION "3.0.2"
47
48 /* Skeleton name. */
49 #define YYSKELETON_NAME "yacc.c"
50
51 /* Pure parsers. */
52 #define YYPURE 1
53
54 /* Push parsers. */
55 #define YYPUSH 0
56
57 /* Pull parsers. */
58 #define YYPULL 1
59
60
61 /* Substitute the variable and function names. */
62 #define yyparse Mawk_parse
63 #define yylex Mawk_lex
64 #define yyerror Mawk_error
65 #define yydebug Mawk_debug
66 #define yynerrs Mawk_nerrs
67
68
69 /* Copy the first part of user declarations. */
70 #line 86 "parse.y" /* yacc.c:339 */
71
72 #include <stdio.h>
73 #include "mawk.h"
74 #include "types.h"
75 #include "symtype.h"
76 #include "code.h"
77 #include "memory.h"
78 #include "bi_funct.h"
79 #include "bi_vars.h"
80 #include "jmp.h"
81 #include "field.h"
82 #include "files.h"
83 #include "scan.h"
84 #include "zmalloc.h"
85 #include "f2d.h"
86
87
88 #define YYMAXDEPTH 200
89
90 void mawk_eat_nl(mawk_state_t * MAWK, YYSTYPE *lvalp);
91 static void resize_fblock(mawk_state_t *, FBLOCK *);
92 static void switch_code_to_main(mawk_state_t *);
93 static void mawk_code_array(mawk_state_t *, SYMTAB *);
94 static void mawk_code_call_id(mawk_state_t *, CA_REC *, SYMTAB *);
95 static void field_A2I(mawk_state_t *MAWK);
96 static void check_var(mawk_state_t *, SYMTAB *);
97 static void check_array(mawk_state_t *, SYMTAB *);
98 static void RE_as_arg(mawk_state_t *MAWK);
99
100 void mawk_parser_include(mawk_state_t *MAWK, void *str);
101
102 #define mawk_code_address(x) \
103 do { \
104 if (is_local(x)) \
105 mawk_code2op(MAWK, L_PUSHA, (x)->offset) ;\
106 else \
107 code2(MAWK, _PUSHA, (x)->stval.cp); \
108 } while(0)
109
110 #define CDP(x) (mawk_code_base+(x))
111 /* WARNING: These CDP() calculations become invalid after calls
112 that might change code_base. Which are: code2(), mawk_code2op(),
113 code_jmp() and code_pop().
114 */
115
116 /* this nonsense caters to MSDOS large model */
117 #define CODE_FE_PUSHA() mawk_code_ptr->ptr = (PTR) 0 ; code1(FE_PUSHA)
118
119
120 #line 122 "y.tab.c" /* yacc.c:339 */
121
122 # ifndef YY_NULLPTR
123 # if defined __cplusplus && 201103L <= __cplusplus
124 # define YY_NULLPTR nullptr
125 # else
126 # define YY_NULLPTR 0
127 # endif
128 # endif
129
130 /* Enabling verbose error messages. */
131 #ifdef YYERROR_VERBOSE
132 # undef YYERROR_VERBOSE
133 # define YYERROR_VERBOSE 1
134 #else
135 # define YYERROR_VERBOSE 0
136 #endif
137
138 /* In a future release of Bison, this section will be replaced
139 by #include "y.tab.h". */
140 #ifndef YY_MAWK_Y_TAB_H_INCLUDED
141 # define YY_MAWK_Y_TAB_H_INCLUDED
142 /* Debug traces. */
143 #ifndef YYDEBUG
144 # define YYDEBUG 0
145 #endif
146 #if YYDEBUG
147 extern int Mawk_debug;
148 #endif
149
150 /* Token type. */
151 #ifndef YYTOKENTYPE
152 # define YYTOKENTYPE
153 enum yytokentype
154 {
155 UNEXPECTED = 258,
156 BAD_DECIMAL = 259,
157 NL = 260,
158 SEMI_COLON = 261,
159 LBRACE = 262,
160 RBRACE = 263,
161 LBOX = 264,
162 RBOX = 265,
163 COMMA = 266,
164 IO_OUT = 267,
165 ASSIGN = 268,
166 ADD_ASG = 269,
167 SUB_ASG = 270,
168 MUL_ASG = 271,
169 DIV_ASG = 272,
170 MOD_ASG = 273,
171 POW_ASG = 274,
172 QMARK = 275,
173 COLON = 276,
174 OR = 277,
175 AND = 278,
176 IN = 279,
177 MATCH = 280,
178 EQ = 281,
179 NEQ = 282,
180 LT = 283,
181 LTE = 284,
182 GT = 285,
183 GTE = 286,
184 CAT = 287,
185 GETLINE = 288,
186 PLUS = 289,
187 MINUS = 290,
188 MUL = 291,
189 DIV = 292,
190 MOD = 293,
191 NOT = 294,
192 UMINUS = 295,
193 IO_IN = 296,
194 PIPE = 297,
195 POW = 298,
196 INC_or_DEC = 299,
197 DOLLAR = 300,
198 FIELD = 301,
199 LPAREN = 302,
200 RPAREN = 303,
201 DOUBLE = 304,
202 STRING_ = 305,
203 RE = 306,
204 ID = 307,
205 D_ID = 308,
206 FUNCT_ID = 309,
207 C_FUNCT_ID = 310,
208 BUILTIN = 311,
209 LENGTH = 312,
210 PRINT = 313,
211 PRINTF = 314,
212 SPLIT = 315,
213 MATCH_FUNC = 316,
214 SUB = 317,
215 GSUB = 318,
216 DO = 319,
217 WHILE = 320,
218 FOR = 321,
219 BREAK = 322,
220 CONTINUE = 323,
221 IF = 324,
222 ELSE = 325,
223 DELETE = 326,
224 BEGIN = 327,
225 END = 328,
226 EXIT = 329,
227 NEXT = 330,
228 RETURN = 331,
229 FUNCTION = 332,
230 INCLUDE = 333
231 };
232 #endif
233 /* Tokens. */
234 #define UNEXPECTED 258
235 #define BAD_DECIMAL 259
236 #define NL 260
237 #define SEMI_COLON 261
238 #define LBRACE 262
239 #define RBRACE 263
240 #define LBOX 264
241 #define RBOX 265
242 #define COMMA 266
243 #define IO_OUT 267
244 #define ASSIGN 268
245 #define ADD_ASG 269
246 #define SUB_ASG 270
247 #define MUL_ASG 271
248 #define DIV_ASG 272
249 #define MOD_ASG 273
250 #define POW_ASG 274
251 #define QMARK 275
252 #define COLON 276
253 #define OR 277
254 #define AND 278
255 #define IN 279
256 #define MATCH 280
257 #define EQ 281
258 #define NEQ 282
259 #define LT 283
260 #define LTE 284
261 #define GT 285
262 #define GTE 286
263 #define CAT 287
264 #define GETLINE 288
265 #define PLUS 289
266 #define MINUS 290
267 #define MUL 291
268 #define DIV 292
269 #define MOD 293
270 #define NOT 294
271 #define UMINUS 295
272 #define IO_IN 296
273 #define PIPE 297
274 #define POW 298
275 #define INC_or_DEC 299
276 #define DOLLAR 300
277 #define FIELD 301
278 #define LPAREN 302
279 #define RPAREN 303
280 #define DOUBLE 304
281 #define STRING_ 305
282 #define RE 306
283 #define ID 307
284 #define D_ID 308
285 #define FUNCT_ID 309
286 #define C_FUNCT_ID 310
287 #define BUILTIN 311
288 #define LENGTH 312
289 #define PRINT 313
290 #define PRINTF 314
291 #define SPLIT 315
292 #define MATCH_FUNC 316
293 #define SUB 317
294 #define GSUB 318
295 #define DO 319
296 #define WHILE 320
297 #define FOR 321
298 #define BREAK 322
299 #define CONTINUE 323
300 #define IF 324
301 #define ELSE 325
302 #define DELETE 326
303 #define BEGIN 327
304 #define END 328
305 #define EXIT 329
306 #define NEXT 330
307 #define RETURN 331
308 #define FUNCTION 332
309 #define INCLUDE 333
310
311 /* Value type. */
312 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
313 typedef union YYSTYPE YYSTYPE;
314 union YYSTYPE
315 {
316 #line 136 "parse.y" /* yacc.c:355 */
317
318 mawk_cell_t *cp ;
319 SYMTAB *stp ;
320 int start ; /* code starting address as offset from code_base */
321 PF_CP fp ; /* ptr to a (print/printf) or (sub/gsub) function */
322 const BI_REC *bip ; /* ptr to info about a builtin */
323 FBLOCK *fbp ; /* ptr to a function block */
324 ARG2_REC *arg2p ;
325 CA_REC *ca_p ;
326 int ival ;
327 PTR ptr ;
328
329 #line 331 "y.tab.c" /* yacc.c:355 */
330 };
331 # define YYSTYPE_IS_TRIVIAL 1
332 # define YYSTYPE_IS_DECLARED 1
333 #endif
334
335
336
337 int Mawk_parse (mawk_state_t *MAWK);
338
339 #endif /* !YY_MAWK_Y_TAB_H_INCLUDED */
340
341 /* Copy the second part of user declarations. */
342
343 #line 345 "y.tab.c" /* yacc.c:358 */
344
345 #ifdef short
346 # undef short
347 #endif
348
349 #ifdef YYTYPE_UINT8
350 typedef YYTYPE_UINT8 yytype_uint8;
351 #else
352 typedef unsigned char yytype_uint8;
353 #endif
354
355 #ifdef YYTYPE_INT8
356 typedef YYTYPE_INT8 yytype_int8;
357 #else
358 typedef signed char yytype_int8;
359 #endif
360
361 #ifdef YYTYPE_UINT16
362 typedef YYTYPE_UINT16 yytype_uint16;
363 #else
364 typedef unsigned short int yytype_uint16;
365 #endif
366
367 #ifdef YYTYPE_INT16
368 typedef YYTYPE_INT16 yytype_int16;
369 #else
370 typedef short int yytype_int16;
371 #endif
372
373 #ifndef YYSIZE_T
374 # ifdef __SIZE_TYPE__
375 # define YYSIZE_T __SIZE_TYPE__
376 # elif defined size_t
377 # define YYSIZE_T size_t
378 # elif ! defined YYSIZE_T
379 # include <stddef.h> /* INFRINGES ON USER NAME SPACE */
380 # define YYSIZE_T size_t
381 # else
382 # define YYSIZE_T unsigned int
383 # endif
384 #endif
385
386 #define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
387
388 #ifndef YY_
389 # if defined YYENABLE_NLS && YYENABLE_NLS
390 # if ENABLE_NLS
391 # include <libintl.h> /* INFRINGES ON USER NAME SPACE */
392 # define YY_(Msgid) dgettext ("bison-runtime", Msgid)
393 # endif
394 # endif
395 # ifndef YY_
396 # define YY_(Msgid) Msgid
397 # endif
398 #endif
399
400 #ifndef YY_ATTRIBUTE
401 # if (defined __GNUC__ \
402 && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
403 || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
404 # define YY_ATTRIBUTE(Spec) __attribute__(Spec)
405 # else
406 # define YY_ATTRIBUTE(Spec) /* empty */
407 # endif
408 #endif
409
410 #ifndef YY_ATTRIBUTE_PURE
411 # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
412 #endif
413
414 #ifndef YY_ATTRIBUTE_UNUSED
415 # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
416 #endif
417
418 #if !defined _Noreturn \
419 && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
420 # if defined _MSC_VER && 1200 <= _MSC_VER
421 # define _Noreturn __declspec (noreturn)
422 # else
423 # define _Noreturn YY_ATTRIBUTE ((__noreturn__))
424 # endif
425 #endif
426
427 /* Suppress unused-variable warnings by "using" E. */
428 #if ! defined lint || defined __GNUC__
429 # define YYUSE(E) ((void) (E))
430 #else
431 # define YYUSE(E) /* empty */
432 #endif
433
434 #if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
435 /* Suppress an incorrect diagnostic about yylval being uninitialized. */
436 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
437 _Pragma ("GCC diagnostic push") \
438 _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
439 _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
440 # define YY_IGNORE_MAYBE_UNINITIALIZED_END \
441 _Pragma ("GCC diagnostic pop")
442 #else
443 # define YY_INITIAL_VALUE(Value) Value
444 #endif
445 #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
446 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
447 # define YY_IGNORE_MAYBE_UNINITIALIZED_END
448 #endif
449 #ifndef YY_INITIAL_VALUE
450 # define YY_INITIAL_VALUE(Value) /* Nothing. */
451 #endif
452
453
454 #if ! defined yyoverflow || YYERROR_VERBOSE
455
456 /* The parser invokes alloca or malloc; define the necessary symbols. */
457
458 # ifdef YYSTACK_USE_ALLOCA
459 # if YYSTACK_USE_ALLOCA
460 # ifdef __GNUC__
461 # define YYSTACK_ALLOC __builtin_alloca
462 # elif defined __BUILTIN_VA_ARG_INCR
463 # include <alloca.h> /* INFRINGES ON USER NAME SPACE */
464 # elif defined _AIX
465 # define YYSTACK_ALLOC __alloca
466 # elif defined _MSC_VER
467 # include <malloc.h> /* INFRINGES ON USER NAME SPACE */
468 # define alloca _alloca
469 # else
470 # define YYSTACK_ALLOC alloca
471 # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
472 # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
473 /* Use EXIT_SUCCESS as a witness for stdlib.h. */
474 # ifndef EXIT_SUCCESS
475 # define EXIT_SUCCESS 0
476 # endif
477 # endif
478 # endif
479 # endif
480 # endif
481
482 # ifdef YYSTACK_ALLOC
483 /* Pacify GCC's 'empty if-body' warning. */
484 # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
485 # ifndef YYSTACK_ALLOC_MAXIMUM
486 /* The OS might guarantee only one guard page at the bottom of the stack,
487 and a page size can be as small as 4096 bytes. So we cannot safely
488 invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
489 to allow for a few compiler-allocated temporary stack slots. */
490 # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
491 # endif
492 # else
493 # define YYSTACK_ALLOC YYMALLOC
494 # define YYSTACK_FREE YYFREE
495 # ifndef YYSTACK_ALLOC_MAXIMUM
496 # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
497 # endif
498 # if (defined __cplusplus && ! defined EXIT_SUCCESS \
499 && ! ((defined YYMALLOC || defined malloc) \
500 && (defined YYFREE || defined free)))
501 # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
502 # ifndef EXIT_SUCCESS
503 # define EXIT_SUCCESS 0
504 # endif
505 # endif
506 # ifndef YYMALLOC
507 # define YYMALLOC malloc
508 # if ! defined malloc && ! defined EXIT_SUCCESS
509 void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
510 # endif
511 # endif
512 # ifndef YYFREE
513 # define YYFREE free
514 # if ! defined free && ! defined EXIT_SUCCESS
515 void free (void *); /* INFRINGES ON USER NAME SPACE */
516 # endif
517 # endif
518 # endif
519 #endif /* ! defined yyoverflow || YYERROR_VERBOSE */
520
521
522 #if (! defined yyoverflow \
523 && (! defined __cplusplus \
524 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
525
526 /* A type that is properly aligned for any stack member. */
527 union yyalloc
528 {
529 yytype_int16 yyss_alloc;
530 YYSTYPE yyvs_alloc;
531 };
532
533 /* The size of the maximum gap between one aligned stack and the next. */
534 # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
535
536 /* The size of an array large to enough to hold all stacks, each with
537 N elements. */
538 # define YYSTACK_BYTES(N) \
539 ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
540 + YYSTACK_GAP_MAXIMUM)
541
542 # define YYCOPY_NEEDED 1
543
544 /* Relocate STACK from its old location to the new one. The
545 local variables YYSIZE and YYSTACKSIZE give the old and new number of
546 elements in the stack, and YYPTR gives the new location of the
547 stack. Advance YYPTR to a properly aligned location for the next
548 stack. */
549 # define YYSTACK_RELOCATE(Stack_alloc, Stack) \
550 do \
551 { \
552 YYSIZE_T yynewbytes; \
553 YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
554 Stack = &yyptr->Stack_alloc; \
555 yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
556 yyptr += yynewbytes / sizeof (*yyptr); \
557 } \
558 while (0)
559
560 #endif
561
562 #if defined YYCOPY_NEEDED && YYCOPY_NEEDED
563 /* Copy COUNT objects from SRC to DST. The source and destination do
564 not overlap. */
565 # ifndef YYCOPY
566 # if defined __GNUC__ && 1 < __GNUC__
567 # define YYCOPY(Dst, Src, Count) \
568 __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
569 # else
570 # define YYCOPY(Dst, Src, Count) \
571 do \
572 { \
573 YYSIZE_T yyi; \
574 for (yyi = 0; yyi < (Count); yyi++) \
575 (Dst)[yyi] = (Src)[yyi]; \
576 } \
577 while (0)
578 # endif
579 # endif
580 #endif /* !YYCOPY_NEEDED */
581
582 /* YYFINAL -- State number of the termination state. */
583 #define YYFINAL 103
584 /* YYLAST -- Last index in YYTABLE. */
585 #define YYLAST 1147
586
587 /* YYNTOKENS -- Number of terminals. */
588 #define YYNTOKENS 79
589 /* YYNNTS -- Number of nonterminals. */
590 #define YYNNTS 60
591 /* YYNRULES -- Number of rules. */
592 #define YYNRULES 186
593 /* YYNSTATES -- Number of states. */
594 #define YYNSTATES 360
595
596 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
597 by yylex, with out-of-bounds checking. */
598 #define YYUNDEFTOK 2
599 #define YYMAXUTOK 333
600
601 #define YYTRANSLATE(YYX) \
602 ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
603
604 /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
605 as returned by yylex, without out-of-bounds checking. */
606 static const yytype_uint8 yytranslate[] =
607 {
608 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
609 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
610 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
611 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
612 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
613 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
614 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
615 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
616 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
617 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
618 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
619 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
620 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
621 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
622 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
623 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
624 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
625 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
626 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
627 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
628 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
629 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
630 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
631 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
632 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
633 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
634 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
635 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
636 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
637 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
638 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
639 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
640 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
641 75, 76, 77, 78
642 };
643
644 #if YYDEBUG
645 /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
646 static const yytype_uint16 yyrline[] =
647 {
648 0, 213, 213, 214, 217, 218, 219, 222, 227, 229,
649 232, 231, 238, 237, 244, 243, 251, 267, 250, 280,
650 282, 288, 289, 295, 296, 300, 301, 303, 305, 311,
651 314, 317, 321, 329, 329, 332, 333, 334, 335, 336,
652 337, 338, 339, 340, 341, 342, 343, 344, 345, 346,
653 347, 348, 349, 350, 351, 352, 354, 383, 382, 390,
654 389, 396, 397, 396, 402, 403, 407, 409, 411, 419,
655 423, 427, 428, 429, 430, 431, 432, 433, 435, 437,
656 439, 442, 450, 455, 462, 466, 473, 482, 483, 486,
657 488, 493, 504, 514, 517, 526, 527, 530, 531, 535,
658 539, 544, 548, 549, 556, 561, 565, 569, 577, 582,
659 588, 608, 634, 658, 659, 663, 664, 681, 685, 698,
660 703, 716, 729, 742, 754, 771, 779, 790, 804, 821,
661 823, 832, 846, 848, 852, 856, 857, 858, 859, 860,
662 861, 862, 868, 872, 879, 881, 905, 912, 935, 938,
663 941, 944, 949, 956, 962, 967, 972, 979, 983, 983,
664 983, 985, 989, 997, 1016, 1017, 1021, 1026, 1034, 1042,
665 1061, 1084, 1091, 1092, 1095, 1101, 1114, 1126, 1138, 1147,
666 1149, 1164, 1166, 1173, 1182, 1188, 1196
667 };
668 #endif
669
670 #if YYDEBUG || YYERROR_VERBOSE || 0
671 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
672 First, the terminals, then, starting at YYNTOKENS, nonterminals. */
673 static const char *const yytname[] =
674 {
675 "$end", "error", "$undefined", "UNEXPECTED", "BAD_DECIMAL", "NL",
676 "SEMI_COLON", "LBRACE", "RBRACE", "LBOX", "RBOX", "COMMA", "IO_OUT",
677 "ASSIGN", "ADD_ASG", "SUB_ASG", "MUL_ASG", "DIV_ASG", "MOD_ASG",
678 "POW_ASG", "QMARK", "COLON", "OR", "AND", "IN", "MATCH", "EQ", "NEQ",
679 "LT", "LTE", "GT", "GTE", "CAT", "GETLINE", "PLUS", "MINUS", "MUL",
680 "DIV", "MOD", "NOT", "UMINUS", "IO_IN", "PIPE", "POW", "INC_or_DEC",
681 "DOLLAR", "FIELD", "LPAREN", "RPAREN", "DOUBLE", "STRING_", "RE", "ID",
682 "D_ID", "FUNCT_ID", "C_FUNCT_ID", "BUILTIN", "LENGTH", "PRINT", "PRINTF",
683 "SPLIT", "MATCH_FUNC", "SUB", "GSUB", "DO", "WHILE", "FOR", "BREAK",
684 "CONTINUE", "IF", "ELSE", "DELETE", "BEGIN", "END", "EXIT", "NEXT",
685 "RETURN", "FUNCTION", "INCLUDE", "$accept", "program", "program_block",
686 "PA_block", "$@1", "$@2", "$@3", "$@4", "$@5", "block",
687 "block_or_separator", "statement_list", "statement", "separator", "expr",
688 "$@6", "$@7", "$@8", "$@9", "cat_expr", "p_expr", "lvalue", "arglist",
689 "args", "builtin", "mark", "print", "pr_args", "arg2", "pr_direction",
690 "if_front", "else", "do", "while_front", "for1", "for2", "for3",
691 "bifunct_target_arr", "lvalue_arrwr", "array_loop_front", "field",
692 "split_front", "split_back", "re_arg", "return_statement", "getline",
693 "bifunct_target", "getline_file", "sub_or_gsub", "sub_back",
694 "function_def", "funct_start", "funct_head", "f_arglist", "f_args",
695 "outside_error", "call_args", "ca_front", "ca_back", "include", YY_NULLPTR
696 };
697 #endif
698
699 # ifdef YYPRINT
700 /* YYTOKNUM[NUM] -- (External) token number corresponding to the
701 (internal) symbol number NUM (which must be that of a token). */
702 static const yytype_uint16 yytoknum[] =
703 {
704 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
705 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
706 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
707 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
708 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
709 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
710 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
711 325, 326, 327, 328, 329, 330, 331, 332, 333
712 };
713 # endif
714
715 #define YYPACT_NINF -225
716
717 #define yypact_value_is_default(Yystate) \
718 (!!((Yystate) == (-225)))
719
720 #define YYTABLE_NINF -123
721
722 #define yytable_value_is_error(Yytable_value) \
723 (!!((Yytable_value) == (-123)))
724
725 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
726 STATE-NUM. */
727 static const yytype_int16 yypact[] =
728 {
729 351, -225, -225, 486, -225, 811, 811, 811, 104, 718,
730 -225, 842, -225, -225, -225, 219, -225, -225, -225, -225,
731 -45, -10, -225, -225, -225, -225, 7, -9, 316, -225,
732 -225, -225, 1074, 811, 153, 1038, -225, 1073, 73, 1,
733 32, 811, 4, -225, 48, 11, 48, -225, 30, -225,
734 -225, -225, -225, -225, 16, 18, 25, 25, 22, 19,
735 625, 25, 625, -225, 414, -225, -225, 411, -225, 558,
736 558, 558, 656, 558, -225, 842, 20, 120, 37, 120,
737 120, 59, 67, -225, -225, -225, 67, -225, 475, 2,
738 198, -225, 74, 38, 38, 46, 842, 842, 48, 48,
739 -225, -225, -225, -225, -225, -225, -225, -225, -225, 43,
740 842, 842, 842, 842, 842, 842, 842, 169, 153, 811,
741 811, 811, 811, 811, 66, 811, 842, 842, 842, 842,
742 842, 842, 842, 842, 842, 842, 842, 842, 842, 842,
743 842, 842, 842, 842, 842, 842, 842, -225, 842, -225,
744 -225, -225, 67, -225, -225, -225, 60, 127, 842, -225,
745 71, -225, -225, -225, 842, 687, -225, -225, 842, 25,
746 -225, 411, -225, -225, 411, 25, -225, -225, -225, 873,
747 84, 101, -225, -225, 1041, 749, -225, 948, 163, 130,
748 184, 192, 842, -225, 842, 203, -225, 842, 171, -225,
749 904, -225, 842, 1095, 1116, -225, -225, 842, 842, 842,
750 842, -225, 307, -225, -225, -225, -225, -225, -225, -225,
751 -225, -225, 216, 216, 120, 120, 120, 249, 196, 559,
752 559, 559, 559, 559, 559, 559, 559, 559, 559, 559,
753 559, 559, 559, 559, 559, 559, 559, 559, 559, 559,
754 960, 231, -225, 559, 230, -225, 197, 233, 975, -225,
755 259, 1053, 987, -225, 238, -225, -225, 780, 559, -225,
756 237, 239, -225, 558, 208, -225, -225, 1002, 558, 842,
757 842, 842, 559, 559, 204, 34, -225, 8, 547, -225,
758 202, 209, 842, 559, 487, 626, 260, -225, -225, 842,
759 842, -225, 210, -225, 212, -225, -225, 842, -225, 9,
760 842, 842, 25, -225, 842, -225, -225, 188, 193, 195,
761 -225, 313, -225, -225, -225, -225, -225, -225, 217, 169,
762 -225, 211, 617, -225, 221, 214, 203, 559, 559, -225,
763 1014, 226, -225, -225, -225, -225, -225, 842, -225, 249,
764 -225, -225, -225, 25, 25, 559, 223, -225, -225, -225
765 };
766
767 /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
768 Performed when YYTABLE does not specify something else to do. Zero
769 means the default is an error. */
770 static const yytype_uint8 yydefact[] =
771 {
772 0, 176, 9, 0, 157, 0, 0, 0, 0, 0,
773 129, 0, 66, 67, 70, 68, 93, 93, 93, 92,
774 0, 0, 164, 165, 10, 12, 0, 0, 0, 2,
775 4, 7, 14, 35, 64, 0, 80, 0, 134, 0,
776 152, 0, 0, 5, 0, 0, 0, 8, 0, 33,
777 34, 95, 96, 108, 0, 0, 0, 0, 0, 0,
778 0, 0, 0, 25, 0, 23, 27, 0, 93, 0,
779 0, 0, 0, 0, 31, 0, 68, 78, 134, 79,
780 77, 0, 86, 82, 83, 85, 130, 132, 0, 0,
781 134, 81, 0, 0, 0, 0, 0, 0, 0, 0,
782 170, 171, 186, 1, 3, 16, 61, 57, 59, 0,
783 0, 0, 0, 0, 0, 0, 0, 0, 65, 0,
784 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
785 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
786 0, 0, 0, 0, 0, 0, 0, 84, 0, 144,
787 142, 161, 86, 158, 159, 160, 153, 154, 0, 168,
788 172, 6, 20, 28, 0, 0, 29, 30, 0, 93,
789 148, 0, 32, 150, 0, 0, 19, 24, 26, 87,
790 105, 0, 111, 115, 0, 0, 128, 0, 0, 0,
791 0, 0, 0, 69, 0, 0, 133, 0, 181, 177,
792 0, 178, 87, 0, 0, 11, 13, 0, 0, 0,
793 0, 119, 56, 50, 51, 52, 53, 54, 55, 21,
794 15, 22, 71, 72, 73, 74, 75, 155, 76, 36,
795 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
796 47, 48, 49, 135, 136, 137, 138, 139, 140, 141,
797 0, 0, 162, 147, 0, 174, 0, 173, 0, 113,
798 68, 0, 0, 126, 0, 149, 151, 0, 89, 97,
799 88, 102, 106, 0, 0, 116, 117, 0, 0, 0,
800 0, 0, 100, 101, 0, 0, 179, 68, 0, 180,
801 0, 0, 0, 17, 0, 58, 60, 156, 145, 0,
802 0, 169, 0, 110, 0, 114, 104, 0, 99, 0,
803 0, 0, 0, 107, 0, 118, 112, 0, 0, 0,
804 120, 123, 183, 185, 182, 184, 91, 143, 0, 0,
805 62, 0, 0, 175, 0, 0, 98, 90, 103, 94,
806 0, 123, 122, 131, 124, 146, 18, 0, 121, 0,
807 166, 163, 127, 0, 0, 63, 0, 125, 109, 167
808 };
809
810 /* YYPGOTO[NTERM-NUM]. */
811 static const yytype_int16 yypgoto[] =
812 {
813 -225, -225, 254, -225, -225, -225, -225, -225, -225, 54,
814 -36, -225, -55, -14, 0, -225, -225, -225, -225, -225,
815 61, -7, 95, -50, -225, 91, -225, -225, 35, -225,
816 -225, -225, -225, -225, -225, -225, -225, -225, 296, -225,
817 -1, -225, -225, 13, -225, -225, -224, -225, -225, -225,
818 -225, -225, -225, -225, -225, -225, 215, -225, -225, -225
819 };
820
821 /* YYDEFGOTO[NTERM-NUM]. */
822 static const yytype_int16 yydefgoto[] =
823 {
824 -1, 28, 29, 30, 98, 99, 117, 207, 329, 63,
825 220, 64, 65, 66, 67, 209, 210, 208, 347, 33,
826 34, 35, 269, 270, 36, 92, 68, 271, 89, 312,
827 69, 273, 70, 71, 72, 185, 278, 154, 37, 73,
828 38, 39, 150, 254, 74, 40, 156, 41, 42, 351,
829 43, 44, 45, 256, 257, 46, 199, 200, 289, 47
830 };
831
832 /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
833 positive, shift that token. If negative, reduce the rule whose
834 number is the opposite. If YYTABLE_NINF, syntax error. */
835 static const yytype_int16 yytable[] =
836 {
837 32, 83, 96, 297, 78, 78, 78, 85, 78, 177,
838 90, 88, 148, 194, 180, 181, 182, -93, 186, 322,
839 194, -86, -86, -86, -86, -86, -86, -86, 32, -93,
840 49, 50, 78, 153, 163, 49, 50, 97, 162, 155,
841 78, 102, 166, 167, 321, 310, 170, 172, 173, 149,
842 195, 158, 91, 178, 31, 3, 323, 336, 160, 100,
843 171, 101, 174, 164, 91, 165, 77, 79, 80, 168,
844 87, 169, 184, 151, 90, 187, -93, 9, 10, 81,
845 189, 147, 31, 197, 152, 198, 140, 141, 142, 143,
846 144, 145, 146, 202, 118, 211, 203, 204, 159, 227,
847 161, 252, 157, 221, 9, 10, 81, 93, 94, 95,
848 212, 213, 214, 215, 216, 217, 218, 147, 78, 78,
849 78, 78, 78, 255, 78, 356, 229, 230, 231, 232,
850 233, 234, 235, 236, 237, 238, 239, 240, 241, 242,
851 243, 244, 245, 246, 247, 248, 249, 285, 250, 9,
852 10, 81, 205, 206, 272, 263, 82, 265, 253, 179,
853 266, 163, 124, 125, 258, 261, 274, 188, 262, -123,
854 125, 219, 279, 190, 49, 50, 3, 191, 196, 268,
855 222, 223, 224, 225, 226, 277, 228, 119, 120, 121,
856 122, 123, 282, 280, 283, 124, 125, 268, 341, 310,
857 288, 281, 268, 342, 310, 343, 310, 293, 294, 295,
858 296, 140, 141, 142, 143, 144, 145, 146, 313, 286,
859 153, 348, 310, 316, 353, 310, 155, 284, -93, 317,
860 318, 319, -86, -86, -86, -86, -86, -86, -86, 125,
861 299, 300, 147, 251, 302, 301, 196, 307, 310, 331,
862 326, 311, 121, 122, 123, 314, 320, 335, 124, 125,
863 264, 327, 333, 91, 334, 345, 90, 88, -93, 352,
864 344, 359, -86, -86, -86, -86, -86, -86, -86, 268,
865 268, 268, 104, 304, 109, 110, 111, 112, 113, 114,
866 115, 116, 253, 346, 9, 10, 81, 290, 339, 268,
867 332, 152, 309, 91, 84, 328, 0, 268, 0, 201,
868 337, 338, 0, 0, 340, 221, 103, 1, 0, 0,
869 0, 2, 0, 3, 0, 0, -122, -122, -122, -122,
870 -122, -122, -122, 111, 112, 113, 114, 115, 116, 357,
871 358, 0, 153, 0, 0, 0, 0, 355, 155, 4,
872 5, 6, 1, 0, 0, 7, 2, 344, 3, 0,
873 8, 9, 10, 11, 0, 12, 13, 14, 15, 0,
874 16, 17, 18, 19, 0, 0, 20, 21, 22, 23,
875 0, 0, 0, 219, 4, 5, 6, 0, 24, 25,
876 7, 0, 0, 26, 27, 8, 9, 10, 11, 0,
877 12, 13, 14, 15, 0, 16, 17, 18, 19, 0,
878 0, 20, 21, 22, 23, 175, 49, 50, 0, 49,
879 50, 3, 176, 24, 25, 0, 0, 0, 26, 27,
880 0, 106, 0, 107, 108, 109, 110, 111, 112, 113,
881 114, 115, 116, 0, 0, 0, 0, 4, 5, 6,
882 0, 0, 0, 7, 0, 0, 0, 0, 8, 9,
883 10, 11, 0, 12, 13, 14, 15, 0, 16, 17,
884 18, 19, 51, 52, 20, 21, 22, 23, 53, 54,
885 55, 56, 57, 58, 0, 59, 192, 48, 60, 61,
886 62, 49, 50, 3, 0, 106, 0, 107, 108, 109,
887 110, 111, 112, 113, 114, 115, 116, 106, 330, 107,
888 108, 109, 110, 111, 112, 113, 114, 115, 116, 4,
889 5, 6, 0, 193, 0, 7, 0, 0, 0, 0,
890 8, 9, 10, 11, 0, 12, 13, 14, 15, 0,
891 16, 17, 18, 19, 51, 52, 20, 21, 22, 23,
892 53, 54, 55, 56, 57, 58, 0, 59, 324, 175,
893 60, 61, 62, 49, 50, 3, 0, 106, 0, 107,
894 108, 109, 110, 111, 112, 113, 114, 115, 116, 106,
895 0, 107, 108, 109, 110, 111, 112, 113, 114, 115,
896 116, 4, 5, 6, 0, 325, 0, 7, 0, 0,
897 0, 0, 8, 9, 10, 11, 0, 12, 13, 14,
898 15, 0, 16, 17, 18, 19, 51, 52, 20, 21,
899 22, 23, 53, 54, 55, 56, 57, 58, 349, 59,
900 49, 50, 60, 61, 62, 0, 0, 106, 0, 107,
901 108, 109, 110, 111, 112, 113, 114, 115, 116, 108,
902 109, 110, 111, 112, 113, 114, 115, 116, 4, 5,
903 6, 0, 183, 0, 7, 350, 0, 0, 0, 8,
904 9, 10, 11, 0, 12, 13, 14, 15, 0, 16,
905 17, 18, 19, 0, 0, 20, 21, 22, 23, 4,
906 5, 6, 0, 259, 0, 7, 0, 0, 0, 0,
907 8, 9, 10, 11, 0, 12, 13, 14, 15, 0,
908 16, 17, 18, 19, 0, 0, 20, 21, 22, 23,
909 4, 5, 6, 0, 0, 0, 7, 0, 0, 0,
910 0, 8, 9, 10, 11, 0, 12, 13, 14, 260,
911 0, 16, 17, 18, 19, 0, 0, 20, 21, 22,
912 23, 4, 5, 6, 0, 0, 0, 7, 0, 0,
913 0, 0, 8, 9, 10, 75, 0, 12, 13, 14,
914 76, 86, 16, 17, 18, 19, 0, 0, 20, 21,
915 22, 23, 4, 5, 6, 0, 0, 0, 7, 0,
916 0, 0, 0, 8, 9, 10, 11, 276, 12, 13,
917 14, 15, 0, 16, 17, 18, 19, 0, 0, 20,
918 21, 22, 23, 4, 5, 6, 0, 0, 0, 7,
919 0, 0, 0, 0, 8, 9, 10, 11, 308, 12,
920 13, 14, 15, 0, 16, 17, 18, 19, 0, 0,
921 20, 21, 22, 23, 4, 5, 6, 0, 0, 0,
922 7, 0, 0, 0, 0, 8, 9, 10, 75, 0,
923 12, 13, 14, 76, 0, 16, 17, 18, 19, 0,
924 0, 20, 21, 22, 23, 4, 5, 6, 0, 0,
925 0, 7, 0, 0, 0, 0, 8, 9, 10, 11,
926 0, 12, 13, 14, 15, 0, 16, 17, 18, 19,
927 0, 0, 20, 21, 22, 23, 4, 5, 6, 0,
928 0, 0, 7, 0, 0, 0, 0, 8, 9, 10,
929 267, 0, 12, 13, 14, 15, 0, 16, 17, 18,
930 19, 0, 0, 20, 21, 22, 23, 4, 5, 6,
931 0, 0, 0, 7, 0, 0, 0, 0, 8, 9,
932 10, 11, 0, 12, 13, 14, 287, 0, 16, 17,
933 18, 19, 0, 0, 20, 21, 22, 23, 106, 0,
934 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
935 106, 0, 107, 108, 109, 110, 111, 112, 113, 114,
936 115, 116, 0, 0, 0, 106, 193, 107, 108, 109,
937 110, 111, 112, 113, 114, 115, 116, 106, 298, 107,
938 108, 109, 110, 111, 112, 113, 114, 115, 116, 0,
939 0, 0, 106, 303, 107, 108, 109, 110, 111, 112,
940 113, 114, 115, 116, 106, 306, 107, 108, 109, 110,
941 111, 112, 113, 114, 115, 116, 0, 275, 0, 0,
942 315, 126, 127, 128, 129, 130, 131, 132, 0, 305,
943 0, 106, 354, 107, 108, 109, 110, 111, 112, 113,
944 114, 115, 116, 106, 0, 107, 108, 109, 110, 111,
945 112, 113, 114, 115, 116, 105, 133, 134, 135, 136,
946 137, 138, 139, 0, 106, 0, 107, 108, 109, 110,
947 111, 112, 113, 114, 115, 116, 291, 0, 0, 0,
948 0, 0, 0, 0, 0, 106, 0, 107, 108, 109,
949 110, 111, 112, 113, 114, 115, 116, 292, 0, 0,
950 0, 0, 0, 0, 0, 0, 106, 0, 107, 108,
951 109, 110, 111, 112, 113, 114, 115, 116
952 };
953
954 static const yytype_int16 yycheck[] =
955 {
956 0, 8, 47, 227, 5, 6, 7, 8, 9, 64,
957 11, 11, 11, 11, 69, 70, 71, 9, 73, 11,
958 11, 13, 14, 15, 16, 17, 18, 19, 28, 9,
959 5, 6, 33, 40, 48, 5, 6, 47, 8, 40,
960 41, 50, 56, 57, 10, 11, 60, 61, 62, 48,
961 48, 47, 44, 67, 0, 7, 48, 48, 47, 52,
962 60, 54, 62, 47, 44, 47, 5, 6, 7, 47,
963 9, 52, 72, 41, 75, 75, 9, 45, 46, 47,
964 81, 44, 28, 9, 52, 47, 13, 14, 15, 16,
965 17, 18, 19, 47, 33, 52, 96, 97, 44, 33,
966 46, 41, 41, 117, 45, 46, 47, 16, 17, 18,
967 110, 111, 112, 113, 114, 115, 116, 44, 119, 120,
968 121, 122, 123, 52, 125, 349, 126, 127, 128, 129,
969 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
970 140, 141, 142, 143, 144, 145, 146, 197, 148, 45,
971 46, 47, 98, 99, 70, 169, 52, 171, 158, 68,
972 174, 175, 42, 43, 164, 165, 65, 76, 168, 42,
973 43, 117, 9, 82, 5, 6, 7, 86, 48, 179,
974 119, 120, 121, 122, 123, 185, 125, 34, 35, 36,
975 37, 38, 192, 9, 194, 42, 43, 197, 10, 11,
976 200, 9, 202, 10, 11, 10, 11, 207, 208, 209,
977 210, 13, 14, 15, 16, 17, 18, 19, 273, 48,
978 227, 10, 11, 278, 10, 11, 227, 24, 9, 279,
979 280, 281, 13, 14, 15, 16, 17, 18, 19, 43,
980 9, 11, 44, 152, 11, 48, 48, 9, 11, 299,
981 48, 12, 36, 37, 38, 47, 52, 307, 42, 43,
982 169, 52, 52, 44, 52, 48, 267, 267, 9, 48,
983 44, 48, 13, 14, 15, 16, 17, 18, 19, 279,
984 280, 281, 28, 24, 24, 25, 26, 27, 28, 29,
985 30, 31, 292, 329, 45, 46, 47, 202, 312, 299,
986 300, 52, 267, 44, 8, 292, -1, 307, -1, 94,
987 310, 311, -1, -1, 314, 329, 0, 1, -1, -1,
988 -1, 5, -1, 7, -1, -1, 13, 14, 15, 16,
989 17, 18, 19, 26, 27, 28, 29, 30, 31, 353,
990 354, -1, 349, -1, -1, -1, -1, 347, 349, 33,
991 34, 35, 1, -1, -1, 39, 5, 44, 7, -1,
992 44, 45, 46, 47, -1, 49, 50, 51, 52, -1,
993 54, 55, 56, 57, -1, -1, 60, 61, 62, 63,
994 -1, -1, -1, 329, 33, 34, 35, -1, 72, 73,
995 39, -1, -1, 77, 78, 44, 45, 46, 47, -1,
996 49, 50, 51, 52, -1, 54, 55, 56, 57, -1,
997 -1, 60, 61, 62, 63, 1, 5, 6, -1, 5,
998 6, 7, 8, 72, 73, -1, -1, -1, 77, 78,
999 -1, 20, -1, 22, 23, 24, 25, 26, 27, 28,
1000 29, 30, 31, -1, -1, -1, -1, 33, 34, 35,
1001 -1, -1, -1, 39, -1, -1, -1, -1, 44, 45,
1002 46, 47, -1, 49, 50, 51, 52, -1, 54, 55,
1003 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
1004 66, 67, 68, 69, -1, 71, 11, 1, 74, 75,
1005 76, 5, 6, 7, -1, 20, -1, 22, 23, 24,
1006 25, 26, 27, 28, 29, 30, 31, 20, 21, 22,
1007 23, 24, 25, 26, 27, 28, 29, 30, 31, 33,
1008 34, 35, -1, 48, -1, 39, -1, -1, -1, -1,
1009 44, 45, 46, 47, -1, 49, 50, 51, 52, -1,
1010 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
1011 64, 65, 66, 67, 68, 69, -1, 71, 11, 1,
1012 74, 75, 76, 5, 6, 7, -1, 20, -1, 22,
1013 23, 24, 25, 26, 27, 28, 29, 30, 31, 20,
1014 -1, 22, 23, 24, 25, 26, 27, 28, 29, 30,
1015 31, 33, 34, 35, -1, 48, -1, 39, -1, -1,
1016 -1, -1, 44, 45, 46, 47, -1, 49, 50, 51,
1017 52, -1, 54, 55, 56, 57, 58, 59, 60, 61,
1018 62, 63, 64, 65, 66, 67, 68, 69, 11, 71,
1019 5, 6, 74, 75, 76, -1, -1, 20, -1, 22,
1020 23, 24, 25, 26, 27, 28, 29, 30, 31, 23,
1021 24, 25, 26, 27, 28, 29, 30, 31, 33, 34,
1022 35, -1, 6, -1, 39, 48, -1, -1, -1, 44,
1023 45, 46, 47, -1, 49, 50, 51, 52, -1, 54,
1024 55, 56, 57, -1, -1, 60, 61, 62, 63, 33,
1025 34, 35, -1, 6, -1, 39, -1, -1, -1, -1,
1026 44, 45, 46, 47, -1, 49, 50, 51, 52, -1,
1027 54, 55, 56, 57, -1, -1, 60, 61, 62, 63,
1028 33, 34, 35, -1, -1, -1, 39, -1, -1, -1,
1029 -1, 44, 45, 46, 47, -1, 49, 50, 51, 52,
1030 -1, 54, 55, 56, 57, -1, -1, 60, 61, 62,
1031 63, 33, 34, 35, -1, -1, -1, 39, -1, -1,
1032 -1, -1, 44, 45, 46, 47, -1, 49, 50, 51,
1033 52, 53, 54, 55, 56, 57, -1, -1, 60, 61,
1034 62, 63, 33, 34, 35, -1, -1, -1, 39, -1,
1035 -1, -1, -1, 44, 45, 46, 47, 48, 49, 50,
1036 51, 52, -1, 54, 55, 56, 57, -1, -1, 60,
1037 61, 62, 63, 33, 34, 35, -1, -1, -1, 39,
1038 -1, -1, -1, -1, 44, 45, 46, 47, 48, 49,
1039 50, 51, 52, -1, 54, 55, 56, 57, -1, -1,
1040 60, 61, 62, 63, 33, 34, 35, -1, -1, -1,
1041 39, -1, -1, -1, -1, 44, 45, 46, 47, -1,
1042 49, 50, 51, 52, -1, 54, 55, 56, 57, -1,
1043 -1, 60, 61, 62, 63, 33, 34, 35, -1, -1,
1044 -1, 39, -1, -1, -1, -1, 44, 45, 46, 47,
1045 -1, 49, 50, 51, 52, -1, 54, 55, 56, 57,
1046 -1, -1, 60, 61, 62, 63, 33, 34, 35, -1,
1047 -1, -1, 39, -1, -1, -1, -1, 44, 45, 46,
1048 47, -1, 49, 50, 51, 52, -1, 54, 55, 56,
1049 57, -1, -1, 60, 61, 62, 63, 33, 34, 35,
1050 -1, -1, -1, 39, -1, -1, -1, -1, 44, 45,
1051 46, 47, -1, 49, 50, 51, 52, -1, 54, 55,
1052 56, 57, -1, -1, 60, 61, 62, 63, 20, -1,
1053 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1054 20, -1, 22, 23, 24, 25, 26, 27, 28, 29,
1055 30, 31, -1, -1, -1, 20, 48, 22, 23, 24,
1056 25, 26, 27, 28, 29, 30, 31, 20, 48, 22,
1057 23, 24, 25, 26, 27, 28, 29, 30, 31, -1,
1058 -1, -1, 20, 48, 22, 23, 24, 25, 26, 27,
1059 28, 29, 30, 31, 20, 48, 22, 23, 24, 25,
1060 26, 27, 28, 29, 30, 31, -1, 6, -1, -1,
1061 48, 13, 14, 15, 16, 17, 18, 19, -1, 6,
1062 -1, 20, 48, 22, 23, 24, 25, 26, 27, 28,
1063 29, 30, 31, 20, -1, 22, 23, 24, 25, 26,
1064 27, 28, 29, 30, 31, 11, 13, 14, 15, 16,
1065 17, 18, 19, -1, 20, -1, 22, 23, 24, 25,
1066 26, 27, 28, 29, 30, 31, 11, -1, -1, -1,
1067 -1, -1, -1, -1, -1, 20, -1, 22, 23, 24,
1068 25, 26, 27, 28, 29, 30, 31, 11, -1, -1,
1069 -1, -1, -1, -1, -1, -1, 20, -1, 22, 23,
1070 24, 25, 26, 27, 28, 29, 30, 31
1071 };
1072
1073 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
1074 symbol of state STATE-NUM. */
1075 static const yytype_uint8 yystos[] =
1076 {
1077 0, 1, 5, 7, 33, 34, 35, 39, 44, 45,
1078 46, 47, 49, 50, 51, 52, 54, 55, 56, 57,
1079 60, 61, 62, 63, 72, 73, 77, 78, 80, 81,
1080 82, 88, 93, 98, 99, 100, 103, 117, 119, 120,
1081 124, 126, 127, 129, 130, 131, 134, 138, 1, 5,
1082 6, 58, 59, 64, 65, 66, 67, 68, 69, 71,
1083 74, 75, 76, 88, 90, 91, 92, 93, 105, 109,
1084 111, 112, 113, 118, 123, 47, 52, 99, 119, 99,
1085 99, 47, 52, 100, 117, 119, 53, 99, 93, 107,
1086 119, 44, 104, 104, 104, 104, 47, 47, 83, 84,
1087 52, 54, 50, 0, 81, 11, 20, 22, 23, 24,
1088 25, 26, 27, 28, 29, 30, 31, 85, 99, 34,
1089 35, 36, 37, 38, 42, 43, 13, 14, 15, 16,
1090 17, 18, 19, 13, 14, 15, 16, 17, 18, 19,
1091 13, 14, 15, 16, 17, 18, 19, 44, 11, 48,
1092 121, 41, 52, 100, 116, 119, 125, 99, 47, 88,
1093 47, 88, 8, 92, 47, 47, 92, 92, 47, 52,
1094 92, 93, 92, 92, 93, 1, 8, 91, 92, 104,
1095 91, 91, 91, 6, 93, 114, 91, 93, 104, 119,
1096 104, 104, 11, 48, 11, 48, 48, 9, 47, 135,
1097 136, 135, 47, 93, 93, 88, 88, 86, 96, 94,
1098 95, 52, 93, 93, 93, 93, 93, 93, 93, 88,
1099 89, 92, 99, 99, 99, 99, 99, 33, 99, 93,
1100 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
1101 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
1102 93, 104, 41, 93, 122, 52, 132, 133, 93, 6,
1103 52, 93, 93, 92, 104, 92, 92, 47, 93, 101,
1104 102, 106, 70, 110, 65, 6, 48, 93, 115, 9,
1105 9, 9, 93, 93, 24, 102, 48, 52, 93, 137,
1106 101, 11, 11, 93, 93, 93, 93, 125, 48, 9,
1107 11, 48, 11, 48, 24, 6, 48, 9, 48, 107,
1108 11, 12, 108, 91, 47, 48, 91, 102, 102, 102,
1109 52, 10, 11, 48, 11, 48, 48, 52, 122, 87,
1110 21, 102, 93, 52, 52, 102, 48, 93, 93, 92,
1111 93, 10, 10, 10, 44, 48, 89, 97, 10, 11,
1112 48, 128, 48, 10, 48, 93, 125, 92, 92, 48
1113 };
1114
1115 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
1116 static const yytype_uint8 yyr1[] =
1117 {
1118 0, 79, 80, 80, 81, 81, 81, 82, 82, 82,
1119 83, 82, 84, 82, 85, 82, 86, 87, 82, 88,
1120 88, 89, 89, 90, 90, 91, 91, 91, 91, 91,
1121 91, 91, 91, 92, 92, 93, 93, 93, 93, 93,
1122 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
1123 93, 93, 93, 93, 93, 93, 93, 94, 93, 95,
1124 93, 96, 97, 93, 98, 98, 99, 99, 99, 99,
1125 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1126 99, 99, 99, 99, 99, 99, 100, 101, 101, 102,
1127 102, 103, 103, 104, 91, 105, 105, 106, 106, 106,
1128 107, 107, 108, 108, 109, 91, 110, 91, 111, 91,
1129 112, 91, 91, 113, 113, 114, 114, 115, 115, 93,
1130 93, 116, 117, 99, 99, 91, 91, 118, 91, 119,
1131 119, 119, 119, 119, 99, 93, 93, 93, 93, 93,
1132 93, 93, 99, 120, 121, 121, 99, 122, 91, 91,
1133 123, 123, 99, 99, 99, 99, 99, 124, 125, 125,
1134 125, 126, 126, 99, 127, 127, 128, 128, 129, 130,
1135 131, 131, 132, 132, 133, 133, 134, 99, 99, 135,
1136 135, 136, 136, 136, 137, 137, 138
1137 };
1138
1139 /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
1140 static const yytype_uint8 yyr2[] =
1141 {
1142 0, 2, 1, 2, 1, 1, 2, 1, 1, 1,
1143 0, 3, 0, 3, 0, 3, 0, 0, 6, 3,
1144 3, 1, 1, 1, 2, 1, 2, 1, 2, 2,
1145 2, 1, 2, 1, 1, 1, 3, 3, 3, 3,
1146 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1147 3, 3, 3, 3, 3, 3, 3, 0, 4, 0,
1148 4, 0, 0, 7, 1, 2, 1, 1, 1, 3,
1149 1, 3, 3, 3, 3, 3, 3, 2, 2, 2,
1150 1, 2, 2, 2, 2, 2, 1, 0, 1, 1,
1151 3, 5, 1, 0, 5, 1, 1, 1, 3, 2,
1152 3, 3, 0, 2, 4, 2, 1, 4, 1, 7,
1153 4, 2, 4, 3, 4, 1, 2, 1, 2, 3,
1154 5, 5, 5, 5, 6, 7, 3, 6, 2, 1,
1155 2, 6, 2, 3, 1, 3, 3, 3, 3, 3,
1156 3, 3, 2, 5, 1, 3, 6, 1, 2, 3,
1157 2, 3, 1, 2, 2, 3, 4, 1, 1, 1,
1158 1, 2, 3, 6, 1, 1, 1, 3, 2, 4,
1159 2, 2, 0, 1, 1, 3, 1, 3, 3, 2,
1160 2, 1, 3, 3, 2, 2, 2
1161 };
1162
1163
1164 #define yyerrok (yyerrstatus = 0)
1165 #define yyclearin (yychar = YYEMPTY)
1166 #define YYEMPTY (-2)
1167 #define YYEOF 0
1168
1169 #define YYACCEPT goto yyacceptlab
1170 #define YYABORT goto yyabortlab
1171 #define YYERROR goto yyerrorlab
1172
1173
1174 #define YYRECOVERING() (!!yyerrstatus)
1175
1176 #define YYBACKUP(Token, Value) \
1177 do \
1178 if (yychar == YYEMPTY) \
1179 { \
1180 yychar = (Token); \
1181 yylval = (Value); \
1182 YYPOPSTACK (yylen); \
1183 yystate = *yyssp; \
1184 goto yybackup; \
1185 } \
1186 else \
1187 { \
1188 yyerror (MAWK, YY_("syntax error: cannot back up")); \
1189 YYERROR; \
1190 } \
1191 while (0)
1192
1193 /* Error token number */
1194 #define YYTERROR 1
1195 #define YYERRCODE 256
1196
1197
1198
1199 /* Enable debugging if requested. */
1200 #if YYDEBUG
1201
1202 # ifndef YYFPRINTF
1203 # include <stdio.h> /* INFRINGES ON USER NAME SPACE */
1204 # define YYFPRINTF fprintf
1205 # endif
1206
1207 # define YYDPRINTF(Args) \
1208 do { \
1209 if (yydebug) \
1210 YYFPRINTF Args; \
1211 } while (0)
1212
1213 /* This macro is provided for backward compatibility. */
1214 #ifndef YY_LOCATION_PRINT
1215 # define YY_LOCATION_PRINT(File, Loc) ((void) 0)
1216 #endif
1217
1218
1219 # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
1220 do { \
1221 if (yydebug) \
1222 { \
1223 YYFPRINTF (stderr, "%s ", Title); \
1224 yy_symbol_print (stderr, \
1225 Type, Value, MAWK); \
1226 YYFPRINTF (stderr, "\n"); \
1227 } \
1228 } while (0)
1229
1230
1231 /*----------------------------------------.
1232 | Print this symbol's value on YYOUTPUT. |
1233 `----------------------------------------*/
1234
1235 static void
1236 yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, mawk_state_t *MAWK)
1237 {
1238 FILE *yyo = yyoutput;
1239 YYUSE (yyo);
1240 YYUSE (MAWK);
1241 if (!yyvaluep)
1242 return;
1243 # ifdef YYPRINT
1244 if (yytype < YYNTOKENS)
1245 YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
1246 # endif
1247 YYUSE (yytype);
1248 }
1249
1250
1251 /*--------------------------------.
1252 | Print this symbol on YYOUTPUT. |
1253 `--------------------------------*/
1254
1255 static void
1256 yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, mawk_state_t *MAWK)
1257 {
1258 YYFPRINTF (yyoutput, "%s %s (",
1259 yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
1260
1261 yy_symbol_value_print (yyoutput, yytype, yyvaluep, MAWK);
1262 YYFPRINTF (yyoutput, ")");
1263 }
1264
1265 /*------------------------------------------------------------------.
1266 | yy_stack_print -- Print the state stack from its BOTTOM up to its |
1267 | TOP (included). |
1268 `------------------------------------------------------------------*/
1269
1270 static void
1271 yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
1272 {
1273 YYFPRINTF (stderr, "Stack now");
1274 for (; yybottom <= yytop; yybottom++)
1275 {
1276 int yybot = *yybottom;
1277 YYFPRINTF (stderr, " %d", yybot);
1278 }
1279 YYFPRINTF (stderr, "\n");
1280 }
1281
1282 # define YY_STACK_PRINT(Bottom, Top) \
1283 do { \
1284 if (yydebug) \
1285 yy_stack_print ((Bottom), (Top)); \
1286 } while (0)
1287
1288
1289 /*------------------------------------------------.
1290 | Report that the YYRULE is going to be reduced. |
1291 `------------------------------------------------*/
1292
1293 static void
1294 yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, mawk_state_t *MAWK)
1295 {
1296 unsigned long int yylno = yyrline[yyrule];
1297 int yynrhs = yyr2[yyrule];
1298 int yyi;
1299 YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
1300 yyrule - 1, yylno);
1301 /* The symbols being reduced. */
1302 for (yyi = 0; yyi < yynrhs; yyi++)
1303 {
1304 YYFPRINTF (stderr, " $%d = ", yyi + 1);
1305 yy_symbol_print (stderr,
1306 yystos[yyssp[yyi + 1 - yynrhs]],
1307 &(yyvsp[(yyi + 1) - (yynrhs)])
1308 , MAWK);
1309 YYFPRINTF (stderr, "\n");
1310 }
1311 }
1312
1313 # define YY_REDUCE_PRINT(Rule) \
1314 do { \
1315 if (yydebug) \
1316 yy_reduce_print (yyssp, yyvsp, Rule, MAWK); \
1317 } while (0)
1318
1319 /* Nonzero means print parse trace. It is left uninitialized so that
1320 multiple parsers can coexist. */
1321 int yydebug;
1322 #else /* !YYDEBUG */
1323 # define YYDPRINTF(Args)
1324 # define YY_SYMBOL_PRINT(Title, Type, Value, Location)
1325 # define YY_STACK_PRINT(Bottom, Top)
1326 # define YY_REDUCE_PRINT(Rule)
1327 #endif /* !YYDEBUG */
1328
1329
1330 /* YYINITDEPTH -- initial size of the parser's stacks. */
1331 #ifndef YYINITDEPTH
1332 # define YYINITDEPTH 200
1333 #endif
1334
1335 /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
1336 if the built-in stack extension method is used).
1337
1338 Do not make this value too large; the results are undefined if
1339 YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
1340 evaluated with infinite-precision integer arithmetic. */
1341
1342 #ifndef YYMAXDEPTH
1343 # define YYMAXDEPTH 10000
1344 #endif
1345
1346
1347 #if YYERROR_VERBOSE
1348
1349 # ifndef yystrlen
1350 # if defined __GLIBC__ && defined _STRING_H
1351 # define yystrlen strlen
1352 # else
1353 /* Return the length of YYSTR. */
1354 static YYSIZE_T
1355 yystrlen (const char *yystr)
1356 {
1357 YYSIZE_T yylen;
1358 for (yylen = 0; yystr[yylen]; yylen++)
1359 continue;
1360 return yylen;
1361 }
1362 # endif
1363 # endif
1364
1365 # ifndef yystpcpy
1366 # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
1367 # define yystpcpy stpcpy
1368 # else
1369 /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
1370 YYDEST. */
1371 static char *
1372 yystpcpy (char *yydest, const char *yysrc)
1373 {
1374 char *yyd = yydest;
1375 const char *yys = yysrc;
1376
1377 while ((*yyd++ = *yys++) != '\0')
1378 continue;
1379
1380 return yyd - 1;
1381 }
1382 # endif
1383 # endif
1384
1385 # ifndef yytnamerr
1386 /* Copy to YYRES the contents of YYSTR after stripping away unnecessary
1387 quotes and backslashes, so that it's suitable for yyerror. The
1388 heuristic is that double-quoting is unnecessary unless the string
1389 contains an apostrophe, a comma, or backslash (other than
1390 backslash-backslash). YYSTR is taken from yytname. If YYRES is
1391 null, do not copy; instead, return the length of what the result
1392 would have been. */
1393 static YYSIZE_T
1394 yytnamerr (char *yyres, const char *yystr)
1395 {
1396 if (*yystr == '"')
1397 {
1398 YYSIZE_T yyn = 0;
1399 char const *yyp = yystr;
1400
1401 for (;;)
1402 switch (*++yyp)
1403 {
1404 case '\'':
1405 case ',':
1406 goto do_not_strip_quotes;
1407
1408 case '\\':
1409 if (*++yyp != '\\')
1410 goto do_not_strip_quotes;
1411 /* Fall through. */
1412 default:
1413 if (yyres)
1414 yyres[yyn] = *yyp;
1415 yyn++;
1416 break;
1417
1418 case '"':
1419 if (yyres)
1420 yyres[yyn] = '\0';
1421 return yyn;
1422 }
1423 do_not_strip_quotes: ;
1424 }
1425
1426 if (! yyres)
1427 return yystrlen (yystr);
1428
1429 return yystpcpy (yyres, yystr) - yyres;
1430 }
1431 # endif
1432
1433 /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
1434 about the unexpected token YYTOKEN for the state stack whose top is
1435 YYSSP.
1436
1437 Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
1438 not large enough to hold the message. In that case, also set
1439 *YYMSG_ALLOC to the required number of bytes. Return 2 if the
1440 required number of bytes is too large to store. */
1441 static int
1442 yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
1443 yytype_int16 *yyssp, int yytoken)
1444 {
1445 YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
1446 YYSIZE_T yysize = yysize0;
1447 enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
1448 /* Internationalized format string. */
1449 const char *yyformat = YY_NULLPTR;
1450 /* Arguments of yyformat. */
1451 char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
1452 /* Number of reported tokens (one for the "unexpected", one per
1453 "expected"). */
1454 int yycount = 0;
1455
1456 /* There are many possibilities here to consider:
1457 - If this state is a consistent state with a default action, then
1458 the only way this function was invoked is if the default action
1459 is an error action. In that case, don't check for expected
1460 tokens because there are none.
1461 - The only way there can be no lookahead present (in yychar) is if
1462 this state is a consistent state with a default action. Thus,
1463 detecting the absence of a lookahead is sufficient to determine
1464 that there is no unexpected or expected token to report. In that
1465 case, just report a simple "syntax error".
1466 - Don't assume there isn't a lookahead just because this state is a
1467 consistent state with a default action. There might have been a
1468 previous inconsistent state, consistent state with a non-default
1469 action, or user semantic action that manipulated yychar.
1470 - Of course, the expected token list depends on states to have
1471 correct lookahead information, and it depends on the parser not
1472 to perform extra reductions after fetching a lookahead from the
1473 scanner and before detecting a syntax error. Thus, state merging
1474 (from LALR or IELR) and default reductions corrupt the expected
1475 token list. However, the list is correct for canonical LR with
1476 one exception: it will still contain any token that will not be
1477 accepted due to an error action in a later state.
1478 */
1479 if (yytoken != YYEMPTY)
1480 {
1481 int yyn = yypact[*yyssp];
1482 yyarg[yycount++] = yytname[yytoken];
1483 if (!yypact_value_is_default (yyn))
1484 {
1485 /* Start YYX at -YYN if negative to avoid negative indexes in
1486 YYCHECK. In other words, skip the first -YYN actions for
1487 this state because they are default actions. */
1488 int yyxbegin = yyn < 0 ? -yyn : 0;
1489 /* Stay within bounds of both yycheck and yytname. */
1490 int yychecklim = YYLAST - yyn + 1;
1491 int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
1492 int yyx;
1493
1494 for (yyx = yyxbegin; yyx < yyxend; ++yyx)
1495 if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
1496 && !yytable_value_is_error (yytable[yyx + yyn]))
1497 {
1498 if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
1499 {
1500 yycount = 1;
1501 yysize = yysize0;
1502 break;
1503 }
1504 yyarg[yycount++] = yytname[yyx];
1505 {
1506 YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
1507 if (! (yysize <= yysize1
1508 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
1509 return 2;
1510 yysize = yysize1;
1511 }
1512 }
1513 }
1514 }
1515
1516 switch (yycount)
1517 {
1518 # define YYCASE_(N, S) \
1519 case N: \
1520 yyformat = S; \
1521 break
1522 YYCASE_(0, YY_("syntax error"));
1523 YYCASE_(1, YY_("syntax error, unexpected %s"));
1524 YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
1525 YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
1526 YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
1527 YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
1528 # undef YYCASE_
1529 }
1530
1531 {
1532 YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
1533 if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
1534 return 2;
1535 yysize = yysize1;
1536 }
1537
1538 if (*yymsg_alloc < yysize)
1539 {
1540 *yymsg_alloc = 2 * yysize;
1541 if (! (yysize <= *yymsg_alloc
1542 && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
1543 *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
1544 return 1;
1545 }
1546
1547 /* Avoid sprintf, as that infringes on the user's name space.
1548 Don't have undefined behavior even if the translation
1549 produced a string with the wrong number of "%s"s. */
1550 {
1551 char *yyp = *yymsg;
1552 int yyi = 0;
1553 while ((*yyp = *yyformat) != '\0')
1554 if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
1555 {
1556 yyp += yytnamerr (yyp, yyarg[yyi++]);
1557 yyformat += 2;
1558 }
1559 else
1560 {
1561 yyp++;
1562 yyformat++;
1563 }
1564 }
1565 return 0;
1566 }
1567 #endif /* YYERROR_VERBOSE */
1568
1569 /*-----------------------------------------------.
1570 | Release the memory associated to this symbol. |
1571 `-----------------------------------------------*/
1572
1573 static void
1574 yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, mawk_state_t *MAWK)
1575 {
1576 YYUSE (yyvaluep);
1577 YYUSE (MAWK);
1578 if (!yymsg)
1579 yymsg = "Deleting";
1580 YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
1581
1582 YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
1583 YYUSE (yytype);
1584 YY_IGNORE_MAYBE_UNINITIALIZED_END
1585 }
1586
1587
1588
1589
1590 /*----------.
1591 | yyparse. |
1592 `----------*/
1593
1594 int
1595 yyparse (mawk_state_t *MAWK)
1596 {
1597 /* The lookahead symbol. */
1598 int yychar;
1599
1600
1601 /* The semantic value of the lookahead symbol. */
1602 /* Default value used for initialization, for pacifying older GCCs
1603 or non-GCC compilers. */
1604 YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
1605 YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
1606
1607 /* Number of syntax errors so far. */
1608 int yynerrs;
1609
1610 int yystate;
1611 /* Number of tokens to shift before error messages enabled. */
1612 int yyerrstatus;
1613
1614 /* The stacks and their tools:
1615 'yyss': related to states.
1616 'yyvs': related to semantic values.
1617
1618 Refer to the stacks through separate pointers, to allow yyoverflow
1619 to reallocate them elsewhere. */
1620
1621 /* The state stack. */
1622 yytype_int16 yyssa[YYINITDEPTH];
1623 yytype_int16 *yyss;
1624 yytype_int16 *yyssp;
1625
1626 /* The semantic value stack. */
1627 YYSTYPE yyvsa[YYINITDEPTH];
1628 YYSTYPE *yyvs;
1629 YYSTYPE *yyvsp;
1630
1631 YYSIZE_T yystacksize;
1632
1633 int yyn;
1634 int yyresult;
1635 /* Lookahead token as an internal (translated) token number. */
1636 int yytoken = 0;
1637 /* The variables used to return semantic value and location from the
1638 action routines. */
1639 YYSTYPE yyval;
1640
1641 #if YYERROR_VERBOSE
1642 /* Buffer for error messages, and its allocated size. */
1643 char yymsgbuf[128];
1644 char *yymsg = yymsgbuf;
1645 YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
1646 #endif
1647
1648 #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
1649
1650 /* The number of symbols on the RHS of the reduced rule.
1651 Keep to zero when no symbol should be popped. */
1652 int yylen = 0;
1653
1654 yyssp = yyss = yyssa;
1655 yyvsp = yyvs = yyvsa;
1656 yystacksize = YYINITDEPTH;
1657
1658 YYDPRINTF ((stderr, "Starting parse\n"));
1659
1660 yystate = 0;
1661 yyerrstatus = 0;
1662 yynerrs = 0;
1663 yychar = YYEMPTY; /* Cause a token to be read. */
1664 goto yysetstate;
1665
1666 /*------------------------------------------------------------.
1667 | yynewstate -- Push a new state, which is found in yystate. |
1668 `------------------------------------------------------------*/
1669 yynewstate:
1670 /* In all cases, when you get here, the value and location stacks
1671 have just been pushed. So pushing a state here evens the stacks. */
1672 yyssp++;
1673
1674 yysetstate:
1675 *yyssp = yystate;
1676
1677 if (yyss + yystacksize - 1 <= yyssp)
1678 {
1679 /* Get the current used size of the three stacks, in elements. */
1680 YYSIZE_T yysize = yyssp - yyss + 1;
1681
1682 #ifdef yyoverflow
1683 {
1684 /* Give user a chance to reallocate the stack. Use copies of
1685 these so that the &'s don't force the real ones into
1686 memory. */
1687 YYSTYPE *yyvs1 = yyvs;
1688 yytype_int16 *yyss1 = yyss;
1689
1690 /* Each stack pointer address is followed by the size of the
1691 data in use in that stack, in bytes. This used to be a
1692 conditional around just the two extra args, but that might
1693 be undefined if yyoverflow is a macro. */
1694 yyoverflow (YY_("memory exhausted"),
1695 &yyss1, yysize * sizeof (*yyssp),
1696 &yyvs1, yysize * sizeof (*yyvsp),
1697 &yystacksize);
1698
1699 yyss = yyss1;
1700 yyvs = yyvs1;
1701 }
1702 #else /* no yyoverflow */
1703 # ifndef YYSTACK_RELOCATE
1704 goto yyexhaustedlab;
1705 # else
1706 /* Extend the stack our own way. */
1707 if (YYMAXDEPTH <= yystacksize)
1708 goto yyexhaustedlab;
1709 yystacksize *= 2;
1710 if (YYMAXDEPTH < yystacksize)
1711 yystacksize = YYMAXDEPTH;
1712
1713 {
1714 yytype_int16 *yyss1 = yyss;
1715 union yyalloc *yyptr =
1716 (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
1717 if (! yyptr)
1718 goto yyexhaustedlab;
1719 YYSTACK_RELOCATE (yyss_alloc, yyss);
1720 YYSTACK_RELOCATE (yyvs_alloc, yyvs);
1721 # undef YYSTACK_RELOCATE
1722 if (yyss1 != yyssa)
1723 YYSTACK_FREE (yyss1);
1724 }
1725 # endif
1726 #endif /* no yyoverflow */
1727
1728 yyssp = yyss + yysize - 1;
1729 yyvsp = yyvs + yysize - 1;
1730
1731 YYDPRINTF ((stderr, "Stack size increased to %lu\n",
1732 (unsigned long int) yystacksize));
1733
1734 if (yyss + yystacksize - 1 <= yyssp)
1735 YYABORT;
1736 }
1737
1738 YYDPRINTF ((stderr, "Entering state %d\n", yystate));
1739
1740 if (yystate == YYFINAL)
1741 YYACCEPT;
1742
1743 goto yybackup;
1744
1745 /*-----------.
1746 | yybackup. |
1747 `-----------*/
1748 yybackup:
1749
1750 /* Do appropriate processing given the current state. Read a
1751 lookahead token if we need one and don't already have one. */
1752
1753 /* First try to decide what to do without reference to lookahead token. */
1754 yyn = yypact[yystate];
1755 if (yypact_value_is_default (yyn))
1756 goto yydefault;
1757
1758 /* Not known => get a lookahead token if don't already have one. */
1759
1760 /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
1761 if (yychar == YYEMPTY)
1762 {
1763 YYDPRINTF ((stderr, "Reading a token: "));
1764 yychar = yylex (&yylval, MAWK);
1765 }
1766
1767 if (yychar <= YYEOF)
1768 {
1769 yychar = yytoken = YYEOF;
1770 YYDPRINTF ((stderr, "Now at end of input.\n"));
1771 }
1772 else
1773 {
1774 yytoken = YYTRANSLATE (yychar);
1775 YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
1776 }
1777
1778 /* If the proper action on seeing token YYTOKEN is to reduce or to
1779 detect an error, take that action. */
1780 yyn += yytoken;
1781 if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
1782 goto yydefault;
1783 yyn = yytable[yyn];
1784 if (yyn <= 0)
1785 {
1786 if (yytable_value_is_error (yyn))
1787 goto yyerrlab;
1788 yyn = -yyn;
1789 goto yyreduce;
1790 }
1791
1792 /* Count tokens shifted since error; after three, turn off error
1793 status. */
1794 if (yyerrstatus)
1795 yyerrstatus--;
1796
1797 /* Shift the lookahead token. */
1798 YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
1799
1800 /* Discard the shifted token. */
1801 yychar = YYEMPTY;
1802
1803 yystate = yyn;
1804 YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
1805 *++yyvsp = yylval;
1806 YY_IGNORE_MAYBE_UNINITIALIZED_END
1807
1808 goto yynewstate;
1809
1810
1811 /*-----------------------------------------------------------.
1812 | yydefault -- do the default action for the current state. |
1813 `-----------------------------------------------------------*/
1814 yydefault:
1815 yyn = yydefact[yystate];
1816 if (yyn == 0)
1817 goto yyerrlab;
1818 goto yyreduce;
1819
1820
1821 /*-----------------------------.
1822 | yyreduce -- Do a reduction. |
1823 `-----------------------------*/
1824 yyreduce:
1825 /* yyn is the number of a rule to reduce with. */
1826 yylen = yyr2[yyn];
1827
1828 /* If YYLEN is nonzero, implement the default value of the action:
1829 '$$ = $1'.
1830
1831 Otherwise, the following line sets YYVAL to garbage.
1832 This behavior is undocumented and Bison
1833 users should not rely upon it. Assigning to YYVAL
1834 unconditionally makes the parser a bit smaller, and it avoids a
1835 GCC warning that YYVAL may be used uninitialized. */
1836 yyval = yyvsp[1-yylen];
1837
1838
1839 YY_REDUCE_PRINT (yyn);
1840 switch (yyn)
1841 {
1842 case 7:
1843 #line 223 "parse.y" /* yacc.c:1646 */
1844 { /* this do nothing action removes a vacuous warning
1845 from Bison */
1846 }
1847 #line 1849 "y.tab.c" /* yacc.c:1646 */
1848 break;
1849
1850 case 10:
1851 #line 232 "parse.y" /* yacc.c:1646 */
1852 { mawk_be_setup(MAWK, MAWK->scope = SCOPE_BEGIN) ; }
1853 #line 1855 "y.tab.c" /* yacc.c:1646 */
1854 break;
1855
1856 case 11:
1857 #line 235 "parse.y" /* yacc.c:1646 */
1858 { switch_code_to_main(MAWK) ; }
1859 #line 1861 "y.tab.c" /* yacc.c:1646 */
1860 break;
1861
1862 case 12:
1863 #line 238 "parse.y" /* yacc.c:1646 */
1864 { mawk_be_setup(MAWK, MAWK->scope = SCOPE_END) ; }
1865 #line 1867 "y.tab.c" /* yacc.c:1646 */
1866 break;
1867
1868 case 13:
1869 #line 241 "parse.y" /* yacc.c:1646 */
1870 { switch_code_to_main(MAWK) ; }
1871 #line 1873 "y.tab.c" /* yacc.c:1646 */
1872 break;
1873
1874 case 14:
1875 #line 244 "parse.y" /* yacc.c:1646 */
1876 { mawk_code_jmp(MAWK, _JZ, (INST*)0) ; }
1877 #line 1879 "y.tab.c" /* yacc.c:1646 */
1878 break;
1879
1880 case 15:
1881 #line 247 "parse.y" /* yacc.c:1646 */
1882 { mawk_patch_jmp(MAWK, mawk_code_ptr ) ; }
1883 #line 1885 "y.tab.c" /* yacc.c:1646 */
1884 break;
1885
1886 case 16:
1887 #line 251 "parse.y" /* yacc.c:1646 */
1888 {
1889 INST *p1 = CDP((yyvsp[-1].start)) ;
1890 int len ;
1891
1892 mawk_code_push(MAWK, p1, mawk_code_ptr - p1, MAWK->scope, MAWK->active_funct) ;
1893 mawk_code_ptr = p1 ;
1894
1895 mawk_code2op(MAWK, _RANGE_CHK, 1) ;
1896 mawk_code_ptr += 3 ;
1897 len = mawk_code_pop(MAWK, mawk_code_ptr) ;
1898 mawk_code_ptr += len ;
1899 code1(_RANGE_STOP) ;
1900 p1 = CDP((yyvsp[-1].start)) ;
1901 p1[2].op = mawk_code_ptr - (p1+1) ;
1902 }
1903 #line 1905 "y.tab.c" /* yacc.c:1646 */
1904 break;
1905
1906 case 17:
1907 #line 267 "parse.y" /* yacc.c:1646 */
1908 { code1(_RANGE_STOP) ; }
1909 #line 1911 "y.tab.c" /* yacc.c:1646 */
1910 break;
1911
1912 case 18:
1913 #line 270 "parse.y" /* yacc.c:1646 */
1914 {
1915 INST *p1 = CDP((yyvsp[-5].start)) ;
1916
1917 p1[3].op = CDP((yyvsp[0].start)) - (p1+1) ;
1918 p1[4].op = mawk_code_ptr - (p1+1) ;
1919 }
1920 #line 1922 "y.tab.c" /* yacc.c:1646 */
1921 break;
1922
1923 case 19:
1924 #line 281 "parse.y" /* yacc.c:1646 */
1925 { (yyval.start) = (yyvsp[-1].start) ; }
1926 #line 1928 "y.tab.c" /* yacc.c:1646 */
1927 break;
1928
1929 case 20:
1930 #line 283 "parse.y" /* yacc.c:1646 */
1931 { (yyval.start) = mawk_code_offset ; /* does nothing won't be mawk_executed */
1932 MAWK->print_flag = MAWK->getline_flag = MAWK->paren_cnt = 0 ;
1933 yyerrok ; }
1934 #line 1936 "y.tab.c" /* yacc.c:1646 */
1935 break;
1936
1937 case 22:
1938 #line 290 "parse.y" /* yacc.c:1646 */
1939 { (yyval.start) = mawk_code_offset ;
1940 code1(_PUSHINT) ; code1(0) ;
1941 code2(MAWK, _PRINT, mawk_f2d(mawk_bi_print)) ;
1942 }
1943 #line 1945 "y.tab.c" /* yacc.c:1646 */
1944 break;
1945
1946 case 26:
1947 #line 302 "parse.y" /* yacc.c:1646 */
1948 { code1(_POP) ; }
1949 #line 1951 "y.tab.c" /* yacc.c:1646 */
1950 break;
1951
1952 case 27:
1953 #line 304 "parse.y" /* yacc.c:1646 */
1954 { (yyval.start) = mawk_code_offset ; }
1955 #line 1957 "y.tab.c" /* yacc.c:1646 */
1956 break;
1957
1958 case 28:
1959 #line 306 "parse.y" /* yacc.c:1646 */
1960 { (yyval.start) = mawk_code_offset ;
1961 MAWK->print_flag = MAWK->getline_flag = 0 ;
1962 MAWK->paren_cnt = 0 ;
1963 yyerrok ;
1964 }
1965 #line 1967 "y.tab.c" /* yacc.c:1646 */
1966 break;
1967
1968 case 29:
1969 #line 312 "parse.y" /* yacc.c:1646 */
1970 { (yyval.start) = mawk_code_offset ; mawk_BC_insert(MAWK, 'B', mawk_code_ptr+1) ;
1971 code2(MAWK, _JMP, 0) /* don't use mawk_code_jmp ! */ ; }
1972 #line 1974 "y.tab.c" /* yacc.c:1646 */
1973 break;
1974
1975 case 30:
1976 #line 315 "parse.y" /* yacc.c:1646 */
1977 { (yyval.start) = mawk_code_offset ; mawk_BC_insert(MAWK, 'C', mawk_code_ptr+1) ;
1978 code2(MAWK, _JMP, 0) ; }
1979 #line 1981 "y.tab.c" /* yacc.c:1646 */
1980 break;
1981
1982 case 31:
1983 #line 318 "parse.y" /* yacc.c:1646 */
1984 { if ( MAWK->scope != SCOPE_FUNCT )
1985 mawk_compile_error(MAWK, "return outside function body") ;
1986 }
1987 #line 1989 "y.tab.c" /* yacc.c:1646 */
1988 break;
1989
1990 case 32:
1991 #line 322 "parse.y" /* yacc.c:1646 */
1992 { if ( MAWK->scope != SCOPE_MAIN )
1993 mawk_compile_error(MAWK, "improper use of next" ) ;
1994 (yyval.start) = mawk_code_offset ;
1995 code1(_NEXT) ;
1996 }
1997 #line 1999 "y.tab.c" /* yacc.c:1646 */
1998 break;
1999
2000 case 36:
2001 #line 333 "parse.y" /* yacc.c:1646 */
2002 { code1(_ASSIGN) ; }
2003 #line 2005 "y.tab.c" /* yacc.c:1646 */
2004 break;
2005
2006 case 37:
2007 #line 334 "parse.y" /* yacc.c:1646 */
2008 { code1(_ADD_ASG) ; }
2009 #line 2011 "y.tab.c" /* yacc.c:1646 */
2010 break;
2011
2012 case 38:
2013 #line 335 "parse.y" /* yacc.c:1646 */
2014 { code1(_SUB_ASG) ; }
2015 #line 2017 "y.tab.c" /* yacc.c:1646 */
2016 break;
2017
2018 case 39:
2019 #line 336 "parse.y" /* yacc.c:1646 */
2020 { code1(_MUL_ASG) ; }
2021 #line 2023 "y.tab.c" /* yacc.c:1646 */
2022 break;
2023
2024 case 40:
2025 #line 337 "parse.y" /* yacc.c:1646 */
2026 { code1(_DIV_ASG) ; }
2027 #line 2029 "y.tab.c" /* yacc.c:1646 */
2028 break;
2029
2030 case 41:
2031 #line 338 "parse.y" /* yacc.c:1646 */
2032 { code1(_MOD_ASG) ; }
2033 #line 2035 "y.tab.c" /* yacc.c:1646 */
2034 break;
2035
2036 case 42:
2037 #line 339 "parse.y" /* yacc.c:1646 */
2038 { code1(_POW_ASG) ; }
2039 #line 2041 "y.tab.c" /* yacc.c:1646 */
2040 break;
2041
2042 case 43:
2043 #line 340 "parse.y" /* yacc.c:1646 */
2044 { code1(_ASSIGN_ARR) ; }
2045 #line 2047 "y.tab.c" /* yacc.c:1646 */
2046 break;
2047
2048 case 44:
2049 #line 341 "parse.y" /* yacc.c:1646 */
2050 { code1(_ADD_ASG_ARR) ; }
2051 #line 2053 "y.tab.c" /* yacc.c:1646 */
2052 break;
2053
2054 case 45:
2055 #line 342 "parse.y" /* yacc.c:1646 */
2056 { code1(_SUB_ASG_ARR) ; }
2057 #line 2059 "y.tab.c" /* yacc.c:1646 */
2058 break;
2059
2060 case 46:
2061 #line 343 "parse.y" /* yacc.c:1646 */
2062 { code1(_MUL_ASG_ARR) ; }
2063 #line 2065 "y.tab.c" /* yacc.c:1646 */
2064 break;
2065
2066 case 47:
2067 #line 344 "parse.y" /* yacc.c:1646 */
2068 { code1(_DIV_ASG_ARR) ; }
2069 #line 2071 "y.tab.c" /* yacc.c:1646 */
2070 break;
2071
2072 case 48:
2073 #line 345 "parse.y" /* yacc.c:1646 */
2074 { code1(_MOD_ASG_ARR) ; }
2075 #line 2077 "y.tab.c" /* yacc.c:1646 */
2076 break;
2077
2078 case 49:
2079 #line 346 "parse.y" /* yacc.c:1646 */
2080 { code1(_POW_ASG_ARR) ; }
2081 #line 2083 "y.tab.c" /* yacc.c:1646 */
2082 break;
2083
2084 case 50:
2085 #line 347 "parse.y" /* yacc.c:1646 */
2086 { code1(_EQ) ; }
2087 #line 2089 "y.tab.c" /* yacc.c:1646 */
2088 break;
2089
2090 case 51:
2091 #line 348 "parse.y" /* yacc.c:1646 */
2092 { code1(_NEQ) ; }
2093 #line 2095 "y.tab.c" /* yacc.c:1646 */
2094 break;
2095
2096 case 52:
2097 #line 349 "parse.y" /* yacc.c:1646 */
2098 { code1(_LT) ; }
2099 #line 2101 "y.tab.c" /* yacc.c:1646 */
2100 break;
2101
2102 case 53:
2103 #line 350 "parse.y" /* yacc.c:1646 */
2104 { code1(_LTE) ; }
2105 #line 2107 "y.tab.c" /* yacc.c:1646 */
2106 break;
2107
2108 case 54:
2109 #line 351 "parse.y" /* yacc.c:1646 */
2110 { code1(_GT) ; }
2111 #line 2113 "y.tab.c" /* yacc.c:1646 */
2112 break;
2113
2114 case 55:
2115 #line 352 "parse.y" /* yacc.c:1646 */
2116 { code1(_GTE) ; }
2117 #line 2119 "y.tab.c" /* yacc.c:1646 */
2118 break;
2119
2120 case 56:
2121 #line 355 "parse.y" /* yacc.c:1646 */
2122 {
2123 INST *p3 = CDP((yyvsp[0].start)) ;
2124
2125 if ( p3 == mawk_code_ptr - 2 )
2126 {
2127 if ( p3->op == _MATCH0 ) p3->op = _MATCH1 ;
2128
2129 else /* check for string */
2130 if ( p3->op == _PUSHS )
2131 {
2132 mawk_cell_t *cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
2133
2134 cp->type = C_STRING ;
2135 cp->ptr = p3[1].ptr ;
2136 mawk_cast_to_RE(MAWK, cp) ;
2137 mawk_code_ptr -= 2 ;
2138 code2(MAWK, _MATCH1, cp->ptr) ;
2139 MAWK_ZFREE(MAWK, cp) ;
2140 }
2141 else code1(_MATCH2) ;
2142 }
2143 else code1(_MATCH2) ;
2144
2145 if ( !(yyvsp[-1].ival) ) code1(_NOT) ;
2146 }
2147 #line 2149 "y.tab.c" /* yacc.c:1646 */
2148 break;
2149
2150 case 57:
2151 #line 383 "parse.y" /* yacc.c:1646 */
2152 { code1(_TEST) ;
2153 mawk_code_jmp(MAWK, _LJNZ, (INST*)0) ;
2154 }
2155 #line 2157 "y.tab.c" /* yacc.c:1646 */
2156 break;
2157
2158 case 58:
2159 #line 387 "parse.y" /* yacc.c:1646 */
2160 { code1(_TEST) ; mawk_patch_jmp(MAWK, mawk_code_ptr) ; }
2161 #line 2163 "y.tab.c" /* yacc.c:1646 */
2162 break;
2163
2164 case 59:
2165 #line 390 "parse.y" /* yacc.c:1646 */
2166 { code1(_TEST) ;
2167 mawk_code_jmp(MAWK, _LJZ, (INST*)0) ;
2168 }
2169 #line 2171 "y.tab.c" /* yacc.c:1646 */
2170 break;
2171
2172 case 60:
2173 #line 394 "parse.y" /* yacc.c:1646 */
2174 { code1(_TEST) ; mawk_patch_jmp(MAWK, mawk_code_ptr) ; }
2175 #line 2177 "y.tab.c" /* yacc.c:1646 */
2176 break;
2177
2178 case 61:
2179 #line 396 "parse.y" /* yacc.c:1646 */
2180 { mawk_code_jmp(MAWK, _JZ, (INST*)0) ; }
2181 #line 2183 "y.tab.c" /* yacc.c:1646 */
2182 break;
2183
2184 case 62:
2185 #line 397 "parse.y" /* yacc.c:1646 */
2186 { mawk_code_jmp(MAWK, _JMP, (INST*)0) ; }
2187 #line 2189 "y.tab.c" /* yacc.c:1646 */
2188 break;
2189
2190 case 63:
2191 #line 399 "parse.y" /* yacc.c:1646 */
2192 { mawk_patch_jmp(MAWK, mawk_code_ptr) ; mawk_patch_jmp(MAWK, CDP((yyvsp[0].start))) ; }
2193 #line 2195 "y.tab.c" /* yacc.c:1646 */
2194 break;
2195
2196 case 65:
2197 #line 404 "parse.y" /* yacc.c:1646 */
2198 { code1(_CAT) ; }
2199 #line 2201 "y.tab.c" /* yacc.c:1646 */
2200 break;
2201
2202 case 66:
2203 #line 408 "parse.y" /* yacc.c:1646 */
2204 { (yyval.start) = mawk_code_offset ; code2(MAWK, _PUSHD, (yyvsp[0].ptr)) ; }
2205 #line 2207 "y.tab.c" /* yacc.c:1646 */
2206 break;
2207
2208 case 67:
2209 #line 410 "parse.y" /* yacc.c:1646 */
2210 { (yyval.start) = mawk_code_offset ; code2(MAWK, _PUSHS, (yyvsp[0].ptr)) ; }
2211 #line 2213 "y.tab.c" /* yacc.c:1646 */
2212 break;
2213
2214 case 68:
2215 #line 412 "parse.y" /* yacc.c:1646 */
2216 { check_var(MAWK, (yyvsp[0].stp)) ;
2217 (yyval.start) = mawk_code_offset ;
2218 if ( is_local((yyvsp[0].stp)) )
2219 { mawk_code2op(MAWK, L_PUSHI, (yyvsp[0].stp)->offset) ; }
2220 else code2(MAWK, _PUSHI, (yyvsp[0].stp)->stval.cp) ;
2221 }
2222 #line 2224 "y.tab.c" /* yacc.c:1646 */
2223 break;
2224
2225 case 69:
2226 #line 420 "parse.y" /* yacc.c:1646 */
2227 { (yyval.start) = (yyvsp[-1].start) ; }
2228 #line 2230 "y.tab.c" /* yacc.c:1646 */
2229 break;
2230
2231 case 70:
2232 #line 424 "parse.y" /* yacc.c:1646 */
2233 { (yyval.start) = mawk_code_offset ; code2(MAWK, _MATCH0, (yyvsp[0].ptr)) ; }
2234 #line 2236 "y.tab.c" /* yacc.c:1646 */
2235 break;
2236
2237 case 71:
2238 #line 427 "parse.y" /* yacc.c:1646 */
2239 { code1(_ADD) ; }
2240 #line 2242 "y.tab.c" /* yacc.c:1646 */
2241 break;
2242
2243 case 72:
2244 #line 428 "parse.y" /* yacc.c:1646 */
2245 { code1(_SUB) ; }
2246 #line 2248 "y.tab.c" /* yacc.c:1646 */
2247 break;
2248
2249 case 73:
2250 #line 429 "parse.y" /* yacc.c:1646 */
2251 { code1(_MUL) ; }
2252 #line 2254 "y.tab.c" /* yacc.c:1646 */
2253 break;
2254
2255 case 74:
2256 #line 430 "parse.y" /* yacc.c:1646 */
2257 { code1(_DIV) ; }
2258 #line 2260 "y.tab.c" /* yacc.c:1646 */
2259 break;
2260
2261 case 75:
2262 #line 431 "parse.y" /* yacc.c:1646 */
2263 { code1(_MOD) ; }
2264 #line 2266 "y.tab.c" /* yacc.c:1646 */
2265 break;
2266
2267 case 76:
2268 #line 432 "parse.y" /* yacc.c:1646 */
2269 { code1(_POW) ; }
2270 #line 2272 "y.tab.c" /* yacc.c:1646 */
2271 break;
2272
2273 case 77:
2274 #line 434 "parse.y" /* yacc.c:1646 */
2275 { (yyval.start) = (yyvsp[0].start) ; code1(_NOT) ; }
2276 #line 2278 "y.tab.c" /* yacc.c:1646 */
2277 break;
2278
2279 case 78:
2280 #line 436 "parse.y" /* yacc.c:1646 */
2281 { (yyval.start) = (yyvsp[0].start) ; code1(_UPLUS) ; }
2282 #line 2284 "y.tab.c" /* yacc.c:1646 */
2283 break;
2284
2285 case 79:
2286 #line 438 "parse.y" /* yacc.c:1646 */
2287 { (yyval.start) = (yyvsp[0].start) ; code1(_UMINUS) ; }
2288 #line 2290 "y.tab.c" /* yacc.c:1646 */
2289 break;
2290
2291 case 81:
2292 #line 443 "parse.y" /* yacc.c:1646 */
2293 { check_var(MAWK, (yyvsp[-1].stp)) ;
2294 (yyval.start) = mawk_code_offset ;
2295 mawk_code_address((yyvsp[-1].stp)) ;
2296
2297 if ( (yyvsp[0].ival) == '+' ) code1(_POST_INC) ;
2298 else code1(_POST_DEC) ;
2299 }
2300 #line 2302 "y.tab.c" /* yacc.c:1646 */
2301 break;
2302
2303 case 82:
2304 #line 451 "parse.y" /* yacc.c:1646 */
2305 { (yyval.start) = (yyvsp[0].start) ;
2306 if ( (yyvsp[-1].ival) == '+' ) code1(_PRE_INC) ;
2307 else code1(_PRE_DEC) ;
2308 }
2309 #line 2311 "y.tab.c" /* yacc.c:1646 */
2310 break;
2311
2312 case 83:
2313 #line 456 "parse.y" /* yacc.c:1646 */
2314 { (yyval.start) = (yyvsp[0].start) ;
2315 if ( (yyvsp[-1].ival) == '+' ) code1(_PRE_INC_ARR) ;
2316 else code1(_PRE_DEC_ARR) ;
2317 }
2318 #line 2320 "y.tab.c" /* yacc.c:1646 */
2319 break;
2320
2321 case 84:
2322 #line 463 "parse.y" /* yacc.c:1646 */
2323 { if ((yyvsp[0].ival) == '+' ) code1(F_POST_INC ) ;
2324 else code1(F_POST_DEC) ;
2325 }
2326 #line 2328 "y.tab.c" /* yacc.c:1646 */
2327 break;
2328
2329 case 85:
2330 #line 467 "parse.y" /* yacc.c:1646 */
2331 { (yyval.start) = (yyvsp[0].start) ;
2332 if ( (yyvsp[-1].ival) == '+' ) code1(F_PRE_INC) ;
2333 else code1( F_PRE_DEC) ;
2334 }
2335 #line 2337 "y.tab.c" /* yacc.c:1646 */
2336 break;
2337
2338 case 86:
2339 #line 474 "parse.y" /* yacc.c:1646 */
2340 { (yyval.start) = mawk_code_offset ;
2341 check_var(MAWK, (yyvsp[0].stp)) ;
2342 mawk_code_address((yyvsp[0].stp)) ;
2343 }
2344 #line 2346 "y.tab.c" /* yacc.c:1646 */
2345 break;
2346
2347 case 87:
2348 #line 482 "parse.y" /* yacc.c:1646 */
2349 { (yyval.ival) = 0 ; }
2350 #line 2352 "y.tab.c" /* yacc.c:1646 */
2351 break;
2352
2353 case 89:
2354 #line 487 "parse.y" /* yacc.c:1646 */
2355 { (yyval.ival) = 1 ; }
2356 #line 2358 "y.tab.c" /* yacc.c:1646 */
2357 break;
2358
2359 case 90:
2360 #line 489 "parse.y" /* yacc.c:1646 */
2361 { (yyval.ival) = (yyvsp[-2].ival) + 1 ; }
2362 #line 2364 "y.tab.c" /* yacc.c:1646 */
2363 break;
2364
2365 case 91:
2366 #line 494 "parse.y" /* yacc.c:1646 */
2367 { const BI_REC *p = (yyvsp[-4].bip) ;
2368 (yyval.start) = (yyvsp[-3].start) ;
2369 if ( (int)p->min_args > (yyvsp[-1].ival) || (int)p->max_args < (yyvsp[-1].ival) )
2370 mawk_compile_error(
2371 MAWK, "wrong number of arguments in call to %s" ,
2372 p->name ) ;
2373 if ( p->min_args != p->max_args ) /* variable args */
2374 { code1(_PUSHINT) ; code1((yyvsp[-1].ival)) ; }
2375 code2(MAWK, _BUILTIN , mawk_f2d(p->fp)) ;
2376 }
2377 #line 2379 "y.tab.c" /* yacc.c:1646 */
2378 break;
2379
2380 case 92:
2381 #line 505 "parse.y" /* yacc.c:1646 */
2382 {
2383 (yyval.start) = mawk_code_offset ;
2384 code1(_PUSHINT) ; code1(0) ;
2385 code2(MAWK, _BUILTIN, mawk_f2d((yyvsp[0].bip)->fp)) ;
2386 }
2387 #line 2389 "y.tab.c" /* yacc.c:1646 */
2388 break;
2389
2390 case 93:
2391 #line 514 "parse.y" /* yacc.c:1646 */
2392 { (yyval.start) = mawk_code_offset ; }
2393 #line 2395 "y.tab.c" /* yacc.c:1646 */
2394 break;
2395
2396 case 94:
2397 #line 518 "parse.y" /* yacc.c:1646 */
2398 { code2(MAWK, _PRINT, mawk_f2d((yyvsp[-4].fp))) ;
2399 if ( (yyvsp[-4].fp) == mawk_bi_printf && (yyvsp[-2].ival) == 0 )
2400 mawk_compile_error(MAWK, "no arguments in call to printf") ;
2401 MAWK->print_flag = 0 ;
2402 (yyval.start) = (yyvsp[-3].start) ;
2403 }
2404 #line 2406 "y.tab.c" /* yacc.c:1646 */
2405 break;
2406
2407 case 95:
2408 #line 526 "parse.y" /* yacc.c:1646 */
2409 { (yyval.fp) = mawk_bi_print ; MAWK->print_flag = 1 ;}
2410 #line 2412 "y.tab.c" /* yacc.c:1646 */
2411 break;
2412
2413 case 96:
2414 #line 527 "parse.y" /* yacc.c:1646 */
2415 { (yyval.fp) = mawk_bi_printf ; MAWK->print_flag = 1 ; }
2416 #line 2418 "y.tab.c" /* yacc.c:1646 */
2417 break;
2418
2419 case 97:
2420 #line 530 "parse.y" /* yacc.c:1646 */
2421 { mawk_code2op(MAWK, _PUSHINT, (yyvsp[0].ival)) ; }
2422 #line 2424 "y.tab.c" /* yacc.c:1646 */
2423 break;
2424
2425 case 98:
2426 #line 532 "parse.y" /* yacc.c:1646 */
2427 { (yyval.ival) = (yyvsp[-1].arg2p)->cnt ; mawk_zfree(MAWK, (yyvsp[-1].arg2p),sizeof(ARG2_REC)) ;
2428 mawk_code2op(MAWK, _PUSHINT, (yyval.ival)) ;
2429 }
2430 #line 2432 "y.tab.c" /* yacc.c:1646 */
2431 break;
2432
2433 case 99:
2434 #line 536 "parse.y" /* yacc.c:1646 */
2435 { (yyval.ival)=0 ; mawk_code2op(MAWK, _PUSHINT, 0) ; }
2436 #line 2438 "y.tab.c" /* yacc.c:1646 */
2437 break;
2438
2439 case 100:
2440 #line 540 "parse.y" /* yacc.c:1646 */
2441 { (yyval.arg2p) = (ARG2_REC*) mawk_zmalloc(MAWK, sizeof(ARG2_REC)) ;
2442 (yyval.arg2p)->start = (yyvsp[-2].start) ;
2443 (yyval.arg2p)->cnt = 2 ;
2444 }
2445 #line 2447 "y.tab.c" /* yacc.c:1646 */
2446 break;
2447
2448 case 101:
2449 #line 545 "parse.y" /* yacc.c:1646 */
2450 { (yyval.arg2p) = (yyvsp[-2].arg2p) ; (yyval.arg2p)->cnt++ ; }
2451 #line 2453 "y.tab.c" /* yacc.c:1646 */
2452 break;
2453
2454 case 103:
2455 #line 550 "parse.y" /* yacc.c:1646 */
2456 { mawk_code2op(MAWK, _PUSHINT, (yyvsp[-1].ival)) ; }
2457 #line 2459 "y.tab.c" /* yacc.c:1646 */
2458 break;
2459
2460 case 104:
2461 #line 557 "parse.y" /* yacc.c:1646 */
2462 { (yyval.start) = (yyvsp[-1].start) ; mawk_eat_nl(MAWK, &yylval) ; mawk_code_jmp(MAWK, _JZ, (INST*)0) ; }
2463 #line 2465 "y.tab.c" /* yacc.c:1646 */
2464 break;
2465
2466 case 105:
2467 #line 562 "parse.y" /* yacc.c:1646 */
2468 { mawk_patch_jmp(MAWK, mawk_code_ptr ) ; }
2469 #line 2471 "y.tab.c" /* yacc.c:1646 */
2470 break;
2471
2472 case 106:
2473 #line 565 "parse.y" /* yacc.c:1646 */
2474 { mawk_eat_nl(MAWK, &yylval) ; mawk_code_jmp(MAWK, _JMP, (INST*)0) ; }
2475 #line 2477 "y.tab.c" /* yacc.c:1646 */
2476 break;
2477
2478 case 107:
2479 #line 570 "parse.y" /* yacc.c:1646 */
2480 { mawk_patch_jmp(MAWK, mawk_code_ptr) ;
2481 mawk_patch_jmp(MAWK, CDP((yyvsp[0].start))) ;
2482 }
2483 #line 2485 "y.tab.c" /* yacc.c:1646 */
2484 break;
2485
2486 case 108:
2487 #line 578 "parse.y" /* yacc.c:1646 */
2488 { mawk_eat_nl(MAWK, &yylval) ; mawk_BC_new(MAWK) ; }
2489 #line 2491 "y.tab.c" /* yacc.c:1646 */
2490 break;
2491
2492 case 109:
2493 #line 583 "parse.y" /* yacc.c:1646 */
2494 { (yyval.start) = (yyvsp[-5].start) ;
2495 mawk_code_jmp(MAWK, _JNZ, CDP((yyvsp[-5].start))) ;
2496 mawk_BC_clear(MAWK, mawk_code_ptr, CDP((yyvsp[-2].start))) ; }
2497 #line 2499 "y.tab.c" /* yacc.c:1646 */
2498 break;
2499
2500 case 110:
2501 #line 589 "parse.y" /* yacc.c:1646 */
2502 { mawk_eat_nl(MAWK, &yylval) ; mawk_BC_new(MAWK) ;
2503 (yyval.start) = (yyvsp[-1].start) ;
2504
2505 /* check if const expression */
2506 if ( mawk_code_ptr - 2 == CDP((yyvsp[-1].start)) &&
2507 mawk_code_ptr[-2].op == _PUSHD &&
2508 *(double*)mawk_code_ptr[-1].ptr != 0.0
2509 )
2510 mawk_code_ptr -= 2 ;
2511 else
2512 { INST *p3 = CDP((yyvsp[-1].start)) ;
2513 mawk_code_push(MAWK, p3, mawk_code_ptr-p3, MAWK->scope, MAWK->active_funct) ;
2514 mawk_code_ptr = p3 ;
2515 code2(MAWK, _JMP, (INST*)0) ; /* code2() not mawk_code_jmp() */
2516 }
2517 }
2518 #line 2520 "y.tab.c" /* yacc.c:1646 */
2519 break;
2520
2521 case 111:
2522 #line 609 "parse.y" /* yacc.c:1646 */
2523 {
2524 int saved_offset ;
2525 int len ;
2526 INST *p1 = CDP((yyvsp[-1].start)) ;
2527 INST *p2 = CDP((yyvsp[0].start)) ;
2528
2529 if ( p1 != p2 ) /* real mawk_test in loop */
2530 {
2531 p1[1].op = mawk_code_ptr-(p1+1) ;
2532 saved_offset = mawk_code_offset ;
2533 len = mawk_code_pop(MAWK, mawk_code_ptr) ;
2534 mawk_code_ptr += len ;
2535 mawk_code_jmp(MAWK, _JNZ, CDP((yyvsp[0].start))) ;
2536 mawk_BC_clear(MAWK, mawk_code_ptr, CDP(saved_offset)) ;
2537 }
2538 else /* while(1) */
2539 {
2540 mawk_code_jmp(MAWK, _JMP, p1) ;
2541 mawk_BC_clear(MAWK, mawk_code_ptr, CDP((yyvsp[0].start))) ;
2542 }
2543 }
2544 #line 2546 "y.tab.c" /* yacc.c:1646 */
2545 break;
2546
2547 case 112:
2548 #line 635 "parse.y" /* yacc.c:1646 */
2549 {
2550 int cont_offset = mawk_code_offset ;
2551 unsigned len = mawk_code_pop(MAWK, mawk_code_ptr) ;
2552 INST *p2 = CDP((yyvsp[-2].start)) ;
2553 INST *p4 = CDP((yyvsp[0].start)) ;
2554
2555 mawk_code_ptr += len ;
2556
2557 if ( p2 != p4 ) /* real mawk_test in for2 */
2558 {
2559 p4[-1].op = mawk_code_ptr - p4 + 1 ;
2560 len = mawk_code_pop(MAWK, mawk_code_ptr) ;
2561 mawk_code_ptr += len ;
2562 mawk_code_jmp(MAWK, _JNZ, CDP((yyvsp[0].start))) ;
2563 }
2564 else /* for(;;) */
2565 mawk_code_jmp(MAWK, _JMP, p4) ;
2566
2567 mawk_BC_clear(MAWK, mawk_code_ptr, CDP(cont_offset)) ;
2568
2569 }
2570 #line 2572 "y.tab.c" /* yacc.c:1646 */
2571 break;
2572
2573 case 113:
2574 #line 658 "parse.y" /* yacc.c:1646 */
2575 { (yyval.start) = mawk_code_offset ; }
2576 #line 2578 "y.tab.c" /* yacc.c:1646 */
2577 break;
2578
2579 case 114:
2580 #line 660 "parse.y" /* yacc.c:1646 */
2581 { (yyval.start) = (yyvsp[-1].start) ; code1(_POP) ; }
2582 #line 2584 "y.tab.c" /* yacc.c:1646 */
2583 break;
2584
2585 case 115:
2586 #line 663 "parse.y" /* yacc.c:1646 */
2587 { (yyval.start) = mawk_code_offset ; }
2588 #line 2590 "y.tab.c" /* yacc.c:1646 */
2589 break;
2590
2591 case 116:
2592 #line 665 "parse.y" /* yacc.c:1646 */
2593 {
2594 if ( mawk_code_ptr - 2 == CDP((yyvsp[-1].start)) &&
2595 mawk_code_ptr[-2].op == _PUSHD &&
2596 * (double*) mawk_code_ptr[-1].ptr != 0.0
2597 )
2598 mawk_code_ptr -= 2 ;
2599 else
2600 {
2601 INST *p1 = CDP((yyvsp[-1].start)) ;
2602 mawk_code_push(MAWK, p1, mawk_code_ptr-p1, MAWK->scope, MAWK->active_funct) ;
2603 mawk_code_ptr = p1 ;
2604 code2(MAWK, _JMP, (INST*)0) ;
2605 }
2606 }
2607 #line 2609 "y.tab.c" /* yacc.c:1646 */
2608 break;
2609
2610 case 117:
2611 #line 682 "parse.y" /* yacc.c:1646 */
2612 { mawk_eat_nl(MAWK, &yylval) ; mawk_BC_new(MAWK) ;
2613 mawk_code_push(MAWK, (INST*)0,0, MAWK->scope, MAWK->active_funct) ;
2614 }
2615 #line 2617 "y.tab.c" /* yacc.c:1646 */
2616 break;
2617
2618 case 118:
2619 #line 686 "parse.y" /* yacc.c:1646 */
2620 { INST *p1 = CDP((yyvsp[-1].start)) ;
2621
2622 mawk_eat_nl(MAWK, &yylval) ; mawk_BC_new(MAWK) ;
2623 code1(_POP) ;
2624 mawk_code_push(MAWK, p1, mawk_code_ptr - p1, MAWK->scope, MAWK->active_funct) ;
2625 mawk_code_ptr -= mawk_code_ptr - p1 ;
2626 }
2627 #line 2629 "y.tab.c" /* yacc.c:1646 */
2628 break;
2629
2630 case 119:
2631 #line 699 "parse.y" /* yacc.c:1646 */
2632 { check_array(MAWK, (yyvsp[0].stp)) ;
2633 mawk_code_array(MAWK, (yyvsp[0].stp)) ;
2634 code1(A_TEST) ;
2635 }
2636 #line 2638 "y.tab.c" /* yacc.c:1646 */
2637 break;
2638
2639 case 120:
2640 #line 704 "parse.y" /* yacc.c:1646 */
2641 { (yyval.start) = (yyvsp[-3].arg2p)->start ;
2642 mawk_code2op(MAWK, A_CAT, (yyvsp[-3].arg2p)->cnt) ;
2643 mawk_zfree(MAWK, (yyvsp[-3].arg2p), sizeof(ARG2_REC)) ;
2644
2645 check_array(MAWK, (yyvsp[0].stp)) ;
2646 mawk_code_array(MAWK, (yyvsp[0].stp)) ;
2647 code1(A_TEST) ;
2648 }
2649 #line 2651 "y.tab.c" /* yacc.c:1646 */
2650 break;
2651
2652 case 121:
2653 #line 717 "parse.y" /* yacc.c:1646 */
2654 {
2655 if ( (yyvsp[-1].ival) > 1 )
2656 { mawk_code2op(MAWK, A_CAT, (yyvsp[-1].ival)) ; }
2657
2658 check_array(MAWK, (yyvsp[-4].stp)) ;
2659 if( is_local((yyvsp[-4].stp)) )
2660 { mawk_code2op(MAWK, LAE_PUSHA, (yyvsp[-4].stp)->offset) ; }
2661 else code2(MAWK, AE_PUSHA, (yyvsp[-4].stp)->stval.array) ;
2662 (yyval.start) = (yyvsp[-3].start) ;
2663 }
2664 #line 2666 "y.tab.c" /* yacc.c:1646 */
2665 break;
2666
2667 case 122:
2668 #line 730 "parse.y" /* yacc.c:1646 */
2669 {
2670 if ( (yyvsp[-1].ival) > 1 )
2671 { mawk_code2op(MAWK, A_CAT, (yyvsp[-1].ival)) ; }
2672
2673 check_array(MAWK, (yyvsp[-4].stp)) ;
2674 if( is_local((yyvsp[-4].stp)) )
2675 { mawk_code2op(MAWK, LAE_PUSHA_WRARR, (yyvsp[-4].stp)->offset) ; }
2676 else code2(MAWK, AE_PUSHA_WRARR, (yyvsp[-4].stp)->stval.array) ;
2677 (yyval.start) = (yyvsp[-3].start) ;
2678 }
2679 #line 2681 "y.tab.c" /* yacc.c:1646 */
2680 break;
2681
2682 case 123:
2683 #line 743 "parse.y" /* yacc.c:1646 */
2684 {
2685 if ( (yyvsp[-1].ival) > 1 )
2686 { mawk_code2op(MAWK, A_CAT, (yyvsp[-1].ival)) ; }
2687
2688 check_array(MAWK, (yyvsp[-4].stp)) ;
2689 if( is_local((yyvsp[-4].stp)) )
2690 { mawk_code2op(MAWK, LAE_PUSHI, (yyvsp[-4].stp)->offset) ; }
2691 else code2(MAWK, AE_PUSHI, (yyvsp[-4].stp)->stval.array) ;
2692 (yyval.start) = (yyvsp[-3].start) ;
2693 }
2694 #line 2696 "y.tab.c" /* yacc.c:1646 */
2695 break;
2696
2697 case 124:
2698 #line 755 "parse.y" /* yacc.c:1646 */
2699 {
2700 if ( (yyvsp[-2].ival) > 1 )
2701 { mawk_code2op(MAWK, A_CAT,(yyvsp[-2].ival)) ; }
2702
2703 check_array(MAWK, (yyvsp[-5].stp)) ;
2704 if( is_local((yyvsp[-5].stp)) )
2705 { mawk_code2op(MAWK, LAE_PUSHA_WRARR, (yyvsp[-5].stp)->offset) ; }
2706 else code2(MAWK, AE_PUSHA_WRARR, (yyvsp[-5].stp)->stval.array) ;
2707 if ( (yyvsp[0].ival) == '+' ) code1(_POST_INC_ARR) ;
2708 else code1(_POST_DEC_ARR) ;
2709
2710 (yyval.start) = (yyvsp[-4].start) ;
2711 }
2712 #line 2714 "y.tab.c" /* yacc.c:1646 */
2713 break;
2714
2715 case 125:
2716 #line 772 "parse.y" /* yacc.c:1646 */
2717 {
2718 (yyval.start) = (yyvsp[-4].start) ;
2719 if ( (yyvsp[-2].ival) > 1 ) { mawk_code2op(MAWK, A_CAT, (yyvsp[-2].ival)) ; }
2720 check_array(MAWK, (yyvsp[-5].stp)) ;
2721 mawk_code_array(MAWK, (yyvsp[-5].stp)) ;
2722 code1(A_DEL) ;
2723 }
2724 #line 2726 "y.tab.c" /* yacc.c:1646 */
2725 break;
2726
2727 case 126:
2728 #line 780 "parse.y" /* yacc.c:1646 */
2729 {
2730 (yyval.start) = mawk_code_offset ;
2731 check_array(MAWK, (yyvsp[-1].stp)) ;
2732 mawk_code_array(MAWK, (yyvsp[-1].stp)) ;
2733 code1(DEL_A) ;
2734 }
2735 #line 2737 "y.tab.c" /* yacc.c:1646 */
2736 break;
2737
2738 case 127:
2739 #line 791 "parse.y" /* yacc.c:1646 */
2740 { mawk_eat_nl(MAWK, &yylval) ; mawk_BC_new(MAWK) ;
2741 (yyval.start) = mawk_code_offset ;
2742
2743 check_var(MAWK, (yyvsp[-3].stp)) ;
2744 mawk_code_address((yyvsp[-3].stp)) ;
2745 check_array(MAWK, (yyvsp[-1].stp)) ;
2746 mawk_code_array(MAWK, (yyvsp[-1].stp)) ;
2747
2748 code2(MAWK, SET_ALOOP, (INST*)0) ;
2749 }
2750 #line 2752 "y.tab.c" /* yacc.c:1646 */
2751 break;
2752
2753 case 128:
2754 #line 805 "parse.y" /* yacc.c:1646 */
2755 {
2756 INST *p2 = CDP((yyvsp[0].start)) ;
2757
2758 p2[-1].op = mawk_code_ptr - p2 + 1 ;
2759 mawk_BC_clear(MAWK, mawk_code_ptr+2 , mawk_code_ptr) ;
2760 mawk_code_jmp(MAWK, ALOOP, p2) ;
2761 code1(POP_AL) ;
2762 }
2763 #line 2765 "y.tab.c" /* yacc.c:1646 */
2764 break;
2765
2766 case 129:
2767 #line 822 "parse.y" /* yacc.c:1646 */
2768 { (yyval.start) = mawk_code_offset ; code2(MAWK, F_PUSHA, (yyvsp[0].cp)) ; }
2769 #line 2771 "y.tab.c" /* yacc.c:1646 */
2770 break;
2771
2772 case 130:
2773 #line 824 "parse.y" /* yacc.c:1646 */
2774 { check_var(MAWK, (yyvsp[0].stp)) ;
2775 (yyval.start) = mawk_code_offset ;
2776 if ( is_local((yyvsp[0].stp)) )
2777 { mawk_code2op(MAWK, L_PUSHI, (yyvsp[0].stp)->offset) ; }
2778 else code2(MAWK, _PUSHI, (yyvsp[0].stp)->stval.cp) ;
2779
2780 CODE_FE_PUSHA() ;
2781 }
2782 #line 2784 "y.tab.c" /* yacc.c:1646 */
2783 break;
2784
2785 case 131:
2786 #line 833 "parse.y" /* yacc.c:1646 */
2787 {
2788 if ( (yyvsp[-1].ival) > 1 )
2789 { mawk_code2op(MAWK, A_CAT, (yyvsp[-1].ival)) ; }
2790
2791 check_array(MAWK, (yyvsp[-4].stp)) ;
2792 if( is_local((yyvsp[-4].stp)) )
2793 { mawk_code2op(MAWK, LAE_PUSHI, (yyvsp[-4].stp)->offset) ; }
2794 else code2(MAWK, AE_PUSHI, (yyvsp[-4].stp)->stval.array) ;
2795
2796 CODE_FE_PUSHA() ;
2797
2798 (yyval.start) = (yyvsp[-3].start) ;
2799 }
2800 #line 2802 "y.tab.c" /* yacc.c:1646 */
2801 break;
2802
2803 case 132:
2804 #line 847 "parse.y" /* yacc.c:1646 */
2805 { (yyval.start) = (yyvsp[0].start) ; CODE_FE_PUSHA() ; }
2806 #line 2808 "y.tab.c" /* yacc.c:1646 */
2807 break;
2808
2809 case 133:
2810 #line 849 "parse.y" /* yacc.c:1646 */
2811 { (yyval.start) = (yyvsp[-1].start) ; }
2812 #line 2814 "y.tab.c" /* yacc.c:1646 */
2813 break;
2814
2815 case 134:
2816 #line 853 "parse.y" /* yacc.c:1646 */
2817 { field_A2I(MAWK) ; }
2818 #line 2820 "y.tab.c" /* yacc.c:1646 */
2819 break;
2820
2821 case 135:
2822 #line 856 "parse.y" /* yacc.c:1646 */
2823 { code1(F_ASSIGN) ; }
2824 #line 2826 "y.tab.c" /* yacc.c:1646 */
2825 break;
2826
2827 case 136:
2828 #line 857 "parse.y" /* yacc.c:1646 */
2829 { code1(F_ADD_ASG) ; }
2830 #line 2832 "y.tab.c" /* yacc.c:1646 */
2831 break;
2832
2833 case 137:
2834 #line 858 "parse.y" /* yacc.c:1646 */
2835 { code1(F_SUB_ASG) ; }
2836 #line 2838 "y.tab.c" /* yacc.c:1646 */
2837 break;
2838
2839 case 138:
2840 #line 859 "parse.y" /* yacc.c:1646 */
2841 { code1(F_MUL_ASG) ; }
2842 #line 2844 "y.tab.c" /* yacc.c:1646 */
2843 break;
2844
2845 case 139:
2846 #line 860 "parse.y" /* yacc.c:1646 */
2847 { code1(F_DIV_ASG) ; }
2848 #line 2850 "y.tab.c" /* yacc.c:1646 */
2849 break;
2850
2851 case 140:
2852 #line 861 "parse.y" /* yacc.c:1646 */
2853 { code1(F_MOD_ASG) ; }
2854 #line 2856 "y.tab.c" /* yacc.c:1646 */
2855 break;
2856
2857 case 141:
2858 #line 862 "parse.y" /* yacc.c:1646 */
2859 { code1(F_POW_ASG) ; }
2860 #line 2862 "y.tab.c" /* yacc.c:1646 */
2861 break;
2862
2863 case 142:
2864 #line 869 "parse.y" /* yacc.c:1646 */
2865 { code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_split)) ; }
2866 #line 2868 "y.tab.c" /* yacc.c:1646 */
2867 break;
2868
2869 case 143:
2870 #line 873 "parse.y" /* yacc.c:1646 */
2871 { (yyval.start) = (yyvsp[-2].start) ;
2872 check_array(MAWK, (yyvsp[0].stp)) ;
2873 mawk_code_array(MAWK, (yyvsp[0].stp)) ;
2874 }
2875 #line 2877 "y.tab.c" /* yacc.c:1646 */
2876 break;
2877
2878 case 144:
2879 #line 880 "parse.y" /* yacc.c:1646 */
2880 { code2(MAWK, _PUSHI, &MAWK->fs_shadow) ; }
2881 #line 2883 "y.tab.c" /* yacc.c:1646 */
2882 break;
2883
2884 case 145:
2885 #line 882 "parse.y" /* yacc.c:1646 */
2886 {
2887 if ( CDP((yyvsp[-1].start)) == mawk_code_ptr - 2 )
2888 {
2889 if ( mawk_code_ptr[-2].op == _MATCH0 )
2890 RE_as_arg(MAWK) ;
2891 else
2892 if ( mawk_code_ptr[-2].op == _PUSHS )
2893 { mawk_cell_t *cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
2894
2895 cp->type = C_STRING ;
2896 cp->ptr = mawk_code_ptr[-1].ptr ;
2897 mawk_cast_for_split(MAWK, cp) ;
2898 mawk_code_ptr[-2].op = _PUSHC ;
2899 mawk_code_ptr[-1].ptr = (PTR) cp ;
2900 }
2901 }
2902 }
2903 #line 2905 "y.tab.c" /* yacc.c:1646 */
2904 break;
2905
2906 case 146:
2907 #line 906 "parse.y" /* yacc.c:1646 */
2908 { (yyval.start) = (yyvsp[-3].start) ;
2909 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_match)) ;
2910 }
2911 #line 2913 "y.tab.c" /* yacc.c:1646 */
2912 break;
2913
2914 case 147:
2915 #line 913 "parse.y" /* yacc.c:1646 */
2916 {
2917 INST *p1 = CDP((yyvsp[0].start)) ;
2918
2919 if ( p1 == mawk_code_ptr - 2 )
2920 {
2921 if ( p1->op == _MATCH0 ) RE_as_arg(MAWK) ;
2922 else
2923 if ( p1->op == _PUSHS )
2924 { mawk_cell_t *cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
2925
2926 cp->type = C_STRING ;
2927 cp->ptr = p1[1].ptr ;
2928 mawk_cast_to_RE(MAWK, cp) ;
2929 p1->op = _PUSHC ;
2930 p1[1].ptr = (PTR) cp ;
2931 }
2932 }
2933 }
2934 #line 2936 "y.tab.c" /* yacc.c:1646 */
2935 break;
2936
2937 case 148:
2938 #line 936 "parse.y" /* yacc.c:1646 */
2939 { (yyval.start) = mawk_code_offset ;
2940 code1(_EXIT0) ; }
2941 #line 2943 "y.tab.c" /* yacc.c:1646 */
2942 break;
2943
2944 case 149:
2945 #line 939 "parse.y" /* yacc.c:1646 */
2946 { (yyval.start) = (yyvsp[-1].start) ; code1(_EXIT) ; }
2947 #line 2949 "y.tab.c" /* yacc.c:1646 */
2948 break;
2949
2950 case 150:
2951 #line 942 "parse.y" /* yacc.c:1646 */
2952 { (yyval.start) = mawk_code_offset ;
2953 code1(_RET0) ; }
2954 #line 2956 "y.tab.c" /* yacc.c:1646 */
2955 break;
2956
2957 case 151:
2958 #line 945 "parse.y" /* yacc.c:1646 */
2959 { (yyval.start) = (yyvsp[-1].start) ; code1(_RET) ; }
2960 #line 2962 "y.tab.c" /* yacc.c:1646 */
2961 break;
2962
2963 case 152:
2964 #line 950 "parse.y" /* yacc.c:1646 */
2965 { (yyval.start) = mawk_code_offset ;
2966 code2(MAWK, F_PUSHA, &MAWK->field[0]) ;
2967 code1(_PUSHINT) ; code1(0) ;
2968 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_getline)) ;
2969 MAWK->getline_flag = 0 ;
2970 }
2971 #line 2973 "y.tab.c" /* yacc.c:1646 */
2972 break;
2973
2974 case 153:
2975 #line 957 "parse.y" /* yacc.c:1646 */
2976 { (yyval.start) = (yyvsp[0].start) ;
2977 code1(_PUSHINT) ; code1(0) ;
2978 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_getline)) ;
2979 MAWK->getline_flag = 0 ;
2980 }
2981 #line 2983 "y.tab.c" /* yacc.c:1646 */
2982 break;
2983
2984 case 154:
2985 #line 963 "parse.y" /* yacc.c:1646 */
2986 { code1(_PUSHINT) ; code1(F_IN) ;
2987 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_getline)) ;
2988 /* getline_flag already off in yylex() */
2989 }
2990 #line 2992 "y.tab.c" /* yacc.c:1646 */
2991 break;
2992
2993 case 155:
2994 #line 968 "parse.y" /* yacc.c:1646 */
2995 { code2(MAWK, F_PUSHA, &MAWK->field[0]) ;
2996 code1(_PUSHINT) ; code1(PIPE_IN) ;
2997 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_getline)) ;
2998 }
2999 #line 3001 "y.tab.c" /* yacc.c:1646 */
3000 break;
3001
3002 case 156:
3003 #line 973 "parse.y" /* yacc.c:1646 */
3004 {
3005 code1(_PUSHINT) ; code1(PIPE_IN) ;
3006 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_getline)) ;
3007 }
3008 #line 3010 "y.tab.c" /* yacc.c:1646 */
3009 break;
3010
3011 case 157:
3012 #line 979 "parse.y" /* yacc.c:1646 */
3013 { MAWK->getline_flag = 1 ; }
3014 #line 3016 "y.tab.c" /* yacc.c:1646 */
3015 break;
3016
3017 case 161:
3018 #line 986 "parse.y" /* yacc.c:1646 */
3019 { (yyval.start) = mawk_code_offset ;
3020 code2(MAWK, F_PUSHA, MAWK->field+0) ;
3021 }
3022 #line 3024 "y.tab.c" /* yacc.c:1646 */
3023 break;
3024
3025 case 162:
3026 #line 990 "parse.y" /* yacc.c:1646 */
3027 { (yyval.start) = (yyvsp[-1].start) ; }
3028 #line 3030 "y.tab.c" /* yacc.c:1646 */
3029 break;
3030
3031 case 163:
3032 #line 998 "parse.y" /* yacc.c:1646 */
3033 {
3034 INST *p5 = CDP((yyvsp[-1].start)) ;
3035 INST *p6 = CDP((yyvsp[0].start)) ;
3036
3037 if ( p6 - p5 == 2 && p5->op == _PUSHS )
3038 { /* cast from STRING to REPL at compile time */
3039 mawk_cell_t *cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
3040 cp->type = C_STRING ;
3041 cp->ptr = p5[1].ptr ;
3042 mawk_cast_to_REPL(MAWK, cp) ;
3043 p5->op = _PUSHC ;
3044 p5[1].ptr = (PTR) cp ;
3045 }
3046 code2(MAWK, _BUILTIN, mawk_f2d((yyvsp[-5].fp))) ;
3047 (yyval.start) = (yyvsp[-3].start) ;
3048 }
3049 #line 3051 "y.tab.c" /* yacc.c:1646 */
3050 break;
3051
3052 case 164:
3053 #line 1016 "parse.y" /* yacc.c:1646 */
3054 { (yyval.fp) = mawk_bi_sub ; }
3055 #line 3057 "y.tab.c" /* yacc.c:1646 */
3056 break;
3057
3058 case 165:
3059 #line 1017 "parse.y" /* yacc.c:1646 */
3060 { (yyval.fp) = mawk_bi_gsub ; }
3061 #line 3063 "y.tab.c" /* yacc.c:1646 */
3062 break;
3063
3064 case 166:
3065 #line 1022 "parse.y" /* yacc.c:1646 */
3066 { (yyval.start) = mawk_code_offset ;
3067 code2(MAWK, F_PUSHA, &MAWK->field[0]) ;
3068 }
3069 #line 3071 "y.tab.c" /* yacc.c:1646 */
3070 break;
3071
3072 case 167:
3073 #line 1027 "parse.y" /* yacc.c:1646 */
3074 { (yyval.start) = (yyvsp[-1].start) ; }
3075 #line 3077 "y.tab.c" /* yacc.c:1646 */
3076 break;
3077
3078 case 168:
3079 #line 1035 "parse.y" /* yacc.c:1646 */
3080 {
3081 resize_fblock(MAWK, (yyvsp[-1].fbp)) ;
3082 mawk_restore_ids(MAWK) ;
3083 switch_code_to_main(MAWK) ;
3084 }
3085 #line 3087 "y.tab.c" /* yacc.c:1646 */
3086 break;
3087
3088 case 169:
3089 #line 1043 "parse.y" /* yacc.c:1646 */
3090 { mawk_eat_nl(MAWK, &yylval) ;
3091 MAWK->scope = SCOPE_FUNCT ;
3092 MAWK->active_funct = (yyvsp[-3].fbp) ;
3093 *MAWK->main_code_p = MAWK->active_code ;
3094
3095 (yyvsp[-3].fbp)->nargs = (yyvsp[-1].ival) ;
3096 if ( (yyvsp[-1].ival) )
3097 (yyvsp[-3].fbp)->typev = (char *)
3098 memset( mawk_zmalloc(MAWK, (yyvsp[-1].ival)), ST_LOCAL_NONE, (yyvsp[-1].ival)) ;
3099 else (yyvsp[-3].fbp)->typev = (char *) 0 ;
3100
3101 mawk_code_ptr = mawk_code_base =
3102 (INST *) mawk_zmalloc(MAWK, INST_BYTES(PAGESZ));
3103 mawk_code_limit = mawk_code_base + PAGESZ ;
3104 mawk_code_warn = mawk_code_limit - CODEWARN ;
3105 }
3106 #line 3108 "y.tab.c" /* yacc.c:1646 */
3107 break;
3108
3109 case 170:
3110 #line 1062 "parse.y" /* yacc.c:1646 */
3111 { FBLOCK *fbp ;
3112
3113 if ( (yyvsp[0].stp)->type == ST_NONE )
3114 {
3115 (yyvsp[0].stp)->type = ST_FUNCT ;
3116 fbp = (yyvsp[0].stp)->stval.fbp =
3117 (FBLOCK *) mawk_zmalloc(MAWK, sizeof(FBLOCK)) ;
3118 fbp->name = (yyvsp[0].stp)->name ;
3119 fbp->code = (INST*) 0 ;
3120 }
3121 else
3122 {
3123 mawk_type_error(MAWK, (yyvsp[0].stp) ) ;
3124
3125 /* this FBLOCK will not be put in
3126 the symbol table */
3127 fbp = (FBLOCK*) mawk_zmalloc(MAWK, sizeof(FBLOCK)) ;
3128 fbp->name = "" ;
3129 }
3130 (yyval.fbp) = fbp ;
3131 }
3132 #line 3134 "y.tab.c" /* yacc.c:1646 */
3133 break;
3134
3135 case 171:
3136 #line 1085 "parse.y" /* yacc.c:1646 */
3137 { (yyval.fbp) = (yyvsp[0].fbp) ;
3138 if ( (yyvsp[0].fbp)->code )
3139 mawk_compile_error(MAWK, "redefinition of %s" , (yyvsp[0].fbp)->name) ;
3140 }
3141 #line 3143 "y.tab.c" /* yacc.c:1646 */
3142 break;
3143
3144 case 172:
3145 #line 1091 "parse.y" /* yacc.c:1646 */
3146 { (yyval.ival) = 0 ; }
3147 #line 3149 "y.tab.c" /* yacc.c:1646 */
3148 break;
3149
3150 case 174:
3151 #line 1096 "parse.y" /* yacc.c:1646 */
3152 { (yyvsp[0].stp) = mawk_save_id(MAWK, (yyvsp[0].stp)->name) ;
3153 (yyvsp[0].stp)->type = ST_LOCAL_NONE ;
3154 (yyvsp[0].stp)->offset = 0 ;
3155 (yyval.ival) = 1 ;
3156 }
3157 #line 3159 "y.tab.c" /* yacc.c:1646 */
3158 break;
3159
3160 case 175:
3161 #line 1102 "parse.y" /* yacc.c:1646 */
3162 { if ( is_local((yyvsp[0].stp)) )
3163 mawk_compile_error(MAWK, "%s is duplicated in argument list",
3164 (yyvsp[0].stp)->name) ;
3165 else
3166 { (yyvsp[0].stp) = mawk_save_id(MAWK, (yyvsp[0].stp)->name) ;
3167 (yyvsp[0].stp)->type = ST_LOCAL_NONE ;
3168 (yyvsp[0].stp)->offset = (yyvsp[-2].ival) ;
3169 (yyval.ival) = (yyvsp[-2].ival) + 1 ;
3170 }
3171 }
3172 #line 3174 "y.tab.c" /* yacc.c:1646 */
3173 break;
3174
3175 case 176:
3176 #line 1115 "parse.y" /* yacc.c:1646 */
3177 { /* we may have to recover from a bungled function
3178 definition */
3179 /* can have local ids, before code scope
3180 changes */
3181 mawk_restore_ids(MAWK) ;
3182
3183 switch_code_to_main(MAWK) ;
3184 }
3185 #line 3187 "y.tab.c" /* yacc.c:1646 */
3186 break;
3187
3188 case 177:
3189 #line 1127 "parse.y" /* yacc.c:1646 */
3190 { (yyval.start) = (yyvsp[-1].start) ;
3191 code2(MAWK, _CALL, (yyvsp[-2].fbp)) ;
3192
3193 if ( (yyvsp[0].ca_p) ) code1((yyvsp[0].ca_p)->arg_num+1) ;
3194 else code1(0) ;
3195
3196 mawk_check_fcall(MAWK, (yyvsp[-2].fbp), MAWK->scope, MAWK->ps.code_move_level, MAWK->active_funct,
3197 (yyvsp[0].ca_p), MAWK->token_lineno) ;
3198 }
3199 #line 3201 "y.tab.c" /* yacc.c:1646 */
3200 break;
3201
3202 case 178:
3203 #line 1139 "parse.y" /* yacc.c:1646 */
3204 { (yyval.start) = (yyvsp[-1].start) ;
3205 code2(MAWK, _CALL, (yyvsp[-2].ptr)) ;
3206
3207 if ( (yyvsp[0].ca_p) ) code1((yyvsp[0].ca_p)->arg_num+1) ;
3208 else code1(0) ;
3209 }
3210 #line 3212 "y.tab.c" /* yacc.c:1646 */
3211 break;
3212
3213 case 179:
3214 #line 1148 "parse.y" /* yacc.c:1646 */
3215 { (yyval.ca_p) = (CA_REC *) 0 ; }
3216 #line 3218 "y.tab.c" /* yacc.c:1646 */
3217 break;
3218
3219 case 180:
3220 #line 1150 "parse.y" /* yacc.c:1646 */
3221 { (yyval.ca_p) = (yyvsp[0].ca_p) ;
3222 (yyval.ca_p)->link = (yyvsp[-1].ca_p) ;
3223 (yyval.ca_p)->arg_num = (yyvsp[-1].ca_p) ? (yyvsp[-1].ca_p)->arg_num+1 : 0 ;
3224 }
3225 #line 3227 "y.tab.c" /* yacc.c:1646 */
3226 break;
3227
3228 case 181:
3229 #line 1165 "parse.y" /* yacc.c:1646 */
3230 { (yyval.ca_p) = (CA_REC *) 0 ; }
3231 #line 3233 "y.tab.c" /* yacc.c:1646 */
3232 break;
3233
3234 case 182:
3235 #line 1167 "parse.y" /* yacc.c:1646 */
3236 { (yyval.ca_p) = MAWK_ZMALLOC(MAWK, CA_REC) ;
3237 (yyval.ca_p)->link = (yyvsp[-2].ca_p) ;
3238 (yyval.ca_p)->type = CA_EXPR ;
3239 (yyval.ca_p)->arg_num = (yyvsp[-2].ca_p) ? (yyvsp[-2].ca_p)->arg_num+1 : 0 ;
3240 (yyval.ca_p)->call_offset = mawk_code_offset ;
3241 }
3242 #line 3244 "y.tab.c" /* yacc.c:1646 */
3243 break;
3244
3245 case 183:
3246 #line 1174 "parse.y" /* yacc.c:1646 */
3247 { (yyval.ca_p) = MAWK_ZMALLOC(MAWK, CA_REC) ;
3248 (yyval.ca_p)->link = (yyvsp[-2].ca_p) ;
3249 (yyval.ca_p)->arg_num = (yyvsp[-2].ca_p) ? (yyvsp[-2].ca_p)->arg_num+1 : 0 ;
3250
3251 mawk_code_call_id(MAWK, (yyval.ca_p), (yyvsp[-1].stp)) ;
3252 }
3253 #line 3255 "y.tab.c" /* yacc.c:1646 */
3254 break;
3255
3256 case 184:
3257 #line 1183 "parse.y" /* yacc.c:1646 */
3258 { (yyval.ca_p) = MAWK_ZMALLOC(MAWK, CA_REC) ;
3259 (yyval.ca_p)->type = CA_EXPR ;
3260 (yyval.ca_p)->call_offset = mawk_code_offset ;
3261 }
3262 #line 3264 "y.tab.c" /* yacc.c:1646 */
3263 break;
3264
3265 case 185:
3266 #line 1189 "parse.y" /* yacc.c:1646 */
3267 { (yyval.ca_p) = MAWK_ZMALLOC(MAWK, CA_REC) ;
3268 mawk_code_call_id(MAWK, (yyval.ca_p), (yyvsp[-1].stp)) ;
3269 }
3270 #line 3272 "y.tab.c" /* yacc.c:1646 */
3271 break;
3272
3273 case 186:
3274 #line 1196 "parse.y" /* yacc.c:1646 */
3275 { mawk_parser_include(MAWK, (yyvsp[0].ptr)); }
3276 #line 3278 "y.tab.c" /* yacc.c:1646 */
3277 break;
3278
3279
3280 #line 3282 "y.tab.c" /* yacc.c:1646 */
3281 default: break;
3282 }
3283 /* User semantic actions sometimes alter yychar, and that requires
3284 that yytoken be updated with the new translation. We take the
3285 approach of translating immediately before every use of yytoken.
3286 One alternative is translating here after every semantic action,
3287 but that translation would be missed if the semantic action invokes
3288 YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
3289 if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
3290 incorrect destructor might then be invoked immediately. In the
3291 case of YYERROR or YYBACKUP, subsequent parser actions might lead
3292 to an incorrect destructor call or verbose syntax error message
3293 before the lookahead is translated. */
3294 YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
3295
3296 YYPOPSTACK (yylen);
3297 yylen = 0;
3298 YY_STACK_PRINT (yyss, yyssp);
3299
3300 *++yyvsp = yyval;
3301
3302 /* Now 'shift' the result of the reduction. Determine what state
3303 that goes to, based on the state we popped back to and the rule
3304 number reduced by. */
3305
3306 yyn = yyr1[yyn];
3307
3308 yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
3309 if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
3310 yystate = yytable[yystate];
3311 else
3312 yystate = yydefgoto[yyn - YYNTOKENS];
3313
3314 goto yynewstate;
3315
3316
3317 /*--------------------------------------.
3318 | yyerrlab -- here on detecting error. |
3319 `--------------------------------------*/
3320 yyerrlab:
3321 /* Make sure we have latest lookahead translation. See comments at
3322 user semantic actions for why this is necessary. */
3323 yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
3324
3325 /* If not already recovering from an error, report this error. */
3326 if (!yyerrstatus)
3327 {
3328 ++yynerrs;
3329 #if ! YYERROR_VERBOSE
3330 yyerror (MAWK, YY_("syntax error"));
3331 #else
3332 # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
3333 yyssp, yytoken)
3334 {
3335 char const *yymsgp = YY_("syntax error");
3336 int yysyntax_error_status;
3337 yysyntax_error_status = YYSYNTAX_ERROR;
3338 if (yysyntax_error_status == 0)
3339 yymsgp = yymsg;
3340 else if (yysyntax_error_status == 1)
3341 {
3342 if (yymsg != yymsgbuf)
3343 YYSTACK_FREE (yymsg);
3344 yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
3345 if (!yymsg)
3346 {
3347 yymsg = yymsgbuf;
3348 yymsg_alloc = sizeof yymsgbuf;
3349 yysyntax_error_status = 2;
3350 }
3351 else
3352 {
3353 yysyntax_error_status = YYSYNTAX_ERROR;
3354 yymsgp = yymsg;
3355 }
3356 }
3357 yyerror (MAWK, yymsgp);
3358 if (yysyntax_error_status == 2)
3359 goto yyexhaustedlab;
3360 }
3361 # undef YYSYNTAX_ERROR
3362 #endif
3363 }
3364
3365
3366
3367 if (yyerrstatus == 3)
3368 {
3369 /* If just tried and failed to reuse lookahead token after an
3370 error, discard it. */
3371
3372 if (yychar <= YYEOF)
3373 {
3374 /* Return failure if at end of input. */
3375 if (yychar == YYEOF)
3376 YYABORT;
3377 }
3378 else
3379 {
3380 yydestruct ("Error: discarding",
3381 yytoken, &yylval, MAWK);
3382 yychar = YYEMPTY;
3383 }
3384 }
3385
3386 /* Else will try to reuse lookahead token after shifting the error
3387 token. */
3388 goto yyerrlab1;
3389
3390
3391 /*---------------------------------------------------.
3392 | yyerrorlab -- error raised explicitly by YYERROR. |
3393 `---------------------------------------------------*/
3394 yyerrorlab:
3395
3396 /* Pacify compilers like GCC when the user code never invokes
3397 YYERROR and the label yyerrorlab therefore never appears in user
3398 code. */
3399 if (/*CONSTCOND*/ 0)
3400 goto yyerrorlab;
3401
3402 /* Do not reclaim the symbols of the rule whose action triggered
3403 this YYERROR. */
3404 YYPOPSTACK (yylen);
3405 yylen = 0;
3406 YY_STACK_PRINT (yyss, yyssp);
3407 yystate = *yyssp;
3408 goto yyerrlab1;
3409
3410
3411 /*-------------------------------------------------------------.
3412 | yyerrlab1 -- common code for both syntax error and YYERROR. |
3413 `-------------------------------------------------------------*/
3414 yyerrlab1:
3415 yyerrstatus = 3; /* Each real token shifted decrements this. */
3416
3417 for (;;)
3418 {
3419 yyn = yypact[yystate];
3420 if (!yypact_value_is_default (yyn))
3421 {
3422 yyn += YYTERROR;
3423 if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
3424 {
3425 yyn = yytable[yyn];
3426 if (0 < yyn)
3427 break;
3428 }
3429 }
3430
3431 /* Pop the current state because it cannot handle the error token. */
3432 if (yyssp == yyss)
3433 YYABORT;
3434
3435
3436 yydestruct ("Error: popping",
3437 yystos[yystate], yyvsp, MAWK);
3438 YYPOPSTACK (1);
3439 yystate = *yyssp;
3440 YY_STACK_PRINT (yyss, yyssp);
3441 }
3442
3443 YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
3444 *++yyvsp = yylval;
3445 YY_IGNORE_MAYBE_UNINITIALIZED_END
3446
3447
3448 /* Shift the error token. */
3449 YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
3450
3451 yystate = yyn;
3452 goto yynewstate;
3453
3454
3455 /*-------------------------------------.
3456 | yyacceptlab -- YYACCEPT comes here. |
3457 `-------------------------------------*/
3458 yyacceptlab:
3459 yyresult = 0;
3460 goto yyreturn;
3461
3462 /*-----------------------------------.
3463 | yyabortlab -- YYABORT comes here. |
3464 `-----------------------------------*/
3465 yyabortlab:
3466 yyresult = 1;
3467 goto yyreturn;
3468
3469 #if !defined yyoverflow || YYERROR_VERBOSE
3470 /*-------------------------------------------------.
3471 | yyexhaustedlab -- memory exhaustion comes here. |
3472 `-------------------------------------------------*/
3473 yyexhaustedlab:
3474 yyerror (MAWK, YY_("memory exhausted"));
3475 yyresult = 2;
3476 /* Fall through. */
3477 #endif
3478
3479 yyreturn:
3480 if (yychar != YYEMPTY)
3481 {
3482 /* Make sure we have latest lookahead translation. See comments at
3483 user semantic actions for why this is necessary. */
3484 yytoken = YYTRANSLATE (yychar);
3485 yydestruct ("Cleanup: discarding lookahead",
3486 yytoken, &yylval, MAWK);
3487 }
3488 /* Do not reclaim the symbols of the rule whose action triggered
3489 this YYABORT or YYACCEPT. */
3490 YYPOPSTACK (yylen);
3491 YY_STACK_PRINT (yyss, yyssp);
3492 while (yyssp != yyss)
3493 {
3494 yydestruct ("Cleanup: popping",
3495 yystos[*yyssp], yyvsp, MAWK);
3496 YYPOPSTACK (1);
3497 }
3498 #ifndef yyoverflow
3499 if (yyss != yyssa)
3500 YYSTACK_FREE (yyss);
3501 #endif
3502 #if YYERROR_VERBOSE
3503 if (yymsg != yymsgbuf)
3504 YYSTACK_FREE (yymsg);
3505 #endif
3506 return yyresult;
3507 }
3508 #line 1204 "parse.y" /* yacc.c:1906 */
3509
3510
3511 /* resize the code for a user function */
3512
3513 static void resize_fblock(mawk_state_t *MAWK, FBLOCK *fbp)
3514 {
3515 CODEBLOCK *p = MAWK_ZMALLOC(MAWK, CODEBLOCK) ;
3516
3517 mawk_code2op(MAWK, _RET0, _HALT) ;
3518 /* make sure there is always a return */
3519
3520 *p = MAWK->active_code ;
3521 fbp->code = mawk_code_shrink(MAWK, p, &fbp->size) ;
3522 /* mawk_code_shrink() zfrees p */
3523
3524 /* this list is alos used to free functions in pedantic mode */
3525 #ifndef MAWK_MEM_PEDANTIC
3526 if ( MAWK->dump_code_flag )
3527 #endif
3528 mawk_add_to_fdump_list(MAWK, fbp) ;
3529 /* printf("CODE add: %p/%d\n", fbp->code, fbp->size);*/
3530 }
3531
3532
3533 /* convert FE_PUSHA to FE_PUSHI
3534 or F_PUSH to F_PUSHI
3535 */
3536 static void field_A2I(mawk_state_t *MAWK)
3537 {
3538 mawk_cell_t *cp;
3539
3540 if ( mawk_code_ptr[-1].op == FE_PUSHA &&
3541 mawk_code_ptr[-1].ptr == (PTR) 0)
3542 /* On most architectures, the two mawk_tests are the same; a good
3543 compiler might eliminate one. On LM_DOS, and possibly other
3544 segmented architectures, they are not */
3545 { mawk_code_ptr[-1].op = FE_PUSHI ; }
3546 else
3547 {
3548 cp = (mawk_cell_t *) mawk_code_ptr[-1].ptr ;
3549
3550 if (cp == MAWK->field || (cp > MAWK_NF && cp <= LAST_PFIELD))
3551 {
3552 mawk_code_ptr[-2].op = _PUSHI ;
3553 }
3554 else if ( cp == MAWK_NF )
3555 { mawk_code_ptr[-2].op = NF_PUSHI ; mawk_code_ptr-- ; }
3556
3557 else
3558 {
3559 mawk_code_ptr[-2].op = F_PUSHI ;
3560 mawk_code_ptr -> op = mawk_field_addr_to_index(MAWK, mawk_code_ptr[-1].ptr ) ;
3561 mawk_code_ptr++ ;
3562 }
3563 }
3564 }
3565
3566 /* we've seen an ID in a context where it should be a VAR,
3567 check that's consistent with previous usage */
3568 static void check_var(mawk_state_t *MAWK, register SYMTAB *p)
3569 {
3570 switch(p->type)
3571 {
3572 case ST_NONE : /* new id */
3573 p->type = ST_VAR ;
3574 p->stval.cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
3575 p->stval.cp->type = C_NOINIT ;
3576 break ;
3577
3578 case ST_LOCAL_NONE :
3579 p->type = ST_LOCAL_VAR ;
3580 MAWK->active_funct->typev[p->offset] = ST_LOCAL_VAR ;
3581 break ;
3582
3583 case ST_VAR :
3584 case ST_LOCAL_VAR : break ;
3585
3586 default :
3587 mawk_type_error(MAWK, p) ;
3588 break ;
3589 }
3590 }
3591
3592 /* we've seen an ID in a context where it should be an ARRAY,
3593 check that's consistent with previous usage */
3594 static void check_array(mawk_state_t *MAWK, register SYMTAB *p)
3595 {
3596 switch(p->type)
3597 {
3598 case ST_NONE : /* a new array */
3599 p->type = ST_ARRAY ;
3600 p->stval.array = mawk_array_new(MAWK, NULL) ;
3601 break ;
3602
3603 case ST_ARRAY :
3604 case ST_LOCAL_ARRAY :
3605 break ;
3606
3607 case ST_LOCAL_NONE :
3608 p->type = ST_LOCAL_ARRAY ;
3609 MAWK->active_funct->typev[p->offset] = ST_LOCAL_ARRAY ;
3610 break ;
3611
3612 default : mawk_type_error(MAWK, p) ; break ;
3613 }
3614 }
3615
3616 static void mawk_code_array(mawk_state_t *MAWK, register SYMTAB *p)
3617 {
3618 if ( is_local(p) ) mawk_code2op(MAWK, LA_PUSHA, p->offset) ;
3619 else code2(MAWK, A_PUSHA, p->stval.array) ;
3620 }
3621
3622
3623 /* we've seen an ID as an argument to a user defined function */
3624 static void mawk_code_call_id(mawk_state_t *MAWK, register CA_REC *p, register SYMTAB *ip)
3625 {
3626 p->call_offset = mawk_code_offset ;
3627 /* This always get set now. So that fcall:relocate_arglist
3628 works. */
3629
3630 switch( ip->type )
3631 {
3632 case ST_VAR :
3633 p->type = CA_EXPR ;
3634 code2(MAWK, _PUSHI, ip->stval.cp) ;
3635 break ;
3636
3637 case ST_LOCAL_VAR :
3638 p->type = CA_EXPR ;
3639 mawk_code2op(MAWK, L_PUSHI, ip->offset) ;
3640 break ;
3641
3642 case ST_ARRAY :
3643 p->type = CA_ARRAY ;
3644 code2(MAWK, A_PUSHA, ip->stval.array) ;
3645 break ;
3646
3647 case ST_LOCAL_ARRAY :
3648 p->type = CA_ARRAY ;
3649 mawk_code2op(MAWK, LA_PUSHA, ip->offset) ;
3650 break ;
3651
3652 /* not enough info to code it now; it will have to
3653 be patched later */
3654
3655 case ST_NONE :
3656 p->type = ST_NONE ;
3657 p->sym_p = ip ;
3658 code2(MAWK, _PUSHI, &MAWK->code_call_id_dummy) ;
3659 break ;
3660
3661 case ST_LOCAL_NONE :
3662 p->type = ST_LOCAL_NONE ;
3663 p->type_p = & MAWK->active_funct->typev[ip->offset] ;
3664 mawk_code2op(MAWK, L_PUSHI, ip->offset) ;
3665 break ;
3666
3667 #ifdef DEBUG
3668 default :
3669 mawk_bozo(MAWK, "mawk_code_call_id") ;
3670 #endif
3671
3672 }
3673 }
3674
3675 /* an RE by itself was coded as _MATCH0 , change to
3676 push as an expression */
3677
3678 static void RE_as_arg(mawk_state_t *MAWK)
3679 {
3680 mawk_cell_t *cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
3681
3682 mawk_code_ptr -= 2 ;
3683 cp->type = C_RE ;
3684 cp->ptr = mawk_code_ptr[1].ptr ;
3685 code2(MAWK, _PUSHC, cp) ;
3686 }
3687
3688 /* reset the active_code back to the MAIN block */
3689 static void switch_code_to_main(mawk_state_t *MAWK)
3690 {
3691 switch(MAWK->scope)
3692 {
3693 case SCOPE_BEGIN :
3694 *MAWK->begin_code_p = MAWK->active_code ;
3695 MAWK->active_code = *MAWK->main_code_p ;
3696 break ;
3697
3698 case SCOPE_END :
3699 *MAWK->end_code_p = MAWK->active_code ;
3700 MAWK->active_code = *MAWK->main_code_p ;
3701 break ;
3702
3703 case SCOPE_FUNCT :
3704 MAWK->active_code = *MAWK->main_code_p ;
3705 break ;
3706
3707 case SCOPE_MAIN :
3708 break ;
3709 }
3710 MAWK->active_funct = (FBLOCK*) 0 ;
3711 MAWK->scope = SCOPE_MAIN ;
3712 }
3713
3714
3715 void mawk_parse(mawk_state_t *MAWK)
3716 {
3717 if (!MAWK->binary_loaded) {
3718 if ( yyparse(MAWK) || MAWK->compile_error_count != 0 ) mawk_exit(MAWK, 2) ;
3719
3720 mawk_scan_cleanup(MAWK) ;
3721 mawk_set_code(MAWK) ;
3722 /* code must be set before call to mawk_resolve_fcalls() */
3723 if ( MAWK->resolve_list ) mawk_resolve_fcalls(MAWK) ;
3724 }
3725
3726 if ( MAWK->compile_error_count != 0 ) mawk_exit(MAWK, 2) ;
3727 if ( MAWK->dump_code_flag ) { mawk_dump_code(MAWK);}
3728 if ( MAWK->dump_sym_flag ) { mawk_dump_sym_text(MAWK); }
3729 if ((MAWK->dump_code_flag ) || ( MAWK->dump_sym_flag )) { mawk_exit(MAWK, 0); }
3730
3731 (void)mawk_d2f(NULL); /* suppress compiler warning */
3732 }
3733
3734
3735 void mawk_parser_include(mawk_state_t *MAWK, void *str)
3736 {
3737 mawk_parser_push(MAWK);
3738
3739 MAWK->ps.eof_flag = 0 ;
3740 MAWK->ps.pfile_name = ((mawk_string_t *)str)->str;
3741 MAWK->ps.buffp = MAWK->ps.buffer = (unsigned char *) mawk_zmalloc(MAWK, BUFFSZ + 1) ;
3742 *MAWK->ps.buffp = '\0';
3743 if (mawk_scan_open(MAWK) == 1)
3744 MAWK->token_lineno = MAWK->lineno = 1 ;
3745 else
3746 mawk_parser_pop(MAWK);
3747 }
0 /* A Bison parser, made by GNU Bison 3.0.2. */
1
2 /* Bison interface for Yacc-like parsers in C
3
4 Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 /* As a special exception, you may create a larger work that contains
20 part or all of the Bison parser skeleton and distribute that work
21 under terms of your choice, so long as that work isn't itself a
22 parser generator using the skeleton or a modified version thereof
23 as a parser skeleton. Alternatively, if you modify or redistribute
24 the parser skeleton itself, you may (at your option) remove this
25 special exception, which will cause the skeleton and the resulting
26 Bison output files to be licensed under the GNU General Public
27 License without this special exception.
28
29 This special exception was added by the Free Software Foundation in
30 version 2.2 of Bison. */
31
32 #ifndef YY_MAWK_Y_TAB_H_INCLUDED
33 # define YY_MAWK_Y_TAB_H_INCLUDED
34 /* Debug traces. */
35 #ifndef YYDEBUG
36 # define YYDEBUG 0
37 #endif
38 #if YYDEBUG
39 extern int Mawk_debug;
40 #endif
41
42 /* Token type. */
43 #ifndef YYTOKENTYPE
44 # define YYTOKENTYPE
45 enum yytokentype
46 {
47 UNEXPECTED = 258,
48 BAD_DECIMAL = 259,
49 NL = 260,
50 SEMI_COLON = 261,
51 LBRACE = 262,
52 RBRACE = 263,
53 LBOX = 264,
54 RBOX = 265,
55 COMMA = 266,
56 IO_OUT = 267,
57 ASSIGN = 268,
58 ADD_ASG = 269,
59 SUB_ASG = 270,
60 MUL_ASG = 271,
61 DIV_ASG = 272,
62 MOD_ASG = 273,
63 POW_ASG = 274,
64 QMARK = 275,
65 COLON = 276,
66 OR = 277,
67 AND = 278,
68 IN = 279,
69 MATCH = 280,
70 EQ = 281,
71 NEQ = 282,
72 LT = 283,
73 LTE = 284,
74 GT = 285,
75 GTE = 286,
76 CAT = 287,
77 GETLINE = 288,
78 PLUS = 289,
79 MINUS = 290,
80 MUL = 291,
81 DIV = 292,
82 MOD = 293,
83 NOT = 294,
84 UMINUS = 295,
85 IO_IN = 296,
86 PIPE = 297,
87 POW = 298,
88 INC_or_DEC = 299,
89 DOLLAR = 300,
90 FIELD = 301,
91 LPAREN = 302,
92 RPAREN = 303,
93 DOUBLE = 304,
94 STRING_ = 305,
95 RE = 306,
96 ID = 307,
97 D_ID = 308,
98 FUNCT_ID = 309,
99 C_FUNCT_ID = 310,
100 BUILTIN = 311,
101 LENGTH = 312,
102 PRINT = 313,
103 PRINTF = 314,
104 SPLIT = 315,
105 MATCH_FUNC = 316,
106 SUB = 317,
107 GSUB = 318,
108 DO = 319,
109 WHILE = 320,
110 FOR = 321,
111 BREAK = 322,
112 CONTINUE = 323,
113 IF = 324,
114 ELSE = 325,
115 DELETE = 326,
116 BEGIN = 327,
117 END = 328,
118 EXIT = 329,
119 NEXT = 330,
120 RETURN = 331,
121 FUNCTION = 332,
122 INCLUDE = 333
123 };
124 #endif
125 /* Tokens. */
126 #define UNEXPECTED 258
127 #define BAD_DECIMAL 259
128 #define NL 260
129 #define SEMI_COLON 261
130 #define LBRACE 262
131 #define RBRACE 263
132 #define LBOX 264
133 #define RBOX 265
134 #define COMMA 266
135 #define IO_OUT 267
136 #define ASSIGN 268
137 #define ADD_ASG 269
138 #define SUB_ASG 270
139 #define MUL_ASG 271
140 #define DIV_ASG 272
141 #define MOD_ASG 273
142 #define POW_ASG 274
143 #define QMARK 275
144 #define COLON 276
145 #define OR 277
146 #define AND 278
147 #define IN 279
148 #define MATCH 280
149 #define EQ 281
150 #define NEQ 282
151 #define LT 283
152 #define LTE 284
153 #define GT 285
154 #define GTE 286
155 #define CAT 287
156 #define GETLINE 288
157 #define PLUS 289
158 #define MINUS 290
159 #define MUL 291
160 #define DIV 292
161 #define MOD 293
162 #define NOT 294
163 #define UMINUS 295
164 #define IO_IN 296
165 #define PIPE 297
166 #define POW 298
167 #define INC_or_DEC 299
168 #define DOLLAR 300
169 #define FIELD 301
170 #define LPAREN 302
171 #define RPAREN 303
172 #define DOUBLE 304
173 #define STRING_ 305
174 #define RE 306
175 #define ID 307
176 #define D_ID 308
177 #define FUNCT_ID 309
178 #define C_FUNCT_ID 310
179 #define BUILTIN 311
180 #define LENGTH 312
181 #define PRINT 313
182 #define PRINTF 314
183 #define SPLIT 315
184 #define MATCH_FUNC 316
185 #define SUB 317
186 #define GSUB 318
187 #define DO 319
188 #define WHILE 320
189 #define FOR 321
190 #define BREAK 322
191 #define CONTINUE 323
192 #define IF 324
193 #define ELSE 325
194 #define DELETE 326
195 #define BEGIN 327
196 #define END 328
197 #define EXIT 329
198 #define NEXT 330
199 #define RETURN 331
200 #define FUNCTION 332
201 #define INCLUDE 333
202
203 /* Value type. */
204 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
205 typedef union YYSTYPE YYSTYPE;
206 union YYSTYPE
207 {
208 #line 136 "parse.y" /* yacc.c:1909 */
209
210 mawk_cell_t *cp ;
211 SYMTAB *stp ;
212 int start ; /* code starting address as offset from code_base */
213 PF_CP fp ; /* ptr to a (print/printf) or (sub/gsub) function */
214 const BI_REC *bip ; /* ptr to info about a builtin */
215 FBLOCK *fbp ; /* ptr to a function block */
216 ARG2_REC *arg2p ;
217 CA_REC *ca_p ;
218 int ival ;
219 PTR ptr ;
220
221 #line 223 "y.tab.h" /* yacc.c:1909 */
222 };
223 # define YYSTYPE_IS_TRIVIAL 1
224 # define YYSTYPE_IS_DECLARED 1
225 #endif
226
227
228
229 int Mawk_parse (mawk_state_t *MAWK);
230
231 #endif /* !YY_MAWK_Y_TAB_H_INCLUDED */
0
1 /********************************************
2 parse.y
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991-94, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* $Log: parse.y,v $
17 * Revision 1.11 1995/06/11 22:40:09 mike
18 * change if(dump_code) -> if(dump_code_flag)
19 * cleanup of parse()
20 * add cast to shutup solaris cc compiler on char to int comparison
21 * switch_code_to_main() which cleans up outside_error production
22 *
23 * Revision 1.10 1995/04/21 14:20:21 mike
24 * move_level variable to fix bug in arglist patching of moved code.
25 *
26 * Revision 1.9 1995/02/19 22:15:39 mike
27 * Always set the call_offset field in a CA_REC (for obscure
28 * reasons in fcall.c (see comments) there.)
29 *
30 * Revision 1.8 1994/12/13 00:39:20 mike
31 * delete A statement to delete all of A at once
32 *
33 * Revision 1.7 1994/10/08 19:15:48 mike
34 * remove SM_DOS
35 *
36 * Revision 1.6 1993/12/01 14:25:17 mike
37 * reentrant array loops
38 *
39 * Revision 1.5 1993/07/22 00:04:13 mike
40 * new op code _LJZ _LJNZ
41 *
42 * Revision 1.4 1993/07/15 23:38:15 mike
43 * SIZE_T and indent
44 *
45 * Revision 1.3 1993/07/07 00:07:46 mike
46 * more work on 1.2
47 *
48 * Revision 1.2 1993/07/03 21:18:01 mike
49 * bye to yacc_mem
50 *
51 * Revision 1.1.1.1 1993/07/03 18:58:17 mike
52 * move source to cvs
53 *
54 * Revision 5.8 1993/05/03 01:07:18 mike
55 * fix mawk_bozo in LENGTH production
56 *
57 * Revision 5.7 1993/01/09 19:03:44 mike
58 * code_pop checks if the resolve_list needs relocation
59 *
60 * Revision 5.6 1993/01/07 02:50:33 mike
61 * relative vs absolute code
62 *
63 * Revision 5.5 1993/01/01 21:30:48 mike
64 * split mawk_new_STRING() into mawk_new_STRING and mawk_new_STRING0
65 *
66 * Revision 5.4 1992/08/08 17:17:20 brennan
67 * patch 2: improved timing of error recovery in
68 * bungled function definitions. Fixes a core dump
69 *
70 * Revision 5.3 1992/07/08 15:43:41 brennan
71 * patch2: length returns. I am a wimp
72 *
73 * Revision 5.2 1992/01/08 16:11:42 brennan
74 * code FE_PUSHA carefully for MSDOS large mode
75 *
76 * Revision 5.1 91/12/05 07:50:22 brennan
77 * 1.1 pre-release
78 *
79 */
80
81 %pure-parser
82 %parse-param {mawk_state_t *MAWK}
83 %lex-param {mawk_state_t *MAWK}
84
85 %{
86 #include <stdio.h>
87 #include "mawk.h"
88 #include "types.h"
89 #include "symtype.h"
90 #include "code.h"
91 #include "memory.h"
92 #include "bi_funct.h"
93 #include "bi_vars.h"
94 #include "jmp.h"
95 #include "field.h"
96 #include "files.h"
97 #include "scan.h"
98 #include "zmalloc.h"
99 #include "f2d.h"
100
101
102 #define YYMAXDEPTH 200
103
104 void mawk_eat_nl(mawk_state_t * MAWK, YYSTYPE *lvalp);
105 static void resize_fblock(mawk_state_t *, FBLOCK *);
106 static void switch_code_to_main(mawk_state_t *);
107 static void mawk_code_array(mawk_state_t *, SYMTAB *);
108 static void mawk_code_call_id(mawk_state_t *, CA_REC *, SYMTAB *);
109 static void field_A2I(mawk_state_t *MAWK);
110 static void check_var(mawk_state_t *, SYMTAB *);
111 static void check_array(mawk_state_t *, SYMTAB *);
112 static void RE_as_arg(mawk_state_t *MAWK);
113
114 void mawk_parser_include(mawk_state_t *MAWK, void *str);
115
116 #define mawk_code_address(x) \
117 do { \
118 if (is_local(x)) \
119 mawk_code2op(MAWK, L_PUSHA, (x)->offset) ;\
120 else \
121 code2(MAWK, _PUSHA, (x)->stval.cp); \
122 } while(0)
123
124 #define CDP(x) (mawk_code_base+(x))
125 /* WARNING: These CDP() calculations become invalid after calls
126 that might change code_base. Which are: code2(), mawk_code2op(),
127 code_jmp() and code_pop().
128 */
129
130 /* this nonsense caters to MSDOS large model */
131 #define CODE_FE_PUSHA() mawk_code_ptr->ptr = (PTR) 0 ; code1(FE_PUSHA)
132
133 %}
134
135 %union{
136 mawk_cell_t *cp ;
137 SYMTAB *stp ;
138 int start ; /* code starting address as offset from code_base */
139 PF_CP fp ; /* ptr to a (print/printf) or (sub/gsub) function */
140 const BI_REC *bip ; /* ptr to info about a builtin */
141 FBLOCK *fbp ; /* ptr to a function block */
142 ARG2_REC *arg2p ;
143 CA_REC *ca_p ;
144 int ival ;
145 PTR ptr ;
146 }
147
148 /* two tokens to help with errors */
149 %token UNEXPECTED /* unexpected character */
150 %token BAD_DECIMAL
151
152 %token NL
153 %token SEMI_COLON
154 %token LBRACE RBRACE
155 %token LBOX RBOX
156 %token COMMA
157 %token <ival> IO_OUT /* > or output pipe */
158
159 %right ASSIGN ADD_ASG SUB_ASG MUL_ASG DIV_ASG MOD_ASG POW_ASG
160 %right QMARK COLON
161 %left OR
162 %left AND
163 %left IN
164 %left <ival> MATCH /* ~ or !~ */
165 %left EQ NEQ LT LTE GT GTE
166 %left CAT
167 %left GETLINE
168 %left PLUS MINUS
169 %left MUL DIV MOD
170 %left NOT UMINUS
171 %nonassoc IO_IN PIPE
172 %right POW
173 %left <ival> INC_or_DEC
174 %left DOLLAR FIELD /* last to remove a SR conflict
175 with getline */
176 %right LPAREN RPAREN /* removes some SR conflicts */
177
178 %token <ptr> DOUBLE STRING_ RE
179 %token <stp> ID D_ID
180 %token <fbp> FUNCT_ID
181 %token <ptr> C_FUNCT_ID
182 %token <bip> BUILTIN LENGTH
183 %token <cp> FIELD
184
185 %token PRINT PRINTF SPLIT MATCH_FUNC SUB GSUB
186 /* keywords */
187 %token DO WHILE FOR BREAK CONTINUE IF ELSE IN
188 %token DELETE BEGIN END EXIT NEXT RETURN FUNCTION INCLUDE
189
190 %type <start> block block_or_separator
191 %type <start> statement_list statement mark
192 %type <ival> pr_args
193 %type <arg2p> arg2
194 %type <start> builtin
195 %type <start> getline_file
196 %type <start> lvalue lvalue_arrwr bifunct_target_arr field bifunct_target
197 %type <start> expr cat_expr p_expr
198 %type <start> while_front if_front
199 %type <start> for1 for2
200 %type <start> array_loop_front
201 %type <start> return_statement
202 %type <start> split_front re_arg sub_back
203 %type <ival> arglist args
204 %type <fp> print sub_or_gsub
205 %type <fbp> funct_start funct_head
206 %type <ca_p> call_args ca_front ca_back
207 %type <ival> f_arglist f_args
208
209 %%
210 /* productions */
211
212 program : program_block
213 | program program_block
214 ;
215
216 program_block : PA_block /* pattern-action */
217 | function_def
218 | outside_error block
219 ;
220
221 PA_block : block
222 { /* this do nothing action removes a vacuous warning
223 from Bison */
224 }
225
226 | include
227
228 | NL /* allow newline anywhere between blocks - normally scan.c eats this up, but include introduces a corner case */
229
230 | BEGIN
231 { mawk_be_setup(MAWK, MAWK->scope = SCOPE_BEGIN) ; }
232
233 block
234 { switch_code_to_main(MAWK) ; }
235
236 | END
237 { mawk_be_setup(MAWK, MAWK->scope = SCOPE_END) ; }
238
239 block
240 { switch_code_to_main(MAWK) ; }
241
242 | expr /* this works just like an if statement */
243 { mawk_code_jmp(MAWK, _JZ, (INST*)0) ; }
244
245 block_or_separator
246 { mawk_patch_jmp(MAWK, mawk_code_ptr ) ; }
247
248 /* range pattern, see comment in mawk_execute.c near _RANGE */
249 | expr COMMA
250 {
251 INST *p1 = CDP($1) ;
252 int len ;
253
254 mawk_code_push(MAWK, p1, mawk_code_ptr - p1, MAWK->scope, MAWK->active_funct) ;
255 mawk_code_ptr = p1 ;
256
257 mawk_code2op(MAWK, _RANGE_CHK, 1) ;
258 mawk_code_ptr += 3 ;
259 len = mawk_code_pop(MAWK, mawk_code_ptr) ;
260 mawk_code_ptr += len ;
261 code1(_RANGE_STOP) ;
262 p1 = CDP($1) ;
263 p1[2].op = mawk_code_ptr - (p1+1) ;
264 }
265 expr
266 { code1(_RANGE_STOP) ; }
267
268 block_or_separator
269 {
270 INST *p1 = CDP($1) ;
271
272 p1[3].op = CDP($6) - (p1+1) ;
273 p1[4].op = mawk_code_ptr - (p1+1) ;
274 }
275 ;
276
277
278
279 block : LBRACE statement_list RBRACE
280 { $$ = $2 ; }
281 | LBRACE error RBRACE
282 { $$ = mawk_code_offset ; /* does nothing won't be mawk_executed */
283 MAWK->print_flag = MAWK->getline_flag = MAWK->paren_cnt = 0 ;
284 yyerrok ; }
285 ;
286
287 block_or_separator : block
288 | separator /* default print action */
289 { $$ = mawk_code_offset ;
290 code1(_PUSHINT) ; code1(0) ;
291 code2(MAWK, _PRINT, mawk_f2d(mawk_bi_print)) ;
292 }
293
294 statement_list : statement
295 | statement_list statement
296 ;
297
298
299 statement : block
300 | expr separator
301 { code1(_POP) ; }
302 | /* empty */ separator
303 { $$ = mawk_code_offset ; }
304 | error separator
305 { $$ = mawk_code_offset ;
306 MAWK->print_flag = MAWK->getline_flag = 0 ;
307 MAWK->paren_cnt = 0 ;
308 yyerrok ;
309 }
310 | BREAK separator
311 { $$ = mawk_code_offset ; mawk_BC_insert(MAWK, 'B', mawk_code_ptr+1) ;
312 code2(MAWK, _JMP, 0) /* don't use mawk_code_jmp ! */ ; }
313 | CONTINUE separator
314 { $$ = mawk_code_offset ; mawk_BC_insert(MAWK, 'C', mawk_code_ptr+1) ;
315 code2(MAWK, _JMP, 0) ; }
316 | return_statement
317 { if ( MAWK->scope != SCOPE_FUNCT )
318 mawk_compile_error(MAWK, "return outside function body") ;
319 }
320 | NEXT separator
321 { if ( MAWK->scope != SCOPE_MAIN )
322 mawk_compile_error(MAWK, "improper use of next" ) ;
323 $$ = mawk_code_offset ;
324 code1(_NEXT) ;
325 }
326 ;
327
328 separator : NL | SEMI_COLON
329 ;
330
331 expr : cat_expr
332 | lvalue ASSIGN expr { code1(_ASSIGN) ; }
333 | lvalue ADD_ASG expr { code1(_ADD_ASG) ; }
334 | lvalue SUB_ASG expr { code1(_SUB_ASG) ; }
335 | lvalue MUL_ASG expr { code1(_MUL_ASG) ; }
336 | lvalue DIV_ASG expr { code1(_DIV_ASG) ; }
337 | lvalue MOD_ASG expr { code1(_MOD_ASG) ; }
338 | lvalue POW_ASG expr { code1(_POW_ASG) ; }
339 | lvalue_arrwr ASSIGN expr { code1(_ASSIGN_ARR) ; }
340 | lvalue_arrwr ADD_ASG expr { code1(_ADD_ASG_ARR) ; }
341 | lvalue_arrwr SUB_ASG expr { code1(_SUB_ASG_ARR) ; }
342 | lvalue_arrwr MUL_ASG expr { code1(_MUL_ASG_ARR) ; }
343 | lvalue_arrwr DIV_ASG expr { code1(_DIV_ASG_ARR) ; }
344 | lvalue_arrwr MOD_ASG expr { code1(_MOD_ASG_ARR) ; }
345 | lvalue_arrwr POW_ASG expr { code1(_POW_ASG_ARR) ; }
346 | expr EQ expr { code1(_EQ) ; }
347 | expr NEQ expr { code1(_NEQ) ; }
348 | expr LT expr { code1(_LT) ; }
349 | expr LTE expr { code1(_LTE) ; }
350 | expr GT expr { code1(_GT) ; }
351 | expr GTE expr { code1(_GTE) ; }
352
353 | expr MATCH expr
354 {
355 INST *p3 = CDP($3) ;
356
357 if ( p3 == mawk_code_ptr - 2 )
358 {
359 if ( p3->op == _MATCH0 ) p3->op = _MATCH1 ;
360
361 else /* check for string */
362 if ( p3->op == _PUSHS )
363 {
364 mawk_cell_t *cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
365
366 cp->type = C_STRING ;
367 cp->ptr = p3[1].ptr ;
368 mawk_cast_to_RE(MAWK, cp) ;
369 mawk_code_ptr -= 2 ;
370 code2(MAWK, _MATCH1, cp->ptr) ;
371 MAWK_ZFREE(MAWK, cp) ;
372 }
373 else code1(_MATCH2) ;
374 }
375 else code1(_MATCH2) ;
376
377 if ( !$2 ) code1(_NOT) ;
378 }
379
380 /* short circuit boolean evaluation */
381 | expr OR
382 { code1(_TEST) ;
383 mawk_code_jmp(MAWK, _LJNZ, (INST*)0) ;
384 }
385 expr
386 { code1(_TEST) ; mawk_patch_jmp(MAWK, mawk_code_ptr) ; }
387
388 | expr AND
389 { code1(_TEST) ;
390 mawk_code_jmp(MAWK, _LJZ, (INST*)0) ;
391 }
392 expr
393 { code1(_TEST) ; mawk_patch_jmp(MAWK, mawk_code_ptr) ; }
394
395 | expr QMARK { mawk_code_jmp(MAWK, _JZ, (INST*)0) ; }
396 expr COLON { mawk_code_jmp(MAWK, _JMP, (INST*)0) ; }
397 expr
398 { mawk_patch_jmp(MAWK, mawk_code_ptr) ; mawk_patch_jmp(MAWK, CDP($7)) ; }
399 ;
400
401 cat_expr : p_expr %prec CAT
402 | cat_expr p_expr %prec CAT
403 { code1(_CAT) ; }
404 ;
405
406 p_expr : DOUBLE
407 { $$ = mawk_code_offset ; code2(MAWK, _PUSHD, $1) ; }
408 | STRING_
409 { $$ = mawk_code_offset ; code2(MAWK, _PUSHS, $1) ; }
410 | ID %prec AND /* anything less than IN */
411 { check_var(MAWK, $1) ;
412 $$ = mawk_code_offset ;
413 if ( is_local($1) )
414 { mawk_code2op(MAWK, L_PUSHI, $1->offset) ; }
415 else code2(MAWK, _PUSHI, $1->stval.cp) ;
416 }
417
418 | LPAREN expr RPAREN
419 { $$ = $2 ; }
420 ;
421
422 p_expr : RE
423 { $$ = mawk_code_offset ; code2(MAWK, _MATCH0, $1) ; }
424 ;
425
426 p_expr : p_expr PLUS p_expr { code1(_ADD) ; }
427 | p_expr MINUS p_expr { code1(_SUB) ; }
428 | p_expr MUL p_expr { code1(_MUL) ; }
429 | p_expr DIV p_expr { code1(_DIV) ; }
430 | p_expr MOD p_expr { code1(_MOD) ; }
431 | p_expr POW p_expr { code1(_POW) ; }
432 | NOT p_expr
433 { $$ = $2 ; code1(_NOT) ; }
434 | PLUS p_expr %prec UMINUS
435 { $$ = $2 ; code1(_UPLUS) ; }
436 | MINUS p_expr %prec UMINUS
437 { $$ = $2 ; code1(_UMINUS) ; }
438 | builtin
439 ;
440
441 p_expr : ID INC_or_DEC
442 { check_var(MAWK, $1) ;
443 $$ = mawk_code_offset ;
444 mawk_code_address($1) ;
445
446 if ( $2 == '+' ) code1(_POST_INC) ;
447 else code1(_POST_DEC) ;
448 }
449 | INC_or_DEC lvalue
450 { $$ = $2 ;
451 if ( $1 == '+' ) code1(_PRE_INC) ;
452 else code1(_PRE_DEC) ;
453 }
454 | INC_or_DEC lvalue_arrwr
455 { $$ = $2 ;
456 if ( $1 == '+' ) code1(_PRE_INC_ARR) ;
457 else code1(_PRE_DEC_ARR) ;
458 }
459 ;
460
461 p_expr : field INC_or_DEC
462 { if ($2 == '+' ) code1(F_POST_INC ) ;
463 else code1(F_POST_DEC) ;
464 }
465 | INC_or_DEC field
466 { $$ = $2 ;
467 if ( $1 == '+' ) code1(F_PRE_INC) ;
468 else code1( F_PRE_DEC) ;
469 }
470 ;
471
472 lvalue : ID
473 { $$ = mawk_code_offset ;
474 check_var(MAWK, $1) ;
475 mawk_code_address($1) ;
476 }
477 ;
478
479
480 arglist : /* empty */
481 { $$ = 0 ; }
482 | args
483 ;
484
485 args : expr %prec LPAREN
486 { $$ = 1 ; }
487 | args COMMA expr
488 { $$ = $1 + 1 ; }
489 ;
490
491 builtin :
492 BUILTIN mark LPAREN arglist RPAREN
493 { const BI_REC *p = $1 ;
494 $$ = $2 ;
495 if ( (int)p->min_args > $4 || (int)p->max_args < $4 )
496 mawk_compile_error(
497 MAWK, "wrong number of arguments in call to %s" ,
498 p->name ) ;
499 if ( p->min_args != p->max_args ) /* variable args */
500 { code1(_PUSHINT) ; code1($4) ; }
501 code2(MAWK, _BUILTIN , mawk_f2d(p->fp)) ;
502 }
503 | LENGTH /* this is an irritation */
504 {
505 $$ = mawk_code_offset ;
506 code1(_PUSHINT) ; code1(0) ;
507 code2(MAWK, _BUILTIN, mawk_f2d($1->fp)) ;
508 }
509 ;
510
511 /* an empty production to store the mawk_code_ptr */
512 mark : /* empty */
513 { $$ = mawk_code_offset ; }
514
515 /* print_statement */
516 statement : print mark pr_args pr_direction separator
517 { code2(MAWK, _PRINT, mawk_f2d($1)) ;
518 if ( $1 == mawk_bi_printf && $3 == 0 )
519 mawk_compile_error(MAWK, "no arguments in call to printf") ;
520 MAWK->print_flag = 0 ;
521 $$ = $2 ;
522 }
523 ;
524
525 print : PRINT { $$ = mawk_bi_print ; MAWK->print_flag = 1 ;}
526 | PRINTF { $$ = mawk_bi_printf ; MAWK->print_flag = 1 ; }
527 ;
528
529 pr_args : arglist { mawk_code2op(MAWK, _PUSHINT, $1) ; }
530 | LPAREN arg2 RPAREN
531 { $$ = $2->cnt ; mawk_zfree(MAWK, $2,sizeof(ARG2_REC)) ;
532 mawk_code2op(MAWK, _PUSHINT, $$) ;
533 }
534 | LPAREN RPAREN
535 { $$=0 ; mawk_code2op(MAWK, _PUSHINT, 0) ; }
536 ;
537
538 arg2 : expr COMMA expr
539 { $$ = (ARG2_REC*) mawk_zmalloc(MAWK, sizeof(ARG2_REC)) ;
540 $$->start = $1 ;
541 $$->cnt = 2 ;
542 }
543 | arg2 COMMA expr
544 { $$ = $1 ; $$->cnt++ ; }
545 ;
546
547 pr_direction : /* empty */
548 | IO_OUT expr
549 { mawk_code2op(MAWK, _PUSHINT, $1) ; }
550 ;
551
552
553 /* IF and IF-ELSE */
554
555 if_front : IF LPAREN expr RPAREN
556 { $$ = $3 ; mawk_eat_nl(MAWK, &yylval) ; mawk_code_jmp(MAWK, _JZ, (INST*)0) ; }
557 ;
558
559 /* if_statement */
560 statement : if_front statement
561 { mawk_patch_jmp(MAWK, mawk_code_ptr ) ; }
562 ;
563
564 else : ELSE { mawk_eat_nl(MAWK, &yylval) ; mawk_code_jmp(MAWK, _JMP, (INST*)0) ; }
565 ;
566
567 /* if_else_statement */
568 statement : if_front statement else statement
569 { mawk_patch_jmp(MAWK, mawk_code_ptr) ;
570 mawk_patch_jmp(MAWK, CDP($4)) ;
571 }
572
573
574 /* LOOPS */
575
576 do : DO
577 { mawk_eat_nl(MAWK, &yylval) ; mawk_BC_new(MAWK) ; }
578 ;
579
580 /* do_statement */
581 statement : do statement WHILE LPAREN expr RPAREN separator
582 { $$ = $2 ;
583 mawk_code_jmp(MAWK, _JNZ, CDP($2)) ;
584 mawk_BC_clear(MAWK, mawk_code_ptr, CDP($5)) ; }
585 ;
586
587 while_front : WHILE LPAREN expr RPAREN
588 { mawk_eat_nl(MAWK, &yylval) ; mawk_BC_new(MAWK) ;
589 $$ = $3 ;
590
591 /* check if const expression */
592 if ( mawk_code_ptr - 2 == CDP($3) &&
593 mawk_code_ptr[-2].op == _PUSHD &&
594 *(double*)mawk_code_ptr[-1].ptr != 0.0
595 )
596 mawk_code_ptr -= 2 ;
597 else
598 { INST *p3 = CDP($3) ;
599 mawk_code_push(MAWK, p3, mawk_code_ptr-p3, MAWK->scope, MAWK->active_funct) ;
600 mawk_code_ptr = p3 ;
601 code2(MAWK, _JMP, (INST*)0) ; /* code2() not mawk_code_jmp() */
602 }
603 }
604 ;
605
606 /* while_statement */
607 statement : while_front statement
608 {
609 int saved_offset ;
610 int len ;
611 INST *p1 = CDP($1) ;
612 INST *p2 = CDP($2) ;
613
614 if ( p1 != p2 ) /* real mawk_test in loop */
615 {
616 p1[1].op = mawk_code_ptr-(p1+1) ;
617 saved_offset = mawk_code_offset ;
618 len = mawk_code_pop(MAWK, mawk_code_ptr) ;
619 mawk_code_ptr += len ;
620 mawk_code_jmp(MAWK, _JNZ, CDP($2)) ;
621 mawk_BC_clear(MAWK, mawk_code_ptr, CDP(saved_offset)) ;
622 }
623 else /* while(1) */
624 {
625 mawk_code_jmp(MAWK, _JMP, p1) ;
626 mawk_BC_clear(MAWK, mawk_code_ptr, CDP($2)) ;
627 }
628 }
629 ;
630
631
632 /* for_statement */
633 statement : for1 for2 for3 statement
634 {
635 int cont_offset = mawk_code_offset ;
636 unsigned len = mawk_code_pop(MAWK, mawk_code_ptr) ;
637 INST *p2 = CDP($2) ;
638 INST *p4 = CDP($4) ;
639
640 mawk_code_ptr += len ;
641
642 if ( p2 != p4 ) /* real mawk_test in for2 */
643 {
644 p4[-1].op = mawk_code_ptr - p4 + 1 ;
645 len = mawk_code_pop(MAWK, mawk_code_ptr) ;
646 mawk_code_ptr += len ;
647 mawk_code_jmp(MAWK, _JNZ, CDP($4)) ;
648 }
649 else /* for(;;) */
650 mawk_code_jmp(MAWK, _JMP, p4) ;
651
652 mawk_BC_clear(MAWK, mawk_code_ptr, CDP(cont_offset)) ;
653
654 }
655 ;
656
657 for1 : FOR LPAREN SEMI_COLON { $$ = mawk_code_offset ; }
658 | FOR LPAREN expr SEMI_COLON
659 { $$ = $3 ; code1(_POP) ; }
660 ;
661
662 for2 : SEMI_COLON { $$ = mawk_code_offset ; }
663 | expr SEMI_COLON
664 {
665 if ( mawk_code_ptr - 2 == CDP($1) &&
666 mawk_code_ptr[-2].op == _PUSHD &&
667 * (double*) mawk_code_ptr[-1].ptr != 0.0
668 )
669 mawk_code_ptr -= 2 ;
670 else
671 {
672 INST *p1 = CDP($1) ;
673 mawk_code_push(MAWK, p1, mawk_code_ptr-p1, MAWK->scope, MAWK->active_funct) ;
674 mawk_code_ptr = p1 ;
675 code2(MAWK, _JMP, (INST*)0) ;
676 }
677 }
678 ;
679
680 for3 : RPAREN
681 { mawk_eat_nl(MAWK, &yylval) ; mawk_BC_new(MAWK) ;
682 mawk_code_push(MAWK, (INST*)0,0, MAWK->scope, MAWK->active_funct) ;
683 }
684 | expr RPAREN
685 { INST *p1 = CDP($1) ;
686
687 mawk_eat_nl(MAWK, &yylval) ; mawk_BC_new(MAWK) ;
688 code1(_POP) ;
689 mawk_code_push(MAWK, p1, mawk_code_ptr - p1, MAWK->scope, MAWK->active_funct) ;
690 mawk_code_ptr -= mawk_code_ptr - p1 ;
691 }
692 ;
693
694
695 /* arrays */
696
697 expr : expr IN ID
698 { check_array(MAWK, $3) ;
699 mawk_code_array(MAWK, $3) ;
700 code1(A_TEST) ;
701 }
702 | LPAREN arg2 RPAREN IN ID
703 { $$ = $2->start ;
704 mawk_code2op(MAWK, A_CAT, $2->cnt) ;
705 mawk_zfree(MAWK, $2, sizeof(ARG2_REC)) ;
706
707 check_array(MAWK, $5) ;
708 mawk_code_array(MAWK, $5) ;
709 code1(A_TEST) ;
710 }
711 ;
712
713 /* array reference for a variable that is in the target (writable) part of
714 a bi_funct call such as gsub, sub or getline */
715 bifunct_target_arr : ID mark LBOX args RBOX
716 {
717 if ( $4 > 1 )
718 { mawk_code2op(MAWK, A_CAT, $4) ; }
719
720 check_array(MAWK, $1) ;
721 if( is_local($1) )
722 { mawk_code2op(MAWK, LAE_PUSHA, $1->offset) ; }
723 else code2(MAWK, AE_PUSHA, $1->stval.array) ;
724 $$ = $2 ;
725 }
726 ;
727
728 lvalue_arrwr : ID mark LBOX args RBOX
729 {
730 if ( $4 > 1 )
731 { mawk_code2op(MAWK, A_CAT, $4) ; }
732
733 check_array(MAWK, $1) ;
734 if( is_local($1) )
735 { mawk_code2op(MAWK, LAE_PUSHA_WRARR, $1->offset) ; }
736 else code2(MAWK, AE_PUSHA_WRARR, $1->stval.array) ;
737 $$ = $2 ;
738 }
739 ;
740
741 p_expr : ID mark LBOX args RBOX %prec AND
742 {
743 if ( $4 > 1 )
744 { mawk_code2op(MAWK, A_CAT, $4) ; }
745
746 check_array(MAWK, $1) ;
747 if( is_local($1) )
748 { mawk_code2op(MAWK, LAE_PUSHI, $1->offset) ; }
749 else code2(MAWK, AE_PUSHI, $1->stval.array) ;
750 $$ = $2 ;
751 }
752
753 | ID mark LBOX args RBOX INC_or_DEC
754 {
755 if ( $4 > 1 )
756 { mawk_code2op(MAWK, A_CAT,$4) ; }
757
758 check_array(MAWK, $1) ;
759 if( is_local($1) )
760 { mawk_code2op(MAWK, LAE_PUSHA_WRARR, $1->offset) ; }
761 else code2(MAWK, AE_PUSHA_WRARR, $1->stval.array) ;
762 if ( $6 == '+' ) code1(_POST_INC_ARR) ;
763 else code1(_POST_DEC_ARR) ;
764
765 $$ = $2 ;
766 }
767 ;
768
769 /* delete A[i] or delete A */
770 statement : DELETE ID mark LBOX args RBOX separator
771 {
772 $$ = $3 ;
773 if ( $5 > 1 ) { mawk_code2op(MAWK, A_CAT, $5) ; }
774 check_array(MAWK, $2) ;
775 mawk_code_array(MAWK, $2) ;
776 code1(A_DEL) ;
777 }
778 | DELETE ID separator
779 {
780 $$ = mawk_code_offset ;
781 check_array(MAWK, $2) ;
782 mawk_code_array(MAWK, $2) ;
783 code1(DEL_A) ;
784 }
785 ;
786
787 /* for ( i in A ) statement */
788
789 array_loop_front : FOR LPAREN ID IN ID RPAREN
790 { mawk_eat_nl(MAWK, &yylval) ; mawk_BC_new(MAWK) ;
791 $$ = mawk_code_offset ;
792
793 check_var(MAWK, $3) ;
794 mawk_code_address($3) ;
795 check_array(MAWK, $5) ;
796 mawk_code_array(MAWK, $5) ;
797
798 code2(MAWK, SET_ALOOP, (INST*)0) ;
799 }
800 ;
801
802 /* array_loop */
803 statement : array_loop_front statement
804 {
805 INST *p2 = CDP($2) ;
806
807 p2[-1].op = mawk_code_ptr - p2 + 1 ;
808 mawk_BC_clear(MAWK, mawk_code_ptr+2 , mawk_code_ptr) ;
809 mawk_code_jmp(MAWK, ALOOP, p2) ;
810 code1(POP_AL) ;
811 }
812 ;
813
814 /* fields
815 D_ID is a special token , same as an ID, but yylex()
816 only returns it after a '$'. In essense,
817 DOLLAR D_ID is really one token.
818 */
819
820 field : FIELD
821 { $$ = mawk_code_offset ; code2(MAWK, F_PUSHA, $1) ; }
822 | DOLLAR D_ID
823 { check_var(MAWK, $2) ;
824 $$ = mawk_code_offset ;
825 if ( is_local($2) )
826 { mawk_code2op(MAWK, L_PUSHI, $2->offset) ; }
827 else code2(MAWK, _PUSHI, $2->stval.cp) ;
828
829 CODE_FE_PUSHA() ;
830 }
831 | DOLLAR D_ID mark LBOX args RBOX
832 {
833 if ( $5 > 1 )
834 { mawk_code2op(MAWK, A_CAT, $5) ; }
835
836 check_array(MAWK, $2) ;
837 if( is_local($2) )
838 { mawk_code2op(MAWK, LAE_PUSHI, $2->offset) ; }
839 else code2(MAWK, AE_PUSHI, $2->stval.array) ;
840
841 CODE_FE_PUSHA() ;
842
843 $$ = $3 ;
844 }
845 | DOLLAR p_expr
846 { $$ = $2 ; CODE_FE_PUSHA() ; }
847 | LPAREN field RPAREN
848 { $$ = $2 ; }
849 ;
850
851 p_expr : field %prec CAT /* removes field (++|--) sr conflict */
852 { field_A2I(MAWK) ; }
853 ;
854
855 expr : field ASSIGN expr { code1(F_ASSIGN) ; }
856 | field ADD_ASG expr { code1(F_ADD_ASG) ; }
857 | field SUB_ASG expr { code1(F_SUB_ASG) ; }
858 | field MUL_ASG expr { code1(F_MUL_ASG) ; }
859 | field DIV_ASG expr { code1(F_DIV_ASG) ; }
860 | field MOD_ASG expr { code1(F_MOD_ASG) ; }
861 | field POW_ASG expr { code1(F_POW_ASG) ; }
862 ;
863
864 /* split is handled different than a builtin because
865 it takes an array and optionally a regular expression as args */
866
867 p_expr : split_front split_back
868 { code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_split)) ; }
869 ;
870
871 split_front : SPLIT LPAREN expr COMMA ID
872 { $$ = $3 ;
873 check_array(MAWK, $5) ;
874 mawk_code_array(MAWK, $5) ;
875 }
876 ;
877
878 split_back : RPAREN
879 { code2(MAWK, _PUSHI, &MAWK->fs_shadow) ; }
880 | COMMA expr RPAREN
881 {
882 if ( CDP($2) == mawk_code_ptr - 2 )
883 {
884 if ( mawk_code_ptr[-2].op == _MATCH0 )
885 RE_as_arg(MAWK) ;
886 else
887 if ( mawk_code_ptr[-2].op == _PUSHS )
888 { mawk_cell_t *cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
889
890 cp->type = C_STRING ;
891 cp->ptr = mawk_code_ptr[-1].ptr ;
892 mawk_cast_for_split(MAWK, cp) ;
893 mawk_code_ptr[-2].op = _PUSHC ;
894 mawk_code_ptr[-1].ptr = (PTR) cp ;
895 }
896 }
897 }
898 ;
899
900
901
902 /* match(expr, RE) */
903
904 p_expr : MATCH_FUNC LPAREN expr COMMA re_arg RPAREN
905 { $$ = $3 ;
906 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_match)) ;
907 }
908 ;
909
910
911 re_arg : expr
912 {
913 INST *p1 = CDP($1) ;
914
915 if ( p1 == mawk_code_ptr - 2 )
916 {
917 if ( p1->op == _MATCH0 ) RE_as_arg(MAWK) ;
918 else
919 if ( p1->op == _PUSHS )
920 { mawk_cell_t *cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
921
922 cp->type = C_STRING ;
923 cp->ptr = p1[1].ptr ;
924 mawk_cast_to_RE(MAWK, cp) ;
925 p1->op = _PUSHC ;
926 p1[1].ptr = (PTR) cp ;
927 }
928 }
929 }
930
931
932
933 /* exit_statement */
934 statement : EXIT separator
935 { $$ = mawk_code_offset ;
936 code1(_EXIT0) ; }
937 | EXIT expr separator
938 { $$ = $2 ; code1(_EXIT) ; }
939
940 return_statement : RETURN separator
941 { $$ = mawk_code_offset ;
942 code1(_RET0) ; }
943 | RETURN expr separator
944 { $$ = $2 ; code1(_RET) ; }
945
946 /* getline */
947
948 p_expr : getline %prec GETLINE
949 { $$ = mawk_code_offset ;
950 code2(MAWK, F_PUSHA, &MAWK->field[0]) ;
951 code1(_PUSHINT) ; code1(0) ;
952 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_getline)) ;
953 MAWK->getline_flag = 0 ;
954 }
955 | getline bifunct_target %prec GETLINE
956 { $$ = $2 ;
957 code1(_PUSHINT) ; code1(0) ;
958 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_getline)) ;
959 MAWK->getline_flag = 0 ;
960 }
961 | getline_file p_expr %prec IO_IN
962 { code1(_PUSHINT) ; code1(F_IN) ;
963 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_getline)) ;
964 /* getline_flag already off in yylex() */
965 }
966 | p_expr PIPE GETLINE
967 { code2(MAWK, F_PUSHA, &MAWK->field[0]) ;
968 code1(_PUSHINT) ; code1(PIPE_IN) ;
969 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_getline)) ;
970 }
971 | p_expr PIPE GETLINE bifunct_target
972 {
973 code1(_PUSHINT) ; code1(PIPE_IN) ;
974 code2(MAWK, _BUILTIN, mawk_f2d(mawk_bi_getline)) ;
975 }
976 ;
977
978 getline : GETLINE { MAWK->getline_flag = 1 ; }
979
980 /* gsub(), sub() and getline has to modify one of their args; the arg has
981 to be a bifunct_target for reference pass */
982 bifunct_target : lvalue | bifunct_target_arr | field ;
983
984 getline_file : getline IO_IN
985 { $$ = mawk_code_offset ;
986 code2(MAWK, F_PUSHA, MAWK->field+0) ;
987 }
988 | getline bifunct_target IO_IN
989 { $$ = $2 ; }
990 ;
991
992 /*==========================================
993 sub and gsub
994 ==========================================*/
995
996 p_expr : sub_or_gsub LPAREN re_arg COMMA expr sub_back
997 {
998 INST *p5 = CDP($5) ;
999 INST *p6 = CDP($6) ;
1000
1001 if ( p6 - p5 == 2 && p5->op == _PUSHS )
1002 { /* cast from STRING to REPL at compile time */
1003 mawk_cell_t *cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
1004 cp->type = C_STRING ;
1005 cp->ptr = p5[1].ptr ;
1006 mawk_cast_to_REPL(MAWK, cp) ;
1007 p5->op = _PUSHC ;
1008 p5[1].ptr = (PTR) cp ;
1009 }
1010 code2(MAWK, _BUILTIN, mawk_f2d($1)) ;
1011 $$ = $3 ;
1012 }
1013 ;
1014
1015 sub_or_gsub : SUB { $$ = mawk_bi_sub ; }
1016 | GSUB { $$ = mawk_bi_gsub ; }
1017 ;
1018
1019
1020 sub_back : RPAREN /* substitute into $0 */
1021 { $$ = mawk_code_offset ;
1022 code2(MAWK, F_PUSHA, &MAWK->field[0]) ;
1023 }
1024
1025 | COMMA bifunct_target RPAREN
1026 { $$ = $2 ; }
1027 ;
1028
1029 /*================================================
1030 user defined functions
1031 *=================================*/
1032
1033 function_def : funct_start block
1034 {
1035 resize_fblock(MAWK, $1) ;
1036 mawk_restore_ids(MAWK) ;
1037 switch_code_to_main(MAWK) ;
1038 }
1039 ;
1040
1041 funct_start : funct_head LPAREN f_arglist RPAREN
1042 { mawk_eat_nl(MAWK, &yylval) ;
1043 MAWK->scope = SCOPE_FUNCT ;
1044 MAWK->active_funct = $1 ;
1045 *MAWK->main_code_p = MAWK->active_code ;
1046
1047 $1->nargs = $3 ;
1048 if ( $3 )
1049 $1->typev = (char *)
1050 memset( mawk_zmalloc(MAWK, $3), ST_LOCAL_NONE, $3) ;
1051 else $1->typev = (char *) 0 ;
1052
1053 mawk_code_ptr = mawk_code_base =
1054 (INST *) mawk_zmalloc(MAWK, INST_BYTES(PAGESZ));
1055 mawk_code_limit = mawk_code_base + PAGESZ ;
1056 mawk_code_warn = mawk_code_limit - CODEWARN ;
1057 }
1058 ;
1059
1060 funct_head : FUNCTION ID
1061 { FBLOCK *fbp ;
1062
1063 if ( $2->type == ST_NONE )
1064 {
1065 $2->type = ST_FUNCT ;
1066 fbp = $2->stval.fbp =
1067 (FBLOCK *) mawk_zmalloc(MAWK, sizeof(FBLOCK)) ;
1068 fbp->name = $2->name ;
1069 fbp->code = (INST*) 0 ;
1070 }
1071 else
1072 {
1073 mawk_type_error(MAWK, $2 ) ;
1074
1075 /* this FBLOCK will not be put in
1076 the symbol table */
1077 fbp = (FBLOCK*) mawk_zmalloc(MAWK, sizeof(FBLOCK)) ;
1078 fbp->name = "" ;
1079 }
1080 $$ = fbp ;
1081 }
1082
1083 | FUNCTION FUNCT_ID
1084 { $$ = $2 ;
1085 if ( $2->code )
1086 mawk_compile_error(MAWK, "redefinition of %s" , $2->name) ;
1087 }
1088 ;
1089
1090 f_arglist : /* empty */ { $$ = 0 ; }
1091 | f_args
1092 ;
1093
1094 f_args : ID
1095 { $1 = mawk_save_id(MAWK, $1->name) ;
1096 $1->type = ST_LOCAL_NONE ;
1097 $1->offset = 0 ;
1098 $$ = 1 ;
1099 }
1100 | f_args COMMA ID
1101 { if ( is_local($3) )
1102 mawk_compile_error(MAWK, "%s is duplicated in argument list",
1103 $3->name) ;
1104 else
1105 { $3 = mawk_save_id(MAWK, $3->name) ;
1106 $3->type = ST_LOCAL_NONE ;
1107 $3->offset = $1 ;
1108 $$ = $1 + 1 ;
1109 }
1110 }
1111 ;
1112
1113 outside_error : error
1114 { /* we may have to recover from a bungled function
1115 definition */
1116 /* can have local ids, before code scope
1117 changes */
1118 mawk_restore_ids(MAWK) ;
1119
1120 switch_code_to_main(MAWK) ;
1121 }
1122 ;
1123
1124 /* a call to a user defined function */
1125 p_expr : FUNCT_ID mark call_args
1126 { $$ = $2 ;
1127 code2(MAWK, _CALL, $1) ;
1128
1129 if ( $3 ) code1($3->arg_num+1) ;
1130 else code1(0) ;
1131
1132 mawk_check_fcall(MAWK, $1, MAWK->scope, MAWK->ps.code_move_level, MAWK->active_funct,
1133 $3, MAWK->token_lineno) ;
1134 }
1135 ;
1136
1137 p_expr : C_FUNCT_ID mark call_args
1138 { $$ = $2 ;
1139 code2(MAWK, _CALL, $1) ;
1140
1141 if ( $3 ) code1($3->arg_num+1) ;
1142 else code1(0) ;
1143 }
1144 ;
1145
1146 call_args : LPAREN RPAREN
1147 { $$ = (CA_REC *) 0 ; }
1148 | ca_front ca_back
1149 { $$ = $2 ;
1150 $$->link = $1 ;
1151 $$->arg_num = $1 ? $1->arg_num+1 : 0 ;
1152 }
1153 ;
1154
1155 /* The funny definition of ca_front with the COMMA bound to the ID is to
1156 force a shift to avoid a reduce/reduce conflict
1157 ID->id or ID->array
1158
1159 Or to avoid a decision, if the type of the ID has not yet been
1160 determined
1161 */
1162
1163 ca_front : LPAREN
1164 { $$ = (CA_REC *) 0 ; }
1165 | ca_front expr COMMA
1166 { $$ = MAWK_ZMALLOC(MAWK, CA_REC) ;
1167 $$->link = $1 ;
1168 $$->type = CA_EXPR ;
1169 $$->arg_num = $1 ? $1->arg_num+1 : 0 ;
1170 $$->call_offset = mawk_code_offset ;
1171 }
1172 | ca_front ID COMMA
1173 { $$ = MAWK_ZMALLOC(MAWK, CA_REC) ;
1174 $$->link = $1 ;
1175 $$->arg_num = $1 ? $1->arg_num+1 : 0 ;
1176
1177 mawk_code_call_id(MAWK, $$, $2) ;
1178 }
1179 ;
1180
1181 ca_back : expr RPAREN
1182 { $$ = MAWK_ZMALLOC(MAWK, CA_REC) ;
1183 $$->type = CA_EXPR ;
1184 $$->call_offset = mawk_code_offset ;
1185 }
1186
1187 | ID RPAREN
1188 { $$ = MAWK_ZMALLOC(MAWK, CA_REC) ;
1189 mawk_code_call_id(MAWK, $$, $1) ;
1190 }
1191 ;
1192
1193
1194 include:
1195 INCLUDE STRING_ { mawk_parser_include(MAWK, $2); }
1196 ;
1197
1198 multi_nl:
1199 NL
1200 | multi_nl NL
1201 ;
1202
1203 %%
1204
1205 /* resize the code for a user function */
1206
1207 static void resize_fblock(mawk_state_t *MAWK, FBLOCK *fbp)
1208 {
1209 CODEBLOCK *p = MAWK_ZMALLOC(MAWK, CODEBLOCK) ;
1210
1211 mawk_code2op(MAWK, _RET0, _HALT) ;
1212 /* make sure there is always a return */
1213
1214 *p = MAWK->active_code ;
1215 fbp->code = mawk_code_shrink(MAWK, p, &fbp->size) ;
1216 /* mawk_code_shrink() zfrees p */
1217
1218 /* this list is alos used to free functions in pedantic mode */
1219 #ifndef MAWK_MEM_PEDANTIC
1220 if ( MAWK->dump_code_flag )
1221 #endif
1222 mawk_add_to_fdump_list(MAWK, fbp) ;
1223 /* printf("CODE add: %p/%d\n", fbp->code, fbp->size);*/
1224 }
1225
1226
1227 /* convert FE_PUSHA to FE_PUSHI
1228 or F_PUSH to F_PUSHI
1229 */
1230 static void field_A2I(mawk_state_t *MAWK)
1231 {
1232 mawk_cell_t *cp;
1233
1234 if ( mawk_code_ptr[-1].op == FE_PUSHA &&
1235 mawk_code_ptr[-1].ptr == (PTR) 0)
1236 /* On most architectures, the two mawk_tests are the same; a good
1237 compiler might eliminate one. On LM_DOS, and possibly other
1238 segmented architectures, they are not */
1239 { mawk_code_ptr[-1].op = FE_PUSHI ; }
1240 else
1241 {
1242 cp = (mawk_cell_t *) mawk_code_ptr[-1].ptr ;
1243
1244 if (cp == MAWK->field || (cp > MAWK_NF && cp <= LAST_PFIELD))
1245 {
1246 mawk_code_ptr[-2].op = _PUSHI ;
1247 }
1248 else if ( cp == MAWK_NF )
1249 { mawk_code_ptr[-2].op = NF_PUSHI ; mawk_code_ptr-- ; }
1250
1251 else
1252 {
1253 mawk_code_ptr[-2].op = F_PUSHI ;
1254 mawk_code_ptr -> op = mawk_field_addr_to_index(MAWK, mawk_code_ptr[-1].ptr ) ;
1255 mawk_code_ptr++ ;
1256 }
1257 }
1258 }
1259
1260 /* we've seen an ID in a context where it should be a VAR,
1261 check that's consistent with previous usage */
1262 static void check_var(mawk_state_t *MAWK, register SYMTAB *p)
1263 {
1264 switch(p->type)
1265 {
1266 case ST_NONE : /* new id */
1267 p->type = ST_VAR ;
1268 p->stval.cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
1269 p->stval.cp->type = C_NOINIT ;
1270 break ;
1271
1272 case ST_LOCAL_NONE :
1273 p->type = ST_LOCAL_VAR ;
1274 MAWK->active_funct->typev[p->offset] = ST_LOCAL_VAR ;
1275 break ;
1276
1277 case ST_VAR :
1278 case ST_LOCAL_VAR : break ;
1279
1280 default :
1281 mawk_type_error(MAWK, p) ;
1282 break ;
1283 }
1284 }
1285
1286 /* we've seen an ID in a context where it should be an ARRAY,
1287 check that's consistent with previous usage */
1288 static void check_array(mawk_state_t *MAWK, register SYMTAB *p)
1289 {
1290 switch(p->type)
1291 {
1292 case ST_NONE : /* a new array */
1293 p->type = ST_ARRAY ;
1294 p->stval.array = mawk_array_new(MAWK, NULL) ;
1295 break ;
1296
1297 case ST_ARRAY :
1298 case ST_LOCAL_ARRAY :
1299 break ;
1300
1301 case ST_LOCAL_NONE :
1302 p->type = ST_LOCAL_ARRAY ;
1303 MAWK->active_funct->typev[p->offset] = ST_LOCAL_ARRAY ;
1304 break ;
1305
1306 default : mawk_type_error(MAWK, p) ; break ;
1307 }
1308 }
1309
1310 static void mawk_code_array(mawk_state_t *MAWK, register SYMTAB *p)
1311 {
1312 if ( is_local(p) ) mawk_code2op(MAWK, LA_PUSHA, p->offset) ;
1313 else code2(MAWK, A_PUSHA, p->stval.array) ;
1314 }
1315
1316
1317 /* we've seen an ID as an argument to a user defined function */
1318 static void mawk_code_call_id(mawk_state_t *MAWK, register CA_REC *p, register SYMTAB *ip)
1319 {
1320 p->call_offset = mawk_code_offset ;
1321 /* This always get set now. So that fcall:relocate_arglist
1322 works. */
1323
1324 switch( ip->type )
1325 {
1326 case ST_VAR :
1327 p->type = CA_EXPR ;
1328 code2(MAWK, _PUSHI, ip->stval.cp) ;
1329 break ;
1330
1331 case ST_LOCAL_VAR :
1332 p->type = CA_EXPR ;
1333 mawk_code2op(MAWK, L_PUSHI, ip->offset) ;
1334 break ;
1335
1336 case ST_ARRAY :
1337 p->type = CA_ARRAY ;
1338 code2(MAWK, A_PUSHA, ip->stval.array) ;
1339 break ;
1340
1341 case ST_LOCAL_ARRAY :
1342 p->type = CA_ARRAY ;
1343 mawk_code2op(MAWK, LA_PUSHA, ip->offset) ;
1344 break ;
1345
1346 /* not enough info to code it now; it will have to
1347 be patched later */
1348
1349 case ST_NONE :
1350 p->type = ST_NONE ;
1351 p->sym_p = ip ;
1352 code2(MAWK, _PUSHI, &MAWK->code_call_id_dummy) ;
1353 break ;
1354
1355 case ST_LOCAL_NONE :
1356 p->type = ST_LOCAL_NONE ;
1357 p->type_p = & MAWK->active_funct->typev[ip->offset] ;
1358 mawk_code2op(MAWK, L_PUSHI, ip->offset) ;
1359 break ;
1360
1361 #ifdef DEBUG
1362 default :
1363 mawk_bozo(MAWK, "mawk_code_call_id") ;
1364 #endif
1365
1366 }
1367 }
1368
1369 /* an RE by itself was coded as _MATCH0 , change to
1370 push as an expression */
1371
1372 static void RE_as_arg(mawk_state_t *MAWK)
1373 {
1374 mawk_cell_t *cp = MAWK_ZMALLOC(MAWK, mawk_cell_t) ;
1375
1376 mawk_code_ptr -= 2 ;
1377 cp->type = C_RE ;
1378 cp->ptr = mawk_code_ptr[1].ptr ;
1379 code2(MAWK, _PUSHC, cp) ;
1380 }
1381
1382 /* reset the active_code back to the MAIN block */
1383 static void switch_code_to_main(mawk_state_t *MAWK)
1384 {
1385 switch(MAWK->scope)
1386 {
1387 case SCOPE_BEGIN :
1388 *MAWK->begin_code_p = MAWK->active_code ;
1389 MAWK->active_code = *MAWK->main_code_p ;
1390 break ;
1391
1392 case SCOPE_END :
1393 *MAWK->end_code_p = MAWK->active_code ;
1394 MAWK->active_code = *MAWK->main_code_p ;
1395 break ;
1396
1397 case SCOPE_FUNCT :
1398 MAWK->active_code = *MAWK->main_code_p ;
1399 break ;
1400
1401 case SCOPE_MAIN :
1402 break ;
1403 }
1404 MAWK->active_funct = (FBLOCK*) 0 ;
1405 MAWK->scope = SCOPE_MAIN ;
1406 }
1407
1408
1409 void mawk_parse(mawk_state_t *MAWK)
1410 {
1411 if (!MAWK->binary_loaded) {
1412 if ( yyparse(MAWK) || MAWK->compile_error_count != 0 ) mawk_exit(MAWK, 2) ;
1413
1414 mawk_scan_cleanup(MAWK) ;
1415 mawk_set_code(MAWK) ;
1416 /* code must be set before call to mawk_resolve_fcalls() */
1417 if ( MAWK->resolve_list ) mawk_resolve_fcalls(MAWK) ;
1418 }
1419
1420 if ( MAWK->compile_error_count != 0 ) mawk_exit(MAWK, 2) ;
1421 if ( MAWK->dump_code_flag ) { mawk_dump_code(MAWK);}
1422 if ( MAWK->dump_sym_flag ) { mawk_dump_sym_text(MAWK); }
1423 if ((MAWK->dump_code_flag ) || ( MAWK->dump_sym_flag )) { mawk_exit(MAWK, 0); }
1424
1425 (void)mawk_d2f(NULL); /* suppress compiler warning */
1426 }
1427
1428
1429 void mawk_parser_include(mawk_state_t *MAWK, void *str)
1430 {
1431 mawk_parser_push(MAWK);
1432
1433 MAWK->ps.eof_flag = 0 ;
1434 MAWK->ps.pfile_name = ((mawk_string_t *)str)->str;
1435 MAWK->ps.buffp = MAWK->ps.buffer = (unsigned char *) mawk_zmalloc(MAWK, BUFFSZ + 1) ;
1436 *MAWK->ps.buffp = '\0';
1437 if (mawk_scan_open(MAWK) == 1)
1438 MAWK->token_lineno = MAWK->lineno = 1 ;
1439 else
1440 mawk_parser_pop(MAWK);
1441 }
0
1 /********************************************
2 print.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991-1993. Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include "mawk.h"
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include "bi_vars.h"
20 #include "bi_funct.h"
21 #include "memory.h"
22 #include "field.h"
23 #include "scan.h"
24 #include "files.h"
25 #include "vio.h"
26 #include "cell.h"
27
28 static mawk_string_t *do_printf(mawk_state_t *, FILE_NODE *, char *, unsigned, mawk_cell_t *);
29 static void bad_conversion(mawk_state_t *, int, char *, char *);
30 static void write_error(mawk_state_t * MAWK);
31
32 /* prototyping fprintf() or sprintf() is a loser as ellipses will
33 always cause problems with ansi compilers depending on what
34 they've already seen,
35 but we need them here and sometimes they are missing
36 */
37
38 #ifdef NO_FPRINTF_IN_STDIO
39 int fprintf(FILE *, const char *, ...);
40 #endif
41 #ifdef NO_SPRINTF_IN_STDIO
42 int sprintf(char *, const char *, ...);
43 #endif
44
45 /* Once mawk_execute() starts the sprintf code is (belatedly) the only
46 code allowed to use string_buff */
47
48 void mawk_print_cell(mawk_state_t *MAWK, register mawk_cell_t *p, register FILE_NODE *fnode)
49 {
50 int len;
51
52 switch (p->type) {
53 case C_NOINIT:
54 break;
55 case C_MBSTRN:
56 case C_STRING:
57 case C_STRNUM:
58 switch (len = string(p)->len) {
59 case 0:
60 break;
61 case 1:
62 mawk_vio_putc(MAWK, fnode->vf, string(p)->str[0]);
63 break;
64
65 default:
66 mawk_vio_write(MAWK, fnode->vf, string(p)->str, len);
67 }
68 break;
69
70 case C_NUM:
71 {
72 Int ival = mawk_d_to_I(p->d.dval);
73 const char *txt;
74
75 txt = mawk_num_print_spec(ival);
76 if (txt != NULL)
77 mawk_vio_write_str(MAWK, fnode->vf, txt);
78 else if ((mawk_num_t) ival == p->d.dval) { /* integers print as "%[l]d" */
79 char buff[64];
80 int len;
81 len = sprintf(buff, INT_FMT, ival);
82 mawk_vio_write(MAWK, fnode->vf, buff, len);
83 }
84 else {
85 fnode->vf->imp->vprintf(MAWK, fnode->vf, string(MAWK_OFMT)->str, p->d.dval);
86 }
87 }
88 break;
89
90 default:
91 mawk_bozo(MAWK, "bad cell passed to print_cell");
92 }
93 }
94
95 /* on entry to bi_print or bi_printf the stack is:
96
97 sp[0] = an integer k
98 if ( k < 0 ) output is to a file with name in sp[-1]
99 { so open file and sp -= 2 }
100
101 sp[0] = k >= 0 is the number of print args
102 sp[-k] holds the first argument
103 */
104
105 mawk_cell_t *mawk_bi_print(mawk_state_t *MAWK, mawk_cell_t *sp)
106 {
107 /* sp is stack ptr passed in */
108 register mawk_cell_t *p;
109 register int k;
110 FILE_NODE *fnode;
111
112 k = sp->type;
113 if (k < 0) {
114 /* k holds redirection */
115 if ((--sp)->type < C_STRING)
116 mawk_cast1_to_str(MAWK, sp);
117 fnode = mawk_file_find(MAWK, string(sp), k, 1);
118 free_STRING(string(sp));
119 k = (--sp)->type;
120 /* k now has number of arguments */
121 }
122 else
123 fnode = MAWK->fnode_stdout;
124
125 if (k) {
126 p = sp - k; /* clear k variables off the stack */
127 sp = p - 1;
128 k--;
129
130 while (k > 0) {
131 if (fnode != NULL) {
132 mawk_print_cell(MAWK, p, fnode);
133 mawk_print_cell(MAWK, OFS, fnode);
134 }
135 mawk_cell_destroy(MAWK, p);
136 p++;
137 k--;
138 }
139
140 if (fnode != NULL)
141 mawk_print_cell(MAWK, p, fnode);
142 mawk_cell_destroy(MAWK, p);
143 }
144 else { /* print $0 */
145 sp--;
146 if (fnode != NULL)
147 mawk_print_cell(MAWK, &MAWK->field[0], fnode);
148 }
149
150 if (fnode != NULL) {
151 mawk_print_cell(MAWK, ORS, fnode);
152 if (mawk_vio_error(MAWK, fnode->vf))
153 write_error(MAWK);
154 }
155 return sp;
156 }
157
158 /*---------- types and defs for doing printf and sprintf----*/
159 #define PF_C 0 /* %c */
160 #define PF_S 1 /* %s */
161 #define PF_D 2 /* int conversion */
162 #define PF_F 3 /* float conversion */
163
164 /* for switch on number of '*' and type */
165 #define AST(num,type) ((PF_F+1)*(num)+(type))
166
167 typedef int (*PRINTER) (PTR, const char *, ...);
168 /*-------------------------------------------------------*/
169
170 static void bad_conversion(mawk_state_t *MAWK, int cnt, char *who, char *format)
171 {
172 mawk_rt_error(MAWK, "improper conversion(number %d) in %s(\"%s\")", cnt, who, format);
173 }
174
175
176 int sprintf_wrapper(mawk_state_t *MAWK, char *ostr, const char *fmt, ...)
177 {
178 int ret;
179 va_list ap;
180 va_start(ap, fmt);
181 ret = vsprintf(ostr, fmt, ap);
182 va_end(ap);
183 return ret;
184 }
185
186
187 /* the contents of format are preserved,
188 caller does mawk_cell_t cleanup
189
190 This routine does both printf and sprintf (if fp==0)
191 */
192 static mawk_string_t *do_printf(mawk_state_t *MAWK, FILE_NODE *fnode, char *format, unsigned argcnt, mawk_cell_t *cp)
193 {
194 /* argcnt number of args on eval stack */
195 /* mawk_cell_t *cp ptr to an array of arguments (on the eval stack) */
196 char save;
197 char *p;
198 register char *q = format;
199 register char *target;
200 int l_flag, h_flag; /* seen %ld or %hd */
201 int ast_cnt;
202 int ast[2];
203 Int Ival;
204 int num_conversion = 0; /* for error messages */
205 char *who; /*ditto */
206 int pf_type; /* conversion type */
207 PRINTER printer; /* pts at fprintf() or sprintf() */
208
209 #ifdef SHORT_INTS
210 char xbuff[256]; /* splice in l qualifier here */
211 #endif
212
213 if (fnode == NULL) { /* doing sprintf */
214 target = MAWK->sprintf_buff;
215 printer = (PRINTER) sprintf_wrapper;
216 who = "sprintf";
217 }
218 else { /* doing printf */
219 target = (char *) fnode->vf; /* will never change */
220 printer = (PRINTER) fnode->vf->imp->vprintf;
221 who = "printf";
222 }
223
224 while (1) {
225 if (fnode) { /* printf */
226 while (*q != '%') {
227 if (*q == 0) {
228 if (mawk_vio_error(MAWK, fnode->vf))
229 write_error(MAWK);
230 /* return is ignored */
231 return (mawk_string_t *) 0;
232 }
233 else {
234 mawk_vio_putc(MAWK, fnode->vf, *q);
235 q++;
236 }
237 }
238 }
239 else { /* sprintf */
240
241 while (*q != '%')
242 if (*q == 0) {
243 if (target > MAWK->sprintf_limit) { /* mawk_damaged */
244 /* hope this works */
245 mawk_rt_overflow(MAWK, "sprintf buffer", MAWK->sprintf_limit - MAWK->sprintf_buff);
246 }
247 else { /* really done */
248
249 mawk_string_t *retval;
250 int len = target - MAWK->sprintf_buff;
251
252 retval = mawk_new_STRING0(MAWK, len);
253 memcpy(retval->str, MAWK->sprintf_buff, len);
254 return retval;
255 }
256 }
257 else
258 *target++ = *q++;
259 }
260
261
262 /* *q == '%' */
263 num_conversion++;
264
265 if (*++q == '%') { /* %% */
266 if (fnode)
267 mawk_vio_putc(MAWK, fnode->vf, *q);
268 else
269 *target++ = *q;
270
271 q++;
272 continue;
273 }
274
275 /* mark the '%' with p */
276 p = q - 1;
277
278 /* eat the flags */
279 while (*q == '-' || *q == '+' || *q == ' ' || *q == '#' || *q == '0')
280 q++;
281
282 ast_cnt = 0;
283 if (*q == '*') {
284 if (cp->type != C_NUM)
285 mawk_cast1_to_num(MAWK, cp);
286 ast[ast_cnt++] = d_to_i(cp++->d.dval);
287 argcnt--;
288 q++;
289 }
290 else
291 while (MAWK->scan_code[*(unsigned char *) q] == SC_DIGIT)
292 q++;
293 /* width is done */
294
295 if (*q == '.') { /* have precision */
296 q++;
297 if (*q == '*') {
298 if (cp->type != C_NUM)
299 mawk_cast1_to_num(MAWK, cp);
300 ast[ast_cnt++] = d_to_i(cp++->d.dval);
301 argcnt--;
302 q++;
303 }
304 else
305 while (MAWK->scan_code[*(unsigned char *) q] == SC_DIGIT)
306 q++;
307 }
308
309 if (argcnt <= 0)
310 mawk_rt_error(MAWK, "not enough arguments passed to %s(\"%s\")", who, format);
311
312 l_flag = h_flag = 0;
313
314 if (*q == 'l') {
315 q++;
316 l_flag = 1;
317 }
318 else if (*q == 'h') {
319 q++;
320 h_flag = 1;
321 }
322 switch (*q++) {
323 case 's':
324 if (l_flag + h_flag)
325 bad_conversion(MAWK, num_conversion, who, format);
326 if (cp->type < C_STRING)
327 mawk_cast1_to_str(MAWK, cp);
328 pf_type = PF_S;
329 break;
330
331 case 'c':
332 if (l_flag + h_flag)
333 bad_conversion(MAWK, num_conversion, who, format);
334
335 switch (cp->type) {
336 case C_NOINIT:
337 Ival = 0;
338 break;
339
340 case C_STRNUM:
341 case C_NUM:
342 Ival = mawk_d_to_I(cp->d.dval);
343 break;
344
345 case C_STRING:
346 Ival = string(cp)->str[0];
347 break;
348
349 case C_MBSTRN:
350 mawk_check_strnum(MAWK, cp);
351 Ival = cp->type == C_STRING ? string(cp)->str[0] : mawk_d_to_I(cp->d.dval);
352 break;
353
354 default:
355 mawk_bozo(MAWK, "printf %c");
356 }
357
358 pf_type = PF_C;
359 break;
360
361 case 'd':
362 case 'o':
363 case 'x':
364 case 'X':
365 case 'i':
366 case 'u':
367 {
368 const char *txt;
369
370 if (cp->type != C_NUM)
371 mawk_cast1_to_num(MAWK, cp);
372 #ifdef MAWK_PRINTF_INFNAN
373 txt = mawk_num_print_spec(cp->d.dval);
374 if (txt == NULL) {
375 #endif
376 Ival = mawk_d_to_I(cp->d.dval);
377 pf_type = PF_D;
378 #ifdef MAWK_PRINTF_INFNAN
379 }
380 else {
381 cp->ptr = (PTR) mawk_new_STRING(MAWK, txt);
382 cp->type = C_STRING;
383 cp->d.dval = 42;
384 p = "%s";
385 pf_type = PF_S;
386 }
387 #endif
388 }
389 break;
390
391 #ifndef MAWK_NO_FLOAT
392 case 'e':
393 case 'g':
394 case 'f':
395 case 'E':
396 case 'G':
397 if (h_flag + l_flag)
398 bad_conversion(MAWK, num_conversion, who, format);
399 if (cp->type != C_NUM)
400 mawk_cast1_to_num(MAWK, cp);
401 pf_type = PF_F;
402 break;
403 #endif
404
405 default:
406 bad_conversion(MAWK, num_conversion, who, format);
407 }
408
409 save = *q;
410 *q = 0;
411
412 #ifdef SHORT_INTS
413 if (pf_type == PF_D) {
414 /* need to splice in long modifier */
415 strcpy(xbuff, p);
416
417 if (l_flag) /* do nothing */
418 ;
419 else {
420 int k = q - p;
421
422 if (h_flag) {
423 Ival = (short) Ival;
424 /* replace the 'h' with 'l' (really!) */
425 xbuff[k - 2] = 'l';
426 if (xbuff[k - 1] != 'd' && xbuff[k - 1] != 'i')
427 Ival &= 0xffff;
428 }
429 else {
430 /* the usual case */
431 xbuff[k] = xbuff[k - 1];
432 xbuff[k - 1] = 'l';
433 xbuff[k + 1] = 0;
434 }
435 }
436 }
437 #endif
438
439 /* ready to call printf() */
440 switch (AST(ast_cnt, pf_type)) {
441 case AST(0, PF_C):
442 (*printer) (MAWK, (PTR) target, p, (int) Ival);
443 break;
444
445 case AST(1, PF_C):
446 (*printer) (MAWK, (PTR) target, p, ast[0], (int) Ival);
447 break;
448
449 case AST(2, PF_C):
450 (*printer) (MAWK, (PTR) target, p, ast[0], ast[1], (int) Ival);
451 break;
452
453 case AST(0, PF_S):
454 (*printer) (MAWK, (PTR) target, p, string(cp)->str);
455 break;
456
457 case AST(1, PF_S):
458 (*printer) (MAWK, (PTR) target, p, ast[0], string(cp)->str);
459 break;
460
461 case AST(2, PF_S):
462 (*printer) (MAWK, (PTR) target, p, ast[0], ast[1], string(cp)->str);
463 break;
464
465 #ifdef SHORT_INTS
466 #define FMT xbuff /* format in xbuff */
467 #else
468 #define FMT p /* p -> format */
469 #endif
470 case AST(0, PF_D):
471 (*printer) (MAWK, (PTR) target, FMT, Ival);
472 break;
473
474 case AST(1, PF_D):
475 (*printer) (MAWK, (PTR) target, FMT, ast[0], Ival);
476 break;
477
478 case AST(2, PF_D):
479 (*printer) (MAWK, (PTR) target, FMT, ast[0], ast[1], Ival);
480 break;
481
482 #undef FMT
483
484
485 case AST(0, PF_F):
486 (*printer) (MAWK, (PTR) target, p, cp->d.dval);
487 break;
488
489 case AST(1, PF_F):
490 (*printer) (MAWK, (PTR) target, p, ast[0], cp->d.dval);
491 break;
492
493 case AST(2, PF_F):
494 (*printer) (MAWK, (PTR) target, p, ast[0], ast[1], cp->d.dval);
495 break;
496 }
497 if (fnode == NULL)
498 while (*target)
499 target++;
500 *q = save;
501 argcnt--;
502 cp++;
503 }
504 }
505
506 mawk_cell_t *mawk_bi_printf(mawk_state_t *MAWK, register mawk_cell_t *sp)
507 {
508 register int k;
509 register mawk_cell_t *p;
510 FILE_NODE *fnode;
511
512 k = sp->type;
513 if (k < 0) {
514 /* k has redirection */
515 if ((--sp)->type < C_STRING)
516 mawk_cast1_to_str(MAWK, sp);
517 fnode = mawk_file_find(MAWK, string(sp), k, 1);
518 free_STRING(string(sp));
519 k = (--sp)->type;
520 /* k is now number of args including format */
521 }
522 else
523 fnode = MAWK->fnode_stdout;
524
525 sp -= k; /* sp points at the format string */
526 k--;
527
528 if (sp->type < C_STRING)
529 mawk_cast1_to_str(MAWK, sp);
530 do_printf(MAWK, fnode, string(sp)->str, k, sp + 1);
531 free_STRING(string(sp));
532
533 /* cleanup arguments on eval stack */
534 for (p = sp + 1; k; k--, p++)
535 mawk_cell_destroy(MAWK, p);
536 return --sp;
537 }
538
539 mawk_cell_t *mawk_bi_sprintf(mawk_state_t *MAWK, mawk_cell_t *sp)
540 {
541 mawk_cell_t *p;
542 int argcnt = sp->type;
543 mawk_string_t *sval;
544
545 sp -= argcnt; /* sp points at the format string */
546 argcnt--;
547
548 if (sp->type != C_STRING)
549 mawk_cast1_to_str(MAWK, sp);
550 sval = do_printf(MAWK, NULL, string(sp)->str, argcnt, sp + 1);
551 free_STRING(string(sp));
552 sp->ptr = (PTR) sval;
553
554 /* cleanup */
555 for (p = sp + 1; argcnt; argcnt--, p++)
556 mawk_cell_destroy(MAWK, p);
557
558 return sp;
559 }
560
561
562 static void write_error(mawk_state_t * MAWK)
563 {
564 mawk_errmsg(MAWK, errno, "write failure");
565 mawk_exit(MAWK, 2);
566 }
0 /********************************************
1 print_dummy.c
2
3 libmawk changes (C) 2013, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
8
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
12
13 #include "mawk.h"
14
15 mawk_cell_t *mawk_bi_print(mawk_state_t *MAWK, mawk_cell_t *sp)
16 {
17 abort();
18 }
19
20 mawk_cell_t *mawk_bi_printf(mawk_state_t *MAWK, register mawk_cell_t *sp)
21 {
22 abort();
23 }
24
25 mawk_cell_t *mawk_bi_sprintf(mawk_state_t *MAWK, mawk_cell_t *sp)
26 {
27 abort();
28 }
29
30
0
1 /********************************************
2 re_cmpl.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include <string.h>
17 #include "mawk.h"
18 #include "memory.h"
19 #include "scan.h"
20 #include "regexp.h"
21 #include "repl.h"
22
23
24 static mawk_cell_t *REPL_compile(mawk_state_t *, mawk_string_t *);
25
26 static const char efmt[] = "regular expression compile failed (%s)\n%s";
27
28 /* compile a mawk_string_t to a regular expression machine.
29 Search a list of pre-compiled strings first
30 */
31 PTR mawk_re_compile(mawk_state_t *MAWK, mawk_string_t *sval)
32 {
33 register RE_NODE *p;
34 RE_NODE *q;
35 char *s;
36
37 /* search list */
38 s = sval->str;
39 p = MAWK->re_list;
40 q = (RE_NODE *) 0;
41 while (p) {
42 if (strcmp(s, p->sval->str) == 0) { /* found */
43 if (!q) /* already at front */
44 goto _return;
45 else { /* delete from list for move to front */
46
47 q->link = p->link;
48 goto found;
49 }
50
51 }
52 else {
53 q = p;
54 p = p->link;
55 }
56 }
57
58 /* not found */
59 p = MAWK_ZMALLOC(MAWK, RE_NODE);
60 p->sval = sval;
61
62 sval->ref_cnt++;
63 if (!(p->re = mawk_REcompile(MAWK, s))) {
64 if (MAWK->mawk_state == EXECUTION)
65 mawk_rt_error(MAWK, efmt, mawk_REerrlist[MAWK->REerrno], s);
66 else { /* compiling */
67
68 mawk_compile_error(MAWK, efmt, mawk_REerrlist[MAWK->REerrno], s);
69 return (PTR) 0;
70 }
71 }
72
73
74 found:
75 /* mawk_insert p at the front of the list */
76 p->link = MAWK->re_list;
77 MAWK->re_list = p;
78
79 _return:
80
81 #if 0
82 #ifdef DEBUG
83 if (MAWK->dump_RE)
84 mawk_REmprint(p->re, stderr);
85 #endif
86 #endif
87 return p->re;
88 }
89
90
91
92 /* this is only used by mawk_da() */
93
94
95 char *mawk_re_uncompile(mawk_state_t *MAWK, PTR m)
96 {
97 register RE_NODE *p;
98
99 for (p = MAWK->re_list; p; p = p->link)
100 if (p->re == m)
101 return p->sval->str;
102 #ifdef DEBUG
103 mawk_bozo(MAWK, "non compiled machine");
104 #endif
105 return NULL;
106 }
107
108
109
110 /*=================================================*/
111 /* replacement operations */
112
113 /* create a replacement mawk_cell_t from a mawk_string_t * */
114
115 static mawk_cell_t *REPL_compile(mawk_state_t *MAWK, mawk_string_t *sval)
116 {
117 int i = 0;
118 register char *p = sval->str;
119 register char *q;
120 char *xbuff;
121 mawk_cell_t *cp;
122
123 q = xbuff = (char *) mawk_zmalloc(MAWK, sval->len + 1);
124
125 while (1) {
126 switch (*p) {
127 case 0:
128 *q = 0;
129 goto done;
130
131 case '\\':
132 if (p[1] == '&' || p[1] == '\\') {
133 *q++ = p[1];
134 p += 2;
135 continue;
136 }
137 else
138 break;
139
140 case '&':
141 /* if empty we don't need to make a node */
142 if (q != xbuff) {
143 *q = 0;
144 split_buff[i++] = mawk_new_STRING(MAWK, xbuff);
145 }
146 /* and a null node for the '&' */
147 split_buff[i++] = (mawk_string_t *) 0;
148 /* reset */
149 p++;
150 q = xbuff;
151 continue;
152
153 default:
154 break;
155 }
156
157 *q++ = *p++;
158 }
159
160 done:
161 /* if we have one empty string it will get made now */
162 if (q > xbuff || i == 0)
163 split_buff[i++] = mawk_new_STRING(MAWK, xbuff);
164
165 /* This will never happen */
166 if (i > MAX_SPLIT)
167 mawk_overflow(MAWK, "replacement pieces", MAX_SPLIT);
168
169 cp = MAWK_ZMALLOC(MAWK, mawk_cell_t);
170 if (i == 1 && split_buff[0]) {
171 cp->type = C_REPL;
172 cp->ptr = (PTR) split_buff[0];
173 }
174 else {
175 mawk_string_t **sp = (mawk_string_t **)
176 (cp->ptr = mawk_zmalloc(MAWK, sizeof(mawk_string_t *) * i));
177 int j = 0;
178
179 while (j < i)
180 *sp++ = split_buff[j++];
181
182 cp->type = C_REPLV;
183 cp->d.vcnt = i;
184 }
185 mawk_zfree(MAWK, xbuff, sval->len + 1);
186 return cp;
187 }
188
189 /* free memory used by a replacement mawk_cell_t */
190
191 void mawk_repl_destroy(mawk_state_t *MAWK, register mawk_cell_t *cp)
192 {
193 register mawk_string_t **p;
194 unsigned cnt;
195
196 if (cp->type == C_REPL)
197 free_STRING(string(cp));
198 else { /* an C_REPLV */
199
200 p = (mawk_string_t **) cp->ptr;
201 for (cnt = cp->d.vcnt; cnt; cnt--) {
202 if (*p) {
203 free_STRING(*p);
204 }
205 p++;
206 }
207 mawk_zfree(MAWK, cp->ptr, cp->d.vcnt * sizeof(mawk_string_t *));
208 }
209 }
210
211 /* copy a C_REPLV cell to another mawk_cell_t */
212
213 mawk_cell_t *mawk_replv_cpy(mawk_state_t *MAWK, mawk_cell_t *target, const mawk_cell_t *source)
214 {
215 mawk_string_t **t, **s;
216 unsigned cnt;
217
218 target->type = C_REPLV;
219 cnt = target->d.vcnt = source->d.vcnt;
220 target->ptr = (PTR) mawk_zmalloc(MAWK, cnt * sizeof(mawk_string_t *));
221
222 t = (mawk_string_t **) target->ptr;
223 s = (mawk_string_t **) source->ptr;
224 while (cnt) {
225 cnt--;
226 if (*s)
227 (*s)->ref_cnt++;
228 *t++ = *s++;
229 }
230 return target;
231 }
232
233
234 /* search the list (with move to the front) for a compiled
235 separator.
236 return a ptr to a mawk_cell_t (C_REPL or C_REPLV)
237 */
238
239 mawk_cell_t *mawk_repl_compile(mawk_state_t *MAWK, mawk_string_t *sval)
240 {
241 register REPL_NODE *p;
242 REPL_NODE *q;
243 char *s;
244
245 /* search the list */
246 s = sval->str;
247 p = MAWK->repl_list;
248 q = (REPL_NODE *) 0;
249 while (p) {
250 if (strcmp(s, p->sval->str) == 0) { /* found */
251 if (!q) /* already at front */
252 return p->cp;
253 else { /* delete from list for move to front */
254
255 q->link = p->link;
256 goto found;
257 }
258
259 }
260 else {
261 q = p;
262 p = p->link;
263 }
264 }
265
266 /* not found */
267 p = MAWK_ZMALLOC(MAWK, REPL_NODE);
268 p->sval = sval;
269 sval->ref_cnt++;
270 p->cp = REPL_compile(MAWK, sval);
271
272 found:
273 /* mawk_insert p at the front of the list */
274 p->link = MAWK->repl_list;
275 MAWK->repl_list = p;
276 return p->cp;
277 }
278
279 /* return the string for a mawk_cell_t or type REPL or REPLV,
280 this is only used by mawk_da() */
281
282
283 char *mawk_repl_uncompile(mawk_state_t *MAWK, mawk_cell_t *cp)
284 {
285 register REPL_NODE *p = MAWK->repl_list;
286
287 if (cp->type == C_REPL) {
288 while (p) {
289 if (p->cp->type == C_REPL && p->cp->ptr == cp->ptr)
290 return p->sval->str;
291 else
292 p = p->link;
293 }
294 }
295 else {
296 while (p) {
297 if (p->cp->type == C_REPLV && memcmp(cp->ptr, p->cp->ptr, cp->d.vcnt * sizeof(mawk_string_t *))
298 == 0)
299 return p->sval->str;
300 else
301 p = p->link;
302 }
303 }
304
305 #if DEBUG
306 mawk_bozo(MAWK, "unable to uncompile an repl");
307 #endif
308 return NULL;
309 }
310
311 /*
312 convert a C_REPLV to C_REPL
313 replacing the &s with sval
314 */
315
316 mawk_cell_t *mawk_replv_to_repl(mawk_state_t *MAWK, mawk_cell_t *cp, mawk_string_t *sval)
317 {
318 register mawk_string_t **p;
319 mawk_string_t **sblock = (mawk_string_t **) cp->ptr;
320 unsigned cnt, vcnt = cp->d.vcnt;
321 unsigned len;
322 char *target;
323
324 #ifdef DEBUG
325 if (cp->type != C_REPLV)
326 mawk_bozo(MAWK, "not replv");
327 #endif
328
329 p = sblock;
330 cnt = vcnt;
331 len = 0;
332 while (cnt--) {
333 if (*p)
334 len += (*p++)->len;
335 else {
336 *p++ = sval;
337 sval->ref_cnt++;
338 len += sval->len;
339 }
340 }
341 cp->type = C_REPL;
342 cp->ptr = (PTR) mawk_new_STRING0(MAWK, len);
343
344 p = sblock;
345 cnt = vcnt;
346 target = string(cp)->str;
347 while (cnt--) {
348 memcpy(target, (*p)->str, (*p)->len);
349 target += (*p)->len;
350 free_STRING(*p);
351 p++;
352 }
353
354 mawk_zfree(MAWK, sblock, vcnt * sizeof(mawk_string_t *));
355 return cp;
356 }
0
1 /********************************************
2 regexp.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16
17 PTR mawk_REcompile(mawk_state_t *MAWK, char *);
18 int mawk_REtest(mawk_state_t *MAWK, char *, PTR);
19 char *mawk_REmatch(mawk_state_t *MAWK, char *, PTR, unsigned *, int);
20 #ifdef DEBUG
21 #include <stdio.h>
22 void mawk_REmprint(PTR m, FILE *f);
23 #endif
24
25 extern const char *mawk_REerrlist[];
0 # Run regression tests of all kind
1 # make: run all tests until the first error
2 # make -j8: same, parallel on 8 threads
3 # make decl.dab run binary save/load test on decl.awk (works on any .awk file anywhere)
4 # make decl.diff run decl awk test - works on any ./*.awk
5 # make decl.out run decl awk test, save output don't compare - works on any ./*.awk
6 # make stage1.diff run zfifo test stage1.zf
7 # make Makefile.dabs update da bin test list
8 # make fpe.out run the FPE (floating-point-exception) tests
9
10 LMAWK=../lmawk
11 ZFTEST=zfifo/zfifo_test
12
13 REF_AWK=mawk
14 IN=test.in
15
16 # awk tests with reference output
17 TESTS = io_print1.diff io_printf.diff \
18 nan_if.diff nan_ops.diff nan_io.diff nan_isnan.diff \
19 math_func.diff math_fmod.diff arr_orig.diff arr_order.diff \
20 getln_nul.diff valueof.diff wc.diff reg012.diff wfrq0.diff \
21 decl.diff fpe.diff re_test.diff call.diff acall.diff \
22 stack_grow.diff
23
24 # zfifo tests
25 ZFTESTS = stage1.diff stage2.diff large_writes.diff small_reads.diff
26
27 # da_bin tests
28 include Makefile.dabs
29
30 .SUFFIXES: .diff .out .ref .awk .zf .dab
31
32 # the .zf.out rule dependency on ZFTEST doesn't really work
33 all: $(ZFTEST)
34 make all_
35
36 all_: $(TESTS) $(ZFTESTS) $(DABTESTS)
37 @echo "*** QC PASS ***"
38
39 .awk.out: $(LMAWK)
40 -$(LMAWK) -f $*.awk < $(IN) > $@ 2>&1; true
41
42 .out.diff: $*.ref
43 @diff -u $*.ref $*.out
44 @rm $*.out
45
46 #.awk.ref:
47 # $(REF_AWK) -f $*.awk < $(IN) > $@ 2>&1 ; true
48
49 ### non-awk generic tests ###
50 .zf.out: $(ZFTEST)
51 $(ZFTEST) < $*.zf > $@ 2>&1; true
52
53 $(ZFTEST): ../zfifo.h ../zfifo.c zfifo/zfifo_test.c
54 cd zfifo && make
55
56 .awk.dab: $(LMAWK) ./da_bin_test.sh
57 LMAWK=$(LMAWK) ./da_bin_test.sh $*.awk
58
59 Makefile.dabs:
60 @echo "Generating Makefile.dabs..."
61 @echo -n "DABTESTS=" > $@
62 @ls *.awk ../examples/*.awk | sed "s/.awk$$/.dab\\\\/" >>$@
63 @echo "" >>$@
64
65
66 ### custom tests ###
67 fpe.out: fpe/fpetest1.awk fpe/fpetest2.awk fpe/fpetest3.awk
68 @echo "-> fpe test"
69 @-$(LMAWK) -f fpe/fpetest1.awk >/dev/null 2>&1; r1=$$?; \
70 $(LMAWK) -f fpe/fpetest2.awk >/dev/null 2>&1; r2=$$?; \
71 $(LMAWK) -f fpe/fpetest3.awk 2>/dev/null > fpe/fpetest3.tmp; r3=$$?; \
72 $(LMAWK) -f fpe/eval.awk -v "r1=$$r1" -v "r2=$$r2" -v "r3=$$r3" < fpe/fpetest3.tmp > $@
73
74 re_test.out: re_test/re_test
75 @echo "-> re_test"
76 @re_test/re_test >$@
77
78 clean:
79 -rm *.out re_test/*.o re_test/re_test zfifo/*.o zfifo/zfifo_test 2>/dev/null ; true
80
81 FORCE:
0 DABTESTS=arr_order.dab\
1 arr_orig.dab\
2 decl.dab\
3 getln_nul.dab\
4 io_print1.dab\
5 io_printf.dab\
6 math_fmod.dab\
7 math_func.dab\
8 nan_if.dab\
9 nan_io.dab\
10 nan_isnan.dab\
11 nan_ops.dab\
12 reg012.dab\
13 valueof.dab\
14 wc.dab\
15 wfrq0.dab\
16 ../examples/ct_length.dab\
17 ../examples/decl.dab\
18 ../examples/deps.dab\
19 ../examples/eatc.dab\
20 ../examples/gdecl.dab\
21 ../examples/nocomment.dab\
22 ../examples/primes.dab\
23 ../examples/qsort.dab\
0 BEGIN {
1 ARG[1] = 3
2 ARG[2] = 9
3 ARG[3] = "haha"
4 c = acall("f1", "ARG")
5 print c
6 }
7
8 function f1(a, b, s ,tmp)
9 {
10 tmp = s "=" a*b
11 return tmp
12 }
0 # test an UB: posix doesn't tell the order of eval
1 # intuitively right side should happen first so that the left
2 # side would create A[1] again.
3 #
4 # Original mawk did it the other way around, leaving A[1] empty (result: 1)
5 # gawk 4.0.1 does right side first and returns 7
6 # lmawk with the virtualized array support does the same, returns 7
7
8 function side_effect()
9 {
10 delete A[1]
11 return 6
12 }
13
14 BEGIN {
15 # UB:
16 A[1] = side_effect()
17 print A[1]+1
18 }
0 # test whether the new array code does all these properly for an orig array
1 # (array with no side effect)
2 # This test should have the same result as with mawk or gawk
3 BEGIN {
4 A[1] = 5
5 A[1] += 2
6 A[1] -= 1
7 A[1]++
8 A[1] *= 6
9 A[1]--
10 A[1] /= 6
11 ++A[1]
12 A[1] ^= 2
13 --A[1]
14 A[1] %= 765
15 print A[1]
16 }
0 BEGIN {
1 c = call("f1", 3, 9, "haha")
2 print c
3 }
4
5 function f1(a, b, s ,tmp)
6 {
7 tmp = s "=" a*b
8 return tmp
9 }
0 #!/bin/sh
1
2 # bin dump round trip test: on all known scripts
3 # - dump asm
4 # - compile to binary, load the binary and dump asm
5 # - compare the two asms
6 # Asms shall match for any script (except for pointer values).
7
8 # replace pointers with <<ptr>>
9 ptr_filt()
10 {
11 sed "s/<<[x0-9a-fA-F]*>>/<<ptr>>/g"
12 }
13
14 # the test procedure for awk source $1
15 bintest()
16 {
17 ($LMAWK -Wdump -f $1 || return 1) | ptr_filt > $1.orig
18 $LMAWK -Wcompile -f $1 > $1.bin || return 1
19 ($LMAWK -Wdump -b $1.bin || return 1) | ptr_filt > $1.new
20 diff $1.orig $1.new || return 1
21 rm $1.orig $1.new $1.bin
22 }
23
24 bintest $1
25
26
0
1 # parse a C declaration by recursive descent
2 # based on a C program in KR ANSI edition
3 #
4 # run on a C file it finds the declarations
5 #
6 # restrictions: one declaration per line
7 # doesn't understand struct {...}
8 # makes assumptions about type names
9 #
10 #
11 # some awks need double escapes on strings used as
12 # regular expressions. If not run on mawk, use gdecl.awk
13
14
15 ################################################
16 # lexical scanner -- gobble()
17 # input : string s -- treated as a regular expression
18 # gobble eats SPACE, then eats longest match of s off front
19 # of global variable line.
20 # Cuts the matched part off of line
21 #
22
23
24 function gobble(s, x)
25 {
26 sub( /^ /, "", line) # eat SPACE if any
27
28 # surround s with parenthesis to make sure ^ acts on the
29 # whole thing
30
31 match(line, "^" "(" s ")")
32 x = substr(line, 1, RLENGTH)
33 line = substr(line, RLENGTH+1)
34 return x
35 }
36
37
38 function ptr_to(n, x) # print "pointer to" , n times
39 { n = int(n)
40 if ( n <= 0 ) return ""
41 x = "pointer to" ; n--
42 while ( n-- ) x = x " pointer to"
43 return x
44 }
45
46
47 #recursively get a decl
48 # returns an english description of the declaration or
49 # "" if not a C declaration.
50
51 function decl( x, t, ptr_part)
52 {
53
54 x = gobble("[* ]+") # get list of *** ...
55 gsub(/ /, "", x) # remove all SPACES
56 ptr_part = ptr_to( length(x) )
57
58 # We expect to see either an identifier or '('
59 #
60
61 if ( gobble("\(") )
62 {
63 # this is the recursive descent part
64 # we expect to match a declaration and closing ')'
65 # If not return "" to indicate failure
66
67 if ( (x = decl()) == "" || gobble( "\)" ) == "" ) return ""
68
69 }
70 else # expecting an identifier
71 {
72 if ( (x = gobble(id)) == "" ) return ""
73 x = x ":"
74 }
75
76 # finally look for ()
77 # or [ opt_size ]
78
79 while ( 1 )
80 if ( gobble( funct_mark ) ) x = x " function returning"
81 else
82 if ( t = gobble( array_mark ) )
83 { gsub(/ /, "", t)
84 x = x " array" t " of"
85 }
86 else break
87
88
89 x = x " " ptr_part
90 return x
91 }
92
93
94 BEGIN { id = "[_A-Za-z][_A-Za-z0-9]*"
95 funct_mark = "\([ \t]*\)"
96 array_mark = "\[[ \t]*[_A-Za-z0-9]*[ \t]*\]"
97
98 # I've assumed types are keywords or all CAPS or end in _t
99 # Other conventions could be added.
100
101 type0 = "int|char|short|long|double|float|void"
102 type1 = "[_A-Z][_A-Z0-9]*" # types are CAPS
103 type2 = "[_A-Za-z][_A-Za-z0-9]*_t" # end in _t
104
105 types = "(" type0 "|" type1 "|" type2 ")"
106 }
107
108
109 {
110
111 gsub( "/\*([^*]|\*[^/])*(\*/|$)" , " ") # remove comments
112 gsub( /[ \t]+/, " ") # squeeze white space to a single space
113
114
115 line = $0
116
117 scope = gobble( "extern|static" )
118
119 if ( type = gobble("(struct|union|enum) ") )
120 type = type gobble(id) # get the tag
121 else
122 {
123
124 type = gobble("(un)?signed ") gobble( types )
125
126 }
127
128 if ( ! type ) next
129
130 if ( (x = decl()) && gobble( ";") )
131 {
132 x = x " " type
133 if ( scope ) x = x " (" scope ")"
134 gsub( / +/, " ", x) #
135 print x
136 }
137
138 }
139
140
141
142
0 hash: function returning unsigned (extern)
1 last_dhash: unsigned (static)
2 A: ARRAY
3 sval: pointer to STRING
4 cflag: int
5 A: ARRAY
6 d: double
7 cflag: int
8 ap: pointer to ANODE
9 signal: function returning pointer to function returning void
0 # check output for nans
1 /[nN][aA][nN]|[?]/ { nan++ }
2
3 END {
4 if (r1 > 128) print "test1 failed"
5 if (r2 > 128) print "test2 failed"
6 if (r3 > 128) print "test3 failed"
7
8 # return values should all be 0 if ignoring FPEs (e.g. with IEEE754)
9 # or all 2 if trapping FPEs
10 if ((r1 == r2) && (r2 == r3)) {
11 print "consistent FPE results: all ", r1
12 if (r1 == 0)
13 print "style: ignoring floating exceptions"
14 else
15 print "style: trapping floating exceptions"
16 }
17 else
18 print "inconsistent FPE results: ", r1, r2, r3
19
20 # test3 must print nan
21 if (!nan) {
22 print "but the library is not IEEE754 compatible"
23 print "test 3 failed"
24 }
25 }
0 BEGIN {
1 x = 100
2 do { y = x ; x *= 1000 } while ( y != x )
3 print "loop terminated"
4 }
0 consistent FPE results: all 0
1 style: ignoring floating exceptions
0 BEGIN {
1 res=(getline < "")
2 print "getline=" res , "\"" $0 "\""
3 }
0 BEGIN {
1 a="hello world"
2 print "str:", a
3 a=1
4 print "int:", a
5 a=1.234
6 print "float:", a
7 }
0 str: hello world
1 int: 1
2 float: 1.234
0 BEGIN {
1 a="hello world"
2 printf("str: %s\n", a);
3 a=1
4 printf("int1: %d\n", a);
5 a=1.234
6 printf("int2: %d\n", a);
7 printf("float: %f\n", a);
8 }
0 str: hello world
1 int1: 1
2 int2: 1
3 float: 1.234000
0 >alloc: 0
1 >write: 80 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
2 >write: 80 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
3 >dump
4 Size: 160/0
5 blk 080 from 000 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
6 ^--readp
7 blk 080 from 000 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
8 ^--readp
9 stg 0 ''
0 alloc
1 # write 2x80 chars
2 write abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12
3 write abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12
4 dump
0 ROOT=../../..
1
2 all: app
3
4 include $(ROOT)/libmawk/Makefile.conf
5 $(ROOT)/libmawk/libmawk.a: FORCE
6 cd $(ROOT)/libmawk && make libmawk.a
7
8
9 OBJS = func_call.o
10 CFLAGS = -I$(ROOT)
11
12 app: $(OBJS) $(ROOT)/libmawk/libmawk.a
13 $(CC) $(LDFLAGS) $(OBJS) $(ROOT)/libmawk/libmawk.a -o $@ $(MATHLIB)
14
15 func_call.o: func_call.c
16
17 run: func_call
18 ./func_cal -f test.awk
19
20 clean:
21 rm -f $(OBJS) func_call
22
23 distclean: clean
24
25
26 FORCE:
0 #include <stdio.h>
1 #include <libmawk.h>
2
3 int main(int argc, char **argv)
4 {
5 mawk_state_t *m;
6 mawk_cell_t ret = libmawk_empty_cell;
7
8 /* init a context, execute BEGIN */
9 m = libmawk_initialize(argc, argv);
10 if (m == NULL) {
11 fprintf(stderr, "libmawk_initialize failed, exiting\n");
12 return 1;
13 }
14
15 if (libmawk_call_function(m, "foo", &ret, "dfsQ", (int)42, (double)1.234, (char *)"test string1.", 1) == MAWK_EXER_FUNCRET) {
16 char buff[32];
17 printf("app: error: function retuned; return value of foo is '%s'\n", libmawk_print_cell(m, &ret, buff, sizeof(buff)));
18 libmawk_cell_destroy(m, &ret);
19 }
20 else {
21 printf("app: OK: function foo didn't return\n");
22 }
23
24 libmawk_uninitialize(m);
25 return 0;
26 }
27
0 function foo(a, b, c)
1 {
2 print "script: foo(" a "," b "," c ")"
3 return a+b
4 }
5
6 BEGIN { print "script: BEGIN" }
7 { print "script: input: \"" $0 "\"" }
8 END { print "script: END" }
0 BEGIN {
1 A[1]=200000000
2 for(n = 0; n < 1.00000; n+=1)
3 A[1] %= 345345
4 print A[1]
5 }
0 BEGIN {
1 nan="nan"+0
2 print "atan2", atan2(nan, nan), atan2(1, nan), atan2(nan, 1), atan2(1, 0)
3 print "log ", log(nan), log(0), log(-1)
4 print "sqrt ", sqrt(nan), sqrt(0), sqrt(-1)
5 print "exp ", exp(nan)
6 print "sin ", sin(nan)
7 print "cos ", sin(nan)
8 print "tan ", sin(nan)
9 print "int ", int(nan)
10 print "pow ", (nan ^ nan), (1 ^ nan), (nan ^ 1), ((-1) ^ 1.2)
11 }
0 atan2 nan nan nan 1.5708
1 log nan nan nan
2 sqrt nan 0 nan
3 exp nan
4 sin nan
5 cos nan
6 tan nan
7 int nan
8 pow nan nan nan nan
0
1 #include <zmalloc.h>
2
3 extern unsigned hash() ;
4
5 /* An array A is a pointer to an array of struct array,
6 which is two hash tables in one. One for strings
7 and one for doubles.
8
9 each array is of size A_HASH_PRIME.
10
11 When an index is deleted via delete A[i], the
12 ANODE is not removed from the hash chain. A[i].cp
13 and A[i].sval are both freed and sval is set NULL.
14 This method of deletion simplifies for( i in A ) loops.
15
16 On the D_ANODE list, we use real deletion and move to the
17 front on access.
18
19 Separate nodes (as opposed to one type of node on two lists)
20 to
21 (1) d1 != d2, but sprintf(A_FMT,d1) == sprintf(A_FMT,d1)
22 so two dnodes can point at the same anode.
23 (2) Save a little data space(64K PC mentality).
24
25 the cost is an extra level of indirection.
26
27 Some care is needed so that things like
28 A[1] = 2 ; delete A["1"] work .
29 */
30
31 #define _dhash(d) (((int)(d)&0x7fff)%A_HASH_PRIME)
32 #define DHASH(d) (last_dhash=_dhash(d))
33 static unsigned last_dhash ;
34
35 /* switch =======;;;;;;hhhh */
36
37 static ANODE *find_by_sval(A, sval, cflag)
38 ARRAY A ;
39 STRING *sval ;
40 int cflag ; /* create if on */
41 {
42 char *s = sval->str ;
43 unsigned h = hash(s) % A_HASH_PRIME ;
44 register ANODE *p = A[h].link ;
45 ANODE *q = 0 ; /* holds first deleted ANODE */
46
47 while ( p )
48 {
49 if ( p->sval )
50 { if ( strcmp(s,p->sval->str) == 0 ) return p ; }
51 else /* its deleted, mark with q */
52 if ( ! q ) q = p ;
53
54 p = p->link ;
55 }
56
57 /* not there */
58 if ( cflag )
59 {
60 if ( q ) p = q ; /* reuse the deleted node q */
61 else
62 { p = (ANODE *)zmalloc(sizeof(ANODE)) ;
63 p->link = A[h].link ; A[h].link = p ;
64 }
65
66 p->sval = sval ;
67 sval->ref_cnt++ ;
68 p->cp = (CELL *) zmalloc(sizeof(CELL)) ;
69 p->cp->type = C_NOINIT ;
70 }
71 return p ;
72 }
73
74
75 /* on the D_ANODE list, when we find a node we move it
76 to the front of the hash chain */
77
78 static D_ANODE *find_by_dval(A, d, cflag)
79 ARRAY A ;
80 double d ;
81 int cflag ;
82 {
83 unsigned h = DHASH(d) ;
84 register D_ANODE *p = A[h].dlink ;
85 D_ANODE *q = 0 ; /* trails p for move to front */
86 ANODE *ap ;
87
88 while ( p )
89 if ( p->dval == d )
90 { /* found */
91 if ( ! p->ap->sval ) /* but it was deleted by string */
92 { if ( q ) q->dlink = p->dlink ;
93 else A[h].dlink = p->dlink ;
94 zfree(p, sizeof(D_ANODE)) ;
95 break ;
96 }
97 /* found */
98 if ( !q ) return p ; /* already at front */
99 else /* delete to put at front */
100 { q->dlink = p->dlink ; goto found ; }
101 }
102 else
103 { q = p ; p = p->dlink ; }
104
105 void (*signal())() ;
106
0 # should throw a runtime error instead
1 BEGIN {
2 nan=log(-1)
3 if (nan)
4 print "then"
5 else
6 print "else"
7 print "after"
8 }
9
0 lmawk: run time error: NaN in conditional jump
1 FILENAME="" FNR=0 NR=0
0 BEGIN {
1 a="nan"+1
2 print a
3 printf("%f\n", a)
4 print sprintf("%f", a)
5 }
0 BEGIN {
1 print isnan(0)
2 print isnan(1)
3 print isnan(log(-1))
4 print isnan("nan")
5 print isnan("nan"+1)
6 }
0 BEGIN { nan=log(-1) }
1
2 # op=, variables
3 {
4 a = 1
5 a += nan
6 print a
7
8 a = 1
9 a -= nan
10 print a
11
12 a = 1
13 a *= nan
14 print a
15
16 a = 1
17 a /= nan
18 print a
19 }
20
21 # op=, fields have their on path in the code
22 {
23 $1 = 1
24 $1 += nan
25 print $1
26
27 $1 = 1
28 $1 -= nan
29 print $1
30
31 $1 = 1
32 $1 *= nan
33 print $1
34
35 $1 = 1
36 $1 /= nan
37 print $1
38 }
39
40 # inc/dec for vars and fields
41 {
42 a = nan
43 a++
44 print a
45
46 a = nan
47 a--
48 print a
49
50 a = nan
51 ++a
52 print a
53
54 a = nan
55 --a
56 print a
57
58 $1 = nan
59 $1++
60 print $1
61
62 $1 = nan
63 $1--
64 print $1
65
66 $1 = nan
67 ++$1
68 print $1
69
70 $1 = nan
71 --$1
72 print $1
73
74 }
75
76 {
77 # enough to test once
78 exit 0
79 }
0 nan
1 nan
2 nan
3 nan
4 nan
5 nan
6 nan
7 nan
8 nan
9 nan
10 nan
11 nan
12 nan
13 nan
14 nan
15 nan
0 #include <stdlib.h>
1 #include <stdio.h>
2 #include <string.h>
3 #include "vargs.h"
4 #include "mawk.h"
5 #include "memory.h"
6 #include "regexp.h"
7
8 void mawk_exit_(mawk_state_t *MAWK, int x)
9 {
10 fprintf(stderr, "mawk_exit\n");
11 exit(1);
12 }
13
14 char *mawk_str_str(register char *target, char *key, unsigned key_len)
15 {
16 register int k = key[0];
17
18 switch (key_len) {
19 case 0:
20 return (char *) 0;
21 case 1:
22 return strchr(target, k);
23 case 2:
24 {
25 int k1 = key[1];
26 while ((target = strchr(target, k)))
27 if (target[1] == k1)
28 return target;
29 else
30 target++;
31 /*failed */
32 return (char *) 0;
33 }
34 }
35
36 key_len--;
37 while ((target = strchr(target, k))) {
38 if (strncmp(target + 1, key + 1, key_len) == 0)
39 return target;
40 else
41 target++;
42 }
43 /*failed */
44 return (char *) 0;
45 }
46
47 void mawk_rt_error VA_ALIST(const char *, format)
48 {
49 va_list args;
50
51 fprintf(stderr, "%s: run time error: ", MAWK->progname);
52 VA_START(args, char *, format);
53 vfprintf(stderr, format, args);
54 va_end(args);
55 putc('\n', stderr);
56 exit(1);
57 }
58
59
60 void mawk_compile_error VA_ALIST(const char *, format)
61 {
62 va_list args;
63 const char *s0, *s1;
64
65 /* with multiple program files put program name in
66 error message */
67 if (MAWK->ps.pfile_name) {
68 s0 = MAWK->ps.pfile_name;
69 s1 = ": ";
70 }
71 else {
72 s0 = s1 = "";
73 }
74
75 fprintf(stderr, "%s: %s%sline %u: ", MAWK->progname, s0, s1, MAWK->token_lineno);
76 VA_START(args, char *, format);
77 vfprintf(stderr, format, args);
78 va_end(args);
79 fprintf(stderr, "\n");
80 if (++(MAWK->compile_error_count) == MAX_COMPILE_ERRORS)
81 mawk_exit(MAWK, 2);
82 }
83
84
85 #define test(str) \
86 do { \
87 PTR p = mawk_REcompile(MAWK, str); \
88 printf("%s -> %s %d\n", str, p == NULL ? "err" : "ok", MAWK->REerrno); \
89 } while(0)
90
91 int main()
92 {
93 mawk_state_t MAWK_, *MAWK = &MAWK_;
94
95 memset(MAWK, 0, sizeof(mawk_state_t));
96
97 test("foo");
98 test(")");
99 test("(");
100 test("[abc");
101 test("foo|");
102 test("(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)");
103 test("^*hah");
104 /* TODO: how to cause E7? */
105
106
107 mawk_free_all(MAWK);
108
109 return 0;
110 }
0 foo -> ok 0
1 ) -> err 1
2 ( -> err 2
3 [abc -> err 3
4 foo| -> err 4
5 (a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+) -> err 5
6 ^*hah -> err 6
0 # used to be test/reg[012].awk
1
2 /return/ {cnt[0]++}
3
4 /return|switch/ {cnt[1]++}
5
6 /[A-Za-z_][A-Za-z0-9_]*\[.*\][ \t]*=/ {cnt[2]++}
7
8 END{print "return=" cnt[0], "return|switch=" cnt[1], "array=" cnt[2]}
0 return=3 return|switch=4 array=2
0 >alloc: 0
1 >write: 80 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
2 >write: 80 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
3 >write: 4 '9876'
4 >dump
5 Size: 164/0
6 blk 080 from 000 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
7 ^--readp
8 blk 080 from 000 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
9 ^--readp
10 stg 4 '9876'
11 >read: 75 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvw'
12 >dump
13 Size: 89/0
14 blk 080 from 075 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
15 ^--readp
16 blk 080 from 000 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
17 ^--readp
18 stg 4 '9876'
19 >read: 7 'xyz12ab'
20 >dump
21 Size: 82/0
22 blk 080 from 002 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
23 ^--readp
24 stg 4 '9876'
25 >read: 75 'cdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxy'
26 >dump
27 Size: 7/0
28 blk 080 from 077 'abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12'
29 ^--readp
30 stg 4 '9876'
31 >read: 7 'z129876'
32 >dump
33 Size: 0/0
34 stg 0 ''
0 alloc
1 # write 2x80 chars
2 write abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12
3 write abcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyzabcdefghijklmnopqrtsuvwxyz12
4 write 9876
5 dump
6 read 75
7 dump
8 read 7
9 dump
10 read 75
11 dump
12 read 100
13 dump
0 function rec(depth)
1 {
2 if (depth < MAX)
3 return rec(depth+1)
4 return "wow at " depth
5 }
6
7 BEGIN {
8 MAX=1000
9 print rec(0)
10 }
0 >alloc: 0
1 >write: 1 'a'
2 >write: 2 'bc'
3 >write: 3 'def'
4 >write: 1 'g'
5 >dump
6 Size: 7/0
7 stg 7 'abcdefg'
8 >read: 7 'abcdefg'
9 >free
0 # a series of small writes that woudl end up in the staging buff
1 alloc
2 write a
3 write bc
4 write def
5 write g
6 dump
7 read 128
8 free
9
0 >alloc: 0
1 >write: 40 '123456789|123456789|123456789|123456789|'
2 >dump
3 Size: 40/0
4 stg 40 '123456789|123456789|123456789|123456789|'
5 >write: 20 'abcdefghi|abcdefghi|'
6 >dump
7 Size: 60/0
8 stg 60 '123456789|123456789|123456789|123456789|abcdefghi|abcdefghi|'
9 >write: 4 'ABCD'
10 >dump
11 Size: 64/0
12 blk 064 from 000 '123456789|123456789|123456789|123456789|abcdefghi|abcdefghi|ABCD'
13 ^--readp
14 stg 0 ''
15 >write: 6 '!EFGHI'
16 >dump
17 Size: 70/0
18 blk 064 from 000 '123456789|123456789|123456789|123456789|abcdefghi|abcdefghi|ABCD'
19 ^--readp
20 stg 6 '!EFGHI'
21 >read: 70 '123456789|123456789|123456789|123456789|abcdefghi|abcdefghi|ABCD!EFGHI'
22 >free
0 # a series of small writes that woudl end up in the staging buff
1 alloc
2 write 123456789|123456789|123456789|123456789|
3 dump
4 write abcdefghi|abcdefghi|
5 dump
6 write ABCD
7 dump
8 write !EFGHI
9 dump
10 read 128
11 free
12
0 1
1 22
2 333
3 4444
4
5 2) A number of obscure bugs have been fixed such as,
6 you can now make a recursive function call inside a for[ i in A] =oop.
7 Function calls with array parameters in loop expressions sometimes
8 generated erroneous internal code.
9
10
11 ### original mawk test input ###
12
13 #include <zmalloc.h>
14
15 extern unsigned hash() ;
16
17 /* An array A is a pointer to an array of struct array,
18 which is two hash tables in one. One for strings
19 and one for doubles.
20
21 each array is of size A_HASH_PRIME.
22
23 When an index is deleted via delete A[i], the
24 ANODE is not removed from the hash chain. A[i].cp
25 and A[i].sval are both freed and sval is set NULL.
26 This method of deletion simplifies for( i in A ) loops.
27
28 On the D_ANODE list, we use real deletion and move to the
29 front on access.
30
31 Separate nodes (as opposed to one type of node on two lists)
32 to
33 (1) d1 != d2, but sprintf(A_FMT,d1) == sprintf(A_FMT,d1)
34 so two dnodes can point at the same anode.
35 (2) Save a little data space(64K PC mentality).
36
37 the cost is an extra level of indirection.
38
39 Some care is needed so that things like
40 A[1] = 2 ; delete A["1"] work .
41 */
42
43 #define _dhash(d) (((int)(d)&0x7fff)%A_HASH_PRIME)
44 #define DHASH(d) (last_dhash=_dhash(d))
45 static unsigned last_dhash ;
46
47 /* switch =======;;;;;;hhhh */
48
49 static ANODE *find_by_sval(A, sval, cflag)
50 ARRAY A ;
51 STRING *sval ;
52 int cflag ; /* create if on */
53 {
54 char *s = sval->str ;
55 unsigned h = hash(s) % A_HASH_PRIME ;
56 register ANODE *p = A[h].link ;
57 ANODE *q = 0 ; /* holds first deleted ANODE */
58
59 while ( p )
60 {
61 if ( p->sval )
62 { if ( strcmp(s,p->sval->str) == 0 ) return p ; }
63 else /* its deleted, mark with q */
64 if ( ! q ) q = p ;
65
66 p = p->link ;
67 }
68
69 /* not there */
70 if ( cflag )
71 {
72 if ( q ) p = q ; /* reuse the deleted node q */
73 else
74 { p = (ANODE *)zmalloc(sizeof(ANODE)) ;
75 p->link = A[h].link ; A[h].link = p ;
76 }
77
78 p->sval = sval ;
79 sval->ref_cnt++ ;
80 p->cp = (CELL *) zmalloc(sizeof(CELL)) ;
81 p->cp->type = C_NOINIT ;
82 }
83 return p ;
84 }
85
86
87 /* on the D_ANODE list, when we find a node we move it
88 to the front of the hash chain */
89
90 static D_ANODE *find_by_dval(A, d, cflag)
91 ARRAY A ;
92 double d ;
93 int cflag ;
94 {
95 unsigned h = DHASH(d) ;
96 register D_ANODE *p = A[h].dlink ;
97 D_ANODE *q = 0 ; /* trails p for move to front */
98 ANODE *ap ;
99
100 while ( p )
101 if ( p->dval == d )
102 { /* found */
103 if ( ! p->ap->sval ) /* but it was deleted by string */
104 { if ( q ) q->dlink = p->dlink ;
105 else A[h].dlink = p->dlink ;
106 zfree(p, sizeof(D_ANODE)) ;
107 break ;
108 }
109 /* found */
110 if ( !q ) return p ; /* already at front */
111 else /* delete to put at front */
112 { q->dlink = p->dlink ; goto found ; }
113 }
114 else
115 { q = p ; p = p->dlink ; }
116
117 void (*signal())() ;
118
0 function test(var, idx)
1 {
2 if (idx == "")
3 print var "=" valueof(var)
4 else
5 print var "=" valueof(var, idx)
6 }
7
8 BEGIN {
9 string="hello world"
10 number=42.321
11 array[1] = "one"
12 array[2] = "two"
13 array["three"] = 3
14 test("string")
15 test("number")
16 test("array", 1)
17 test("array", 2)
18 test("array", "three")
19 }
0 string=hello world
1 number=42.321
2 array=one
3 array=two
4 array=3
0
1 {sum += NF}
2 END{ print NR, sum}
0
1 # this program finds the twenty most freq
2 # words in document using a heap sort at the end
3 #
4 #
5
6 function down_heap(i, k,hold)
7 {
8 while ( 1 )
9 {
10 if ( compare(heap[2*i], heap[2*i+1]) <= 0 ) k = 2*i
11 else k = 2*i + 1
12
13 if ( compare(heap[i],heap[k]) <= 0 ) return
14
15 hold = heap[k] ; heap[k] = heap[i] ; heap[i] = hold
16 i = k
17 }
18 }
19
20 # compares two values of form "number word"
21 # by number and breaks ties by word (reversed)
22
23 function compare(s1, s2, t, X)
24 {
25 t = (s1+0) - (s2+0) # forces types to number
26
27 if ( t == 0 )
28 {
29 split(s1, X); s1 = X[2]
30 split(s2, X); s2 = X[2]
31 if ( s2 < s1 ) return -1
32 return s1 < s2
33 }
34
35 return t
36 }
37
38
39 BEGIN { RS = "[^a-zA-Z]+" ; BIG = "999999:" }
40
41 { cnt[$0]++ }
42
43 END { delete cnt[ "" ]
44
45 # load twenty values
46 j = 1
47 for( i in cnt )
48 {
49 heap[j] = num_word( cnt[i] , i )
50 delete cnt[i] ;
51 if ( ++j == 21 ) break ;
52 }
53
54 # make some sentinals
55 for( i = j ; i < 43 ; i++ ) heap[i] = BIG
56
57 h_empty = j # save the first empty slot
58 # make a heap with the smallest in slot 1
59 for( i = h_empty - 1 ; i > 0 ; i-- ) down_heap(i)
60
61 # examine the rest of the values
62 for ( i in cnt )
63 {
64 j = num_word(cnt[i], i)
65 if ( compare(j, heap[1]) > 0 )
66 { # its bigger
67 # take the smallest out of the heap and readjust
68 heap[1] = j
69 down_heap(1)
70 }
71 }
72
73 h_empty-- ;
74
75 # what's left are the twenty largest
76 # smallest at the top
77 #
78
79 i = 20
80 while ( h_empty > 1 )
81 {
82 buffer[i--] = heap[1]
83 heap[1] = heap[h_empty]
84 heap[h_empty] = BIG
85 down_heap(1)
86 h_empty--
87 }
88 buffer[i--] = heap[1]
89
90 for(j = 1 ; j <= 20 ; j++ ) print buffer[j]
91 }
92
93
94 function num_word(num, word)
95 {
96 return sprintf("%3d %s", num, word)
97 }
0 29 p
1 23 A
2 14 ANODE
3 13 q
4 12 d
5 12 sval
6 10 if
7 10 the
8 8 dlink
9 8 h
10 8 is
11 7 of
12 7 to
13 6 D
14 5 a
15 5 array
16 5 cflag
17 5 deleted
18 5 else
19 5 for
0 CFLAGS = -g -I.
1
2 OBJS=zfifo_test.o zfifo.o
3
4 all: zfifo_test
5
6 zfifo_test: $(OBJS)
7 $(CC) $(OBJS) -o $@
8
9 zfifo.c zfifo.h: ../../zfifo.c ../../zfifo.h
10 cp ../../zfifo.c .
11 cp ../../zfifo.h .
12
13 zfifo.o: zfifo.c zfifo.h
14 $(CC) -c $(CFLAGS) zfifo.c -o $@
15
16 zfifo_test.o: zfifo.h
17
18 clean:
19 rm $(OBJS) zfifo_test zfifo.c zfifo.h 2>/dev/null; true
0 #ifndef MAWK_H
1 #define MAWK_H
2 typedef struct { int dummy;} mawk_state_t;
3 #endif
4
0 #include <stdlib.h>
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include <assert.h>
5 #include "zfifo.h"
6
7
8 mawk_state_t *MAWK = NULL;
9 int main(int argc, char *argv[])
10 {
11 mawk_zfifo_t fifo;
12
13 while(!(feof(stdin))) {
14 char line[1024], *cmd, *args;
15 *line = '\0';
16 fgets(line, sizeof(line), stdin);
17
18 cmd = line;
19 while(isspace(*cmd)) cmd++;
20 if ((*cmd == '#') || (*cmd == '\0'))
21 continue;
22 args = strpbrk(cmd, " \t\r\n");
23 if (args != NULL) {
24 *args = '\0';
25 args++;
26 }
27
28 if (strcmp(cmd, "alloc") == 0) {
29 mawk_zfifo_alloc(MAWK, &fifo, (args == NULL ? -1 : atoi(args)));
30 printf(">alloc: %d\n", fifo.max_size);
31 }
32 else if (strcmp(cmd, "free") == 0) {
33 mawk_zfifo_free(MAWK, &fifo);
34 printf(">free\n");
35 }
36 else if (strcmp(cmd, "write") == 0) {
37 int len;
38 assert(args != NULL);
39 len = strlen(args)-1;
40 while((len > 0) && ((args[len] == '\n') || (args[len] == '\r'))) {
41 args[len] = '\0';
42 len--;
43 }
44 len++;
45 printf(">write: %d '%s'\n", mawk_zfifo_write(MAWK, &fifo, args, len), args);
46 }
47 else if (strcmp(cmd, "read") == 0) {
48 int size = sizeof(line)-1;
49 int ret;
50 if (args != NULL)
51 size = atoi(args);
52 *line = '\0';
53 ret = mawk_zfifo_read(MAWK, &fifo, line, size);
54 if (ret >= 0)
55 line[ret] = '\0';
56 else
57 line[0] = '\0';
58 printf(">read: %d '%s'\n", ret, line);
59 }
60 else if (strcmp(cmd, "dump") == 0) {
61 mawk_zfifo_block_t *b;
62 printf(">dump\n");
63 printf(" Size: %d/%d\n", fifo.size, fifo.max_size);
64 for(b = fifo.head; b != NULL; b = b->next) {
65 int n;
66 memcpy(line, b->buf, b->size);
67 line[b->size] = '\0';
68 printf(" blk %03d from %03d '%s'\n", b->size, b->readp, line);
69 printf(" ");
70 for(n = b->readp; n > 0; n--)
71 printf(" ");
72 printf("^--readp\n");
73 }
74 if (fifo.stage_used > 0)
75 memcpy(line, fifo.stage_buf, fifo.stage_used);
76 line[fifo.stage_used] = '\0';
77 printf(" stg %d '%s'\n", fifo.stage_used, line);
78 }
79 else if (strcmp(cmd, "exit") == 0) {
80 break;
81 }
82 else {
83 fprintf(stderr, "Syntax error at invalid command '%s'\n", cmd);
84 }
85 }
86
87 return 0;
88 }
0 #ifndef ZMALLOC_H
1 #define ZMALLOC_H
2
3 #include <stdlib.h>
4 #define mawk_zfree(MAWK, ptr, size) free(ptr)
5 #define mawk_zmalloc(MAWK, size) malloc(size)
6
7 #endif
0
1 /********************************************
2 repl.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef REPL_H
17 #define REPL_H
18
19 PTR mawk_re_compile(mawk_state_t *, mawk_string_t *);
20 char *mawk_re_uncompile(mawk_state_t *, PTR);
21
22
23 mawk_cell_t *mawk_repl_compile(mawk_state_t *, mawk_string_t *);
24 char *mawk_repl_uncompile(mawk_state_t *, mawk_cell_t *);
25 int pmawk_repl_uncompile_bin(mawk_state_t *MAWK, mawk_cell_t *cp);
26 void mawk_repl_destroy(mawk_state_t *, mawk_cell_t *);
27 mawk_cell_t *mawk_replv_cpy(mawk_state_t *, mawk_cell_t *, const mawk_cell_t *);
28 mawk_cell_t *mawk_replv_to_repl(mawk_state_t *, mawk_cell_t *, mawk_string_t *);
29
30 #endif
0
1 ####################################
2 # This is a makefile for mawk,
3 # an implementation of AWK (1988).
4 ####################################
5 #
6 #
7
8 CC = cc
9 CFLAGS = -g -Wall -O0 -I../.. -DSIZE_T_TYPES_H -fPIC
10
11 O=rexp.o rexp0.o rexp1.o rexp2.o rexp3.o rexpdb.o
12 DB=rexpdb.o
13
14 all : $(O)
15 @cat </dev/null > .done
16
17 debug : $(O) $(DB)
18 @cat </dev/null > .done
19
20 $(O) : rexp.h
21
22 clean :
23 rm -f *.o .done
0
1 /********************************************
2 rexp.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* op precedence parser for regular expressions */
17
18 #include "rexp.h"
19
20
21 /* DATA */
22 const char *mawk_REerrlist[] = { (const char *) 0,
23 /* 1 */ "missing '('",
24 /* 2 */ "missing ')'",
25 /* 3 */ "bad class -- [], [^] or [",
26 /* 4 */ "missing operand",
27 /* 5 */ "resource exhaustion -- regular expression too large",
28 /* 6 */ "syntax error ^* or ^+"
29 };
30
31 /* E5 is very unlikely to occur */
32
33
34 /* This table drives the operator precedence parser */
35 static const short table[8][8] = {
36
37 /* 0 | CAT * + ? ( ) */
38 /* 0 */ { 0, L, L, L, L, L, L, E1},
39 /* | */ { G, G, L, L, L, L, L, G},
40 /* CAT*/{ G, G, G, L, L, L, L, G},
41 /* * */ { G, G, G, G, G, G, E7, G},
42 /* + */ { G, G, G, G, G, G, E7, G},
43 /* ? */ { G, G, G, G, G, G, E7, G},
44 /* ( */ { E2, L, L, L, L, L, L, EQ},
45 /* ) */ { G, G, G, G, G, G, E7, G}
46 };
47
48
49 #define STACKSZ 64
50
51
52 PTR mawk_REcompile(mawk_state_t *MAWK, char *re)
53 {
54 MACHINE m_stack[STACKSZ];
55 struct op {
56 int token;
57 int prec;
58 } op_stack[STACKSZ];
59 register MACHINE *m_ptr;
60 register struct op *op_ptr;
61 register int t;
62 int ern;
63
64 /* do this first because it also checks if we have a
65 run time stack */
66 t = mawk_RE_lex_init(MAWK, re);
67 if (t < 0) {
68 MAWK->REerrno = -t;
69 return NULL;
70 }
71
72 if (*re == 0) {
73 mawk_RESTATE *p = (mawk_RESTATE *) mawk_RE_malloc(MAWK, sizeof(mawk_RESTATE));
74 if (p == NULL) {
75 MAWK->REerrno = -MEMORY_FAILURE;
76 return NULL;
77 }
78 p->type = M_ACCEPT;
79 return (PTR) p;
80 }
81
82 /* initialize the stacks */
83 m_ptr = m_stack - 1;
84 op_ptr = op_stack;
85 op_ptr->token = 0;
86
87 t = mawk_RE_lex(MAWK, m_stack);
88 if (t < 0) {
89 MAWK->REerrno = -t;
90 return NULL;
91 }
92
93 while (1) {
94 switch (t) {
95 case T_STR:
96 case T_ANY:
97 case T_U:
98 case T_START:
99 case T_END:
100 case T_CLASS:
101 m_ptr++;
102 break;
103
104 case 0: /* end of reg expr */
105 if (op_ptr->token == 0) {
106 /* done */
107 if (m_ptr == m_stack)
108 return (PTR) m_ptr->start;
109 else {
110 /* machines still on the stack */
111 mawk_RE_panic("values still on machine stack");
112 }
113 }
114
115 /* otherwise fall thru to default
116 which is operator case */
117
118 default:
119
120 if ((op_ptr->prec = table[op_ptr->token][t]) == G) {
121 do { /* op_pop */
122
123 if (op_ptr->token <= T_CAT) /*binary op */
124 m_ptr--;
125 /* if not enough values on machine stack
126 then we have a missing operand */
127 if (m_ptr < m_stack) {
128 MAWK->REerrno = -E4;
129 return NULL;
130 }
131
132 switch (op_ptr->token) {
133 case T_CAT:
134 ern = mawk_RE_cat(MAWK, m_ptr, m_ptr + 1);
135 if (ern < 0) {
136 MAWK->REerrno = -ern;
137 return NULL;
138 }
139 break;
140
141 case T_OR:
142 ern = mawk_RE_or(MAWK, m_ptr, m_ptr + 1);
143 if (ern < 0) {
144 MAWK->REerrno = -ern;
145 return NULL;
146 }
147 break;
148
149 case T_STAR:
150 ern = mawk_RE_close(MAWK, m_ptr);
151 if (ern < 0) {
152 MAWK->REerrno = -ern;
153 return NULL;
154 }
155 break;
156
157 case T_PLUS:
158 ern = mawk_RE_poscl(MAWK, m_ptr);
159 if (ern < 0) {
160 MAWK->REerrno = -ern;
161 return NULL;
162 }
163 break;
164
165 case T_Q:
166 ern = mawk_RE_01(MAWK, m_ptr);
167 if (ern < 0) {
168 MAWK->REerrno = -ern;
169 return NULL;
170 }
171 break;
172
173 default:
174 /*nothing on ( or ) */
175 break;
176 }
177
178 op_ptr--;
179 }
180 while (op_ptr->prec != L);
181
182 continue; /* back thru switch at top */
183 }
184
185 if (op_ptr->prec < 0) {
186 if (op_ptr->prec == E7)
187 mawk_RE_panic("parser returns E7");
188 else {
189 MAWK->REerrno = -op_ptr->prec;
190 return NULL;
191 }
192 }
193
194 if (++op_ptr == op_stack + STACKSZ) {
195 /* stack overflow */
196 MAWK->REerrno = -E5;
197 return NULL;
198 }
199
200 op_ptr->token = t;
201 } /* end of switch */
202
203 if (m_ptr == m_stack + (STACKSZ - 1)) {
204 /*overflow */
205 MAWK->REerrno = -E5;
206 return NULL;
207 }
208
209 t = mawk_RE_lex(MAWK, m_ptr + 1);
210 if (t < 0) {
211 MAWK->REerrno = -t;
212 return NULL;
213 }
214 }
215 }
216
217
218 /* getting here means a logic flaw or unforeseen case */
219 void mawk_RE_panic(char *s)
220 {
221 fprintf(stderr, "mawk_REcompile() - panic: %s\n", s);
222 exit(100);
223 }
0
1 /********************************************
2 rexp.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef REXP_H
17 #define REXP_H
18
19 #include "libmawk/nstd.h"
20 #include "libmawk/mawk.h"
21 #include <stdio.h>
22
23 PTR mawk_RE_malloc(mawk_state_t *MAWK, unsigned);
24 PTR mawk_RE_realloc(mawk_state_t *MAWK, void *, unsigned, unsigned);
25
26
27 /* finite machine state types */
28
29 #define M_STR 0
30 #define M_CLASS 1
31 #define M_ANY 2
32 #define M_START 3
33 #define M_END 4
34 #define M_U 5
35 #define M_1J 6
36 #define M_2JA 7
37 #define M_2JB 8
38 #define M_ACCEPT 9
39 #define U_ON 10
40
41 #define U_OFF 0
42 #define END_OFF 0
43 #define END_ON (2*U_ON)
44
45
46 #define STATESZ (sizeof(mawk_RESTATE))
47
48 typedef struct {
49 mawk_RESTATE *start, *stop;
50 int size; /* how many bytes are allocated for start */
51 } MACHINE;
52 #define is_invm(m) (((m).start == NULL) && ((m).stop == NULL))
53
54
55 /* tokens */
56 #define T_OR 1 /* | */
57 #define T_CAT 2
58 #define T_STAR 3 /* * */
59 #define T_PLUS 4 /* + */
60 #define T_Q 5 /* ? */
61 #define T_LP 6 /* ( */
62 #define T_RP 7 /* ) */
63 #define T_START 8 /* ^ */
64 #define T_END 9 /* $ */
65 #define T_ANY 10 /* . */
66 #define T_CLASS 11 /* starts with [ */
67 #define T_SLASH 12 /* \ */
68 #define T_CHAR 13 /* all the rest */
69 #define T_STR 14
70 #define T_U 15
71
72 /* precedences and error codes */
73 #define L 0
74 #define EQ 1
75 #define G 2
76 #define E1 (-1)
77 #define E2 (-2)
78 #define E3 (-3)
79 #define E4 (-4)
80 #define E5 (-5)
81 #define E6 (-6)
82 #define E7 (-7)
83
84 #define MEMORY_FAILURE 5
85
86 #define ison(b,x) ((b)[((unsigned char)(x))>>3] & (1<<((x)&7)))
87
88 /* error trap */
89 MACHINE mawk_RE_u(mawk_state_t *MAWK);
90 MACHINE mawk_RE_start(mawk_state_t *MAWK);
91 MACHINE mawk_RE_end(mawk_state_t *MAWK);
92 MACHINE mawk_RE_any(mawk_state_t *MAWK);
93 MACHINE mawk_RE_str(mawk_state_t *MAWK, char *, unsigned);
94 MACHINE mawk_RE_class(mawk_state_t *MAWK, mawk_BV *);
95 int mawk_RE_cat(mawk_state_t *MAWK, MACHINE *, MACHINE *);
96 int mawk_RE_or(mawk_state_t *MAWK, MACHINE *, MACHINE *);
97 int mawk_RE_close(mawk_state_t *MAWK, MACHINE *);
98 int mawk_RE_poscl(mawk_state_t *MAWK, MACHINE *);
99 int mawk_RE_01(mawk_state_t *MAWK, MACHINE *);
100 void mawk_RE_panic(char *);
101 char *mawk_str_str(char *, char *, unsigned);
102
103 int mawk_RE_lex_init(mawk_state_t *MAWK, char *);
104 int mawk_RE_lex(mawk_state_t *MAWK, MACHINE *);
105 int mawk_RE_run_stack_init(mawk_state_t *MAWK);
106 mawk_RT_STATE *mawk_RE_new_run_stack(mawk_state_t *MAWK);
107
108 void mawk_RE_free(mawk_state_t *MAWK, PTR p, unsigned sz);
109
110
111 #endif /* REXP_H */
0
1 /********************************************
2 rexp0.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* lexical scanner */
17
18 #include "rexp.h"
19 #include "libmawk/zmalloc.h"
20 #include <string.h>
21
22 /* static functions */
23 static int do_str(mawk_state_t *MAWK, int, char **, MACHINE *);
24 static int do_class(mawk_state_t *MAWK, char **, MACHINE *);
25 static int escape(char **);
26 static mawk_BV *store_bvp(mawk_state_t *MAWK, mawk_BV *);
27 static int ctohex(int);
28
29
30 #ifndef EG
31 /* make next array visible */
32 static
33 #endif
34 const char RE_char2token['|' + 1] = {
35 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
36 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 9, 13, 13, 13,
37 6, 7, 3, 4, 13, 13, 10, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
38 13, 13, 5, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
39 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 11, 12, 13, 8, 13, 13, 13, 13, 13, 13,
40 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
41 13, 13, 13, 13, 1
42 };
43
44 #define char2token(x) \
45 ( (unsigned char)(x) > '|' ? T_CHAR : RE_char2token[(int)x] )
46
47 #define NOT_STARTED (-1)
48
49 int mawk_RE_lex_init(mawk_state_t *MAWK, char *re)
50 {
51 MAWK->RElp = re;
52 MAWK->RElen = strlen(re) + 1;
53 MAWK->REprev = NOT_STARTED;
54 return mawk_RE_run_stack_init(MAWK);
55 }
56
57
58 int mawk_RE_lex(mawk_state_t *MAWK, MACHINE *mp)
59 {
60 register int c;
61
62 /* reswitch: */
63 switch (c = char2token(*MAWK->RElp)) {
64 case T_PLUS:
65 case T_STAR:
66 if (MAWK->REprev == T_START)
67 return -6;
68 /* fall thru */
69
70 case T_OR:
71 case T_Q:
72 case T_RP:
73 MAWK->RElp++;
74 return MAWK->REprev = c;
75
76 case T_SLASH:
77 break;
78
79 case 0:
80 return 0;
81
82 case T_LP:
83 switch (MAWK->REprev) {
84 case T_CHAR:
85 case T_STR:
86 case T_ANY:
87 case T_CLASS:
88 case T_START:
89 case T_RP:
90 case T_PLUS:
91 case T_STAR:
92 case T_Q:
93 case T_U:
94 return MAWK->REprev = T_CAT;
95
96 default:
97 MAWK->RElp++;
98 return MAWK->REprev = T_LP;
99 }
100 }
101
102 /* *lp is an operand, but implicit cat op is possible */
103 switch (MAWK->REprev) {
104 case NOT_STARTED:
105 case T_OR:
106 case T_LP:
107 case T_CAT:
108
109 switch (c) {
110 case T_ANY:
111 {
112 static int plus_is_star_flag = 0;
113
114 if (*++MAWK->RElp == '*') {
115 MAWK->RElp++;
116 *mp = mawk_RE_u(MAWK);
117 if (is_invm(*mp))
118 return -MEMORY_FAILURE;
119 return MAWK->REprev = T_U;
120 }
121 else if (*MAWK->RElp == '+') {
122 if (plus_is_star_flag) {
123 MAWK->RElp++;
124 *mp = mawk_RE_u(MAWK);
125 if (is_invm(*mp))
126 return -MEMORY_FAILURE;
127 plus_is_star_flag = 0;
128 return MAWK->REprev = T_U;
129 }
130 else {
131 plus_is_star_flag = 1;
132 MAWK->RElp--;
133 *mp = mawk_RE_any(MAWK);
134 if (is_invm(*mp))
135 return -MEMORY_FAILURE;
136 return MAWK->REprev = T_ANY;
137 }
138 }
139 else {
140 *mp = mawk_RE_any(MAWK);
141 if (is_invm(*mp))
142 return -MEMORY_FAILURE;
143 MAWK->REprev = T_ANY;
144 }
145 }
146 break;
147
148 case T_SLASH:
149 MAWK->RElp++;
150 c = escape(&MAWK->RElp);
151 MAWK->REprev = do_str(MAWK, c, &MAWK->RElp, mp);
152 if (MAWK->REprev < 0)
153 return MAWK->REprev;
154 break;
155
156 case T_CHAR:
157 c = *MAWK->RElp++;
158 MAWK->REprev = do_str(MAWK, c, &MAWK->RElp, mp);
159 if (MAWK->REprev < 0)
160 return MAWK->REprev;
161 break;
162
163 case T_CLASS:
164 MAWK->REprev = do_class(MAWK, &MAWK->RElp, mp);
165 if (MAWK->REprev < 0)
166 return MAWK->REprev;
167 break;
168
169 case T_START:
170 *mp = mawk_RE_start(MAWK);
171 if (is_invm(*mp))
172 return -MEMORY_FAILURE;
173 MAWK->RElp++;
174 MAWK->REprev = T_START;
175 break;
176
177 case T_END:
178 MAWK->RElp++;
179 *mp = mawk_RE_end(MAWK);
180 if (is_invm(*mp))
181 return -MEMORY_FAILURE;
182 return MAWK->REprev = T_END;
183
184 default:
185 mawk_RE_panic("bad switch in mawk_RE_lex");
186 }
187 break;
188
189 default:
190 /* don't advance the pointer */
191 return MAWK->REprev = T_CAT;
192 }
193
194 /* check for end character */
195 if (*MAWK->RElp == '$') {
196 mp->start->type += END_ON;
197 MAWK->RElp++;
198 }
199
200 return MAWK->REprev;
201 }
202
203 /*
204 Collect a run of characters into a string machine.
205 If the run ends at *,+, or ?, then don't take the last
206 character unless the string has length one.
207 */
208
209 static int do_str(mawk_state_t *MAWK, int c, char **pp, MACHINE *mp)
210 /* int c; the first character */
211 /* char **pp; where to put the re_char pointer on exit */
212 /* MACHINE *mp; where to put the string machine */
213 {
214 register char *p; /* runs thru the input */
215 char *pt; /* trails p by one */
216 char *str; /* collect it here */
217 register char *s; /* runs thru the output */
218 unsigned len; /* length collected */
219 unsigned alloced;
220
221 p = *pp;
222 s = str = mawk_RE_malloc(MAWK, MAWK->RElen);
223 if (s == NULL)
224 return -MEMORY_FAILURE;
225 alloced = MAWK->RElen;
226 *s++ = c;
227 len = 1;
228
229 while (1) {
230 char *save;
231
232 switch (char2token(*p)) {
233 case T_CHAR:
234 pt = p;
235 *s++ = *p++;
236 break;
237
238 case T_SLASH:
239 pt = p;
240 save = p + 1; /* keep p in a register */
241 *s++ = escape(&save);
242 p = save;
243 break;
244
245 default:
246 goto out;
247 }
248 len++;
249 }
250
251 out:
252 /* if len > 1 and we stopped on a ? + or * , need to back up */
253 if (len > 1 && (*p == '*' || *p == '+' || *p == '?')) {
254 len--;
255 p = pt;
256 s--;
257 }
258
259 *s = 0;
260 *pp = p;
261 *mp = mawk_RE_str(MAWK, (char *) mawk_RE_realloc(MAWK, str, alloced, len + 1), len);
262 if (is_invm(*mp))
263 return -MEMORY_FAILURE;
264 return T_STR;
265 }
266
267
268 /*--------------------------------------------
269 BUILD A CHARACTER CLASS
270 *---------------------------*/
271
272 #define on( b, x) ((b)[(x)>>3] |= ( 1 << ((x)&7) ))
273
274 static void block_on(mawk_BV b, int x, int y)
275 /* caller makes sure x<=y and x>0 y>0 */
276 {
277 int lo = x >> 3;
278 int hi = y >> 3;
279 int r_lo = x & 7;
280 int r_hi = y & 7;
281
282 if (lo == hi) {
283 b[lo] |= (1 << (r_hi + 1)) - (1 << r_lo);
284 }
285 else {
286 int i;
287 for (i = lo + 1; i < hi; i++)
288 b[i] = 0xff;
289 b[lo] |= (0xff << r_lo);
290 b[hi] |= ~(0xff << (r_hi + 1));
291 }
292 }
293
294 /* build a mawk_BV for a character class.
295 *start points at the '['
296 on exit: *start points at the character after ']'
297 mp points at a machine that recognizes the class
298 */
299
300 static int do_class(mawk_state_t *MAWK, char **start, MACHINE *mp)
301 {
302 register char *p;
303 register mawk_BV *bvp;
304 int prev;
305 char *q, *t;
306 int cnt;
307 int comp_flag;
308
309 p = t = (*start) + 1;
310
311 /* []...] puts ] in a class
312 [^]..] negates a class with ]
313 */
314 if (*p == ']')
315 p++;
316 else if (*p == '^' && *(p + 1) == ']')
317 p += 2;
318
319 while (1) { /* find the back of the class */
320 if (!(q = strchr(p, ']'))) {
321 /* no closing bracket */
322 return E3;
323 }
324 p = q - 1;
325 cnt = 0;
326 while (*p == '\\') {
327 cnt++;
328 p--;
329 }
330 if ((cnt & 1) == 0) {
331 /* even number of \ */
332 break;
333 }
334 p = q + 1;
335 }
336
337 /* q now pts at the back of the class */
338 p = t;
339 *start = q + 1;
340
341 bvp = (mawk_BV *) mawk_RE_malloc(MAWK, sizeof(mawk_BV));
342 if (bvp == NULL)
343 return -MEMORY_FAILURE;
344 memset(bvp, 0, sizeof(mawk_BV));
345
346 if (*p == '^') {
347 comp_flag = 1;
348 p++;
349 }
350 else
351 comp_flag = 0;
352
353 prev = -1; /* indicates - cannot be part of a range */
354
355 while (p < q) {
356 switch (*p) {
357 case '\\':
358
359 t = p + 1;
360 prev = escape(&t);
361 on(*bvp, prev);
362 p = t;
363 break;
364
365 case '-':
366
367 if (prev == -1 || p + 1 == q) {
368 prev = '-';
369 on(*bvp, '-');
370 p++;
371 }
372 else {
373 int c;
374 char *mark = ++p;
375
376 if (*p != '\\')
377 c = *(unsigned char *) p++;
378 else {
379 t = p + 1;
380 c = escape(&t);
381 p = t;
382 }
383
384 if (prev <= c) {
385 block_on(*bvp, prev, c);
386 prev = -1;
387 }
388 else { /* back up */
389
390 p = mark;
391 prev = '-';
392 on(*bvp, '-');
393 }
394 }
395 break;
396
397 default:
398 prev = *(unsigned char *) p++;
399 on(*bvp, prev);
400 break;
401 }
402 }
403
404 if (comp_flag) {
405 for (p = (char *) bvp; p < (char *) bvp + sizeof(mawk_BV); p++) {
406 *p = ~*p;
407 }
408 }
409
410 /* make sure zero is off */
411 (*bvp)[0] &= ~1;
412
413 *mp = mawk_RE_class(MAWK, store_bvp(MAWK, bvp));
414 if (is_invm(*mp))
415 return -MEMORY_FAILURE;
416 return T_CLASS;
417 }
418
419
420 /* storage for bit vectors so they can be reused ,
421 stored in an unsorted linear array
422 the array grows as needed
423 */
424
425 #define BV_GROWTH 6
426
427 static mawk_BV *store_bvp(mawk_state_t *MAWK, mawk_BV *bvp)
428 {
429 register mawk_BV **p;
430 unsigned t;
431
432
433 if (MAWK->REbv_next == MAWK->REbv_limit) {
434 /* need to grow */
435 if (!MAWK->REbv_base) {
436 /* first growth */
437 t = 0;
438 MAWK->REbv_base = (mawk_BV **) mawk_RE_malloc(MAWK, BV_GROWTH * sizeof(mawk_BV *));
439 if (MAWK->REbv_base == NULL)
440 return NULL;
441 MAWK->REbv_alloced = BV_GROWTH * sizeof(mawk_BV *);
442 }
443 else {
444 t = MAWK->REbv_next - MAWK->REbv_base;
445 MAWK->REbv_base = (mawk_BV **) mawk_RE_realloc(MAWK, MAWK->REbv_base, MAWK->REbv_alloced, (t + BV_GROWTH) * sizeof(mawk_BV *));
446 MAWK->REbv_alloced = (t + BV_GROWTH) * sizeof(mawk_BV *);
447 if (MAWK->REbv_base == NULL)
448 return NULL;
449 }
450
451 MAWK->REbv_next = MAWK->REbv_base + t;
452 MAWK->REbv_limit = MAWK->REbv_next + BV_GROWTH;
453 }
454
455 /* put bvp in bv_next as a sentinal */
456 *MAWK->REbv_next = bvp;
457 p = MAWK->REbv_base;
458 while (memcmp(*p, bvp, sizeof(mawk_BV)))
459 p++;
460
461 if (p == MAWK->REbv_next) {
462 /* it is new */
463 MAWK->REbv_next++;
464 }
465 else {
466 /* we already have it */
467 mawk_RE_free(MAWK, bvp, sizeof(mawk_BV));
468 }
469
470 return *p;
471 }
472
473
474 /* ---------- convert escape sequences -------------*/
475
476 #define isoctal(x) ((x)>='0'&&(x)<='7')
477
478 #define NOT_HEX 16
479 static const char hex_val['f' - 'A' + 1] = {
480 10, 11, 12, 13, 14, 15, 0, 0,
481 0, 0, 0, 0, 0, 0, 0, 0,
482 0, 0, 0, 0, 0, 0, 0, 0,
483 0, 0, 0, 0, 0, 0, 0, 0,
484 10, 11, 12, 13, 14, 15
485 };
486
487 /* interpret 1 character as hex */
488 static int ctohex(register int c)
489 {
490 int t;
491
492 if (c >= '0' && c <= '9')
493 return c - '0';
494 if (c >= 'A' && c <= 'f' && (t = hex_val[c - 'A']))
495 return t;
496 return NOT_HEX;
497 }
498
499 #define RE_ET_END 7
500
501
502
503 /*-----------------
504 return the char
505 and move the pointer forward
506 on entry *s -> at the character after the slash
507 *-------------------*/
508
509 static int escape(char **start_p)
510 {
511 register char *p = *start_p;
512 register unsigned x;
513 unsigned xx;
514 int i;
515 struct {
516 char in, out;
517 } escape_test[RE_ET_END + 1] = {
518 {'n', '\n'},
519 {'t', '\t'},
520 {'f', '\f'},
521 {'b', '\b'},
522 {'r', '\r'},
523 {'a', '\07'},
524 {'v', '\013'},
525 {0, 0}
526 };
527
528
529 escape_test[RE_ET_END].in = *p;
530 i = 0;
531 while (escape_test[i].in != *p)
532 i++;
533 if (i != RE_ET_END) {
534 /* in escape_test table */
535 *start_p = p + 1;
536 return escape_test[i].out;
537 }
538
539 if (isoctal(*p)) {
540 x = *p++ - '0';
541 if (isoctal(*p)) {
542 x = (x << 3) + *p++ - '0';
543 if (isoctal(*p))
544 x = (x << 3) + *p++ - '0';
545 }
546 *start_p = p;
547 return x & 0xff;
548 }
549
550 if (*p == 0)
551 return '\\';
552
553 if (*p++ == 'x') {
554 if ((x = ctohex(*p)) == NOT_HEX) {
555 *start_p = p;
556 return 'x';
557 }
558
559 /* look for another hex digit */
560 if ((xx = ctohex(*++p)) != NOT_HEX) {
561 x = (x << 4) + xx;
562 p++;
563 }
564
565 *start_p = p;
566 return x;
567 }
568
569 /* anything else \c -> c */
570 *start_p = p;
571 return *(unsigned char *) (p - 1);
572 }
0
1 /********************************************
2 rexp1.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* re machine operations */
17
18 #include "rexp.h"
19 #include "libmawk/zmalloc.h"
20
21 /* initialize a two state machine */
22 static int new_TWO(mawk_state_t *MAWK, int type, MACHINE *mp)
23 {
24 mp->start = (mawk_RESTATE *) mawk_RE_malloc(MAWK, 2 * STATESZ);
25 if (mp->start == NULL) {
26 MAWK->REerrno = MEMORY_FAILURE;
27 return -MEMORY_FAILURE;
28 }
29 mp->size = 2 * STATESZ;
30 mp->stop = mp->start + 1;
31 mp->start->type = type;
32 mp->stop->type = M_ACCEPT;
33 return 0;
34 }
35
36 static const MACHINE INVM = {NULL, NULL};
37
38 /* build a machine that recognizes any */
39 MACHINE mawk_RE_any(mawk_state_t *MAWK)
40 {
41 MACHINE x;
42
43 if (new_TWO(MAWK, M_ANY, &x) < 0)
44 return INVM;
45 return x;
46 }
47
48 /* build a machine that recognizes the start of string */
49 MACHINE mawk_RE_start(mawk_state_t *MAWK)
50 {
51 MACHINE x;
52
53 if (new_TWO(MAWK, M_START, &x) < 0)
54 return INVM;
55 return x;
56 }
57
58 MACHINE mawk_RE_end(mawk_state_t *MAWK)
59 {
60 MACHINE x;
61
62 if (new_TWO(MAWK, M_END, &x) < 0)
63 return INVM;
64 return x;
65 }
66
67 /* build a machine that recognizes a class */
68 MACHINE mawk_RE_class(mawk_state_t *MAWK, mawk_BV *bvp)
69 {
70 MACHINE x;
71
72 if (new_TWO(MAWK, M_CLASS, &x) < 0)
73 return INVM;
74 x.start->data.bvp = bvp;
75 return x;
76 }
77
78 MACHINE mawk_RE_u(mawk_state_t *MAWK)
79 {
80 MACHINE x;
81
82 if (new_TWO(MAWK, M_U, &x) < 0)
83 return INVM;
84 return x;
85 }
86
87 MACHINE mawk_RE_str(mawk_state_t *MAWK, char *str, unsigned len)
88 {
89 MACHINE x;
90
91 if (new_TWO(MAWK, M_STR, &x) < 0)
92 return INVM;
93 x.start->len = len;
94 x.start->data.str = str;
95 return x;
96 }
97
98
99 /* replace m and n by a machine that recognizes mn */
100 int mawk_RE_cat(mawk_state_t *MAWK, MACHINE *mp, MACHINE *np)
101 {
102 unsigned sz1, sz2, sz;
103
104 sz1 = mp->stop - mp->start;
105 sz2 = np->stop - np->start + 1;
106 sz = sz1 + sz2;
107
108 mp->start = (mawk_RESTATE *) mawk_RE_realloc(MAWK, mp->start, mp->size, sz * STATESZ);
109 if (mp->start == NULL)
110 return -MEMORY_FAILURE;
111 mp->size = sz * STATESZ;
112 mp->stop = mp->start + (sz - 1);
113 memcpy(mp->start + sz1, np->start, sz2 * STATESZ);
114 mawk_RE_free(MAWK, np->start, np->size);
115 return 0;
116 }
117
118 /* replace m by a machine that recognizes m|n */
119
120 int mawk_RE_or(mawk_state_t *MAWK, MACHINE *mp, MACHINE *np)
121 {
122 register mawk_RESTATE *p;
123 unsigned szm, szn;
124
125 szm = mp->stop - mp->start + 1;
126 szn = np->stop - np->start + 1;
127
128 p = (mawk_RESTATE *) mawk_RE_malloc(MAWK, (szm + szn + 1) * STATESZ);
129 if (p == NULL)
130 return -MEMORY_FAILURE;
131 memcpy(p + 1, mp->start, szm * STATESZ);
132 mawk_RE_free(MAWK, mp->start, mp->size);
133 mp->start = p;
134 mp->size = (szm + szn + 1) * STATESZ;
135 (mp->stop = p + szm + szn)->type = M_ACCEPT;
136 p->type = M_2JA;
137 p->data.jump = szm + 1;
138 memcpy(p + szm + 1, np->start, szn * STATESZ);
139 mawk_RE_free(MAWK, np->start, np->size);
140 (p += szm)->type = M_1J;
141 p->data.jump = szn;
142 return 0;
143 }
144
145 /* UNARY OPERATIONS */
146
147 /* replace m by m* */
148 int mawk_RE_close(mawk_state_t *MAWK, MACHINE *mp)
149 {
150 register mawk_RESTATE *p;
151 unsigned sz;
152
153 sz = mp->stop - mp->start + 1;
154 p = (mawk_RESTATE *) mawk_RE_malloc(MAWK, (sz + 2) * STATESZ);
155 if (p == NULL)
156 return -MEMORY_FAILURE;
157 memcpy(p + 1, mp->start, sz * STATESZ);
158 mawk_RE_free(MAWK, mp->start, mp->size);
159 mp->start = p;
160 mp->size = (sz + 2) * STATESZ;
161 mp->stop = p + (sz + 1);
162 p->type = M_2JA;
163 p->data.jump = sz + 1;
164 (p += sz)->type = M_2JB;
165 p->data.jump = -(sz - 1);
166 (p + 1)->type = M_ACCEPT;
167 return 0;
168 }
169
170 /* replace m by m+ (positive closure) */
171 int mawk_RE_poscl(mawk_state_t *MAWK, MACHINE *mp)
172 {
173 register mawk_RESTATE *p;
174 unsigned sz;
175
176 sz = mp->stop - mp->start + 1;
177 mp->start = p = (mawk_RESTATE *) mawk_RE_realloc(MAWK, mp->start, mp->size, (sz + 1) * STATESZ);
178 mp->size = (sz + 1) * STATESZ;
179 if (mp->start == NULL)
180 return -MEMORY_FAILURE;
181 mp->stop = p + sz;
182 p += --sz;
183 p->type = M_2JB;
184 p->data.jump = -sz;
185 (p + 1)->type = M_ACCEPT;
186 return 0;
187 }
188
189 /* replace m by m? (zero or one) */
190 int mawk_RE_01(mawk_state_t *MAWK, MACHINE *mp)
191 {
192 unsigned sz;
193 register mawk_RESTATE *p;
194
195 sz = mp->stop - mp->start + 1;
196 p = (mawk_RESTATE *) mawk_RE_malloc(MAWK, (sz + 1) * STATESZ);
197 if (p == NULL)
198 return -MEMORY_FAILURE;
199 memcpy(p + 1, mp->start, sz * STATESZ);
200 mawk_RE_free(MAWK, mp->start, mp->size);
201 mp->start = p;
202 mp->size = (sz + 1) * STATESZ;
203 mp->stop = p + sz;
204 p->type = M_2JB;
205 p->data.jump = sz;
206 return 0;
207 }
208
209 /*===================================
210 MEMORY ALLOCATION
211 *==============================*/
212
213
214 PTR mawk_RE_malloc(mawk_state_t *MAWK, unsigned sz)
215 {
216 PTR p;
217 p = mawk_zmalloc(MAWK, sz);
218 #ifdef MAWK_RE_MDEBUG
219 fprintf(stderr, "RE malloc: -> [%p] %d\n", p, sz);
220 #endif
221 return p;
222 }
223
224 PTR mawk_RE_realloc(mawk_state_t *MAWK, register PTR p, unsigned oldsz, unsigned sz)
225 {
226 PTR n;
227 n = mawk_zrealloc(MAWK, p, oldsz, sz);
228 #ifdef MAWK_RE_MDEBUG
229 fprintf(stderr, "RE realloc: [%p] %d -> [%p] %d\n", p, oldsz, n, sz);
230 #endif
231 return n;
232 }
233
234 void mawk_RE_free(mawk_state_t *MAWK, PTR p, unsigned sz)
235 {
236 #ifdef MAWK_RE_MDEBUG
237 fprintf(stderr, "RE free: [%p] %d\n", p, sz);
238 #endif
239 mawk_zfree(MAWK, p, sz);
240 }
0
1 /********************************************
2 rexp2.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 /* test a string against a machine */
16
17 #include "rexp.h"
18 #include <string.h>
19
20 #define STACKGROWTH 16
21
22 #ifdef DEBUG
23 static mawk_RT_STATE *slow_push(mawk_state_t *MAWK, mawk_RT_STATE *, mawk_RESTATE *, char *, int);
24 #endif
25
26 int mawk_RE_run_stack_init(mawk_state_t *MAWK)
27 {
28 if (!MAWK->RE_run_stack_base) {
29 MAWK->RE_run_stack_base = (mawk_RT_STATE *)
30 mawk_RE_malloc(MAWK, sizeof(mawk_RT_STATE) * STACKGROWTH);
31 if (MAWK->RE_run_stack_base == NULL)
32 return -MEMORY_FAILURE;
33 MAWK->RE_run_stack_limit = MAWK->RE_run_stack_base + STACKGROWTH;
34 MAWK->RE_run_stack_empty = MAWK->RE_run_stack_base - 1;
35 }
36 return 0;
37 }
38
39 /* sometimes during mawk_REmatch(), this stack can grow pretty large.
40 In real life cases, the back tracking usually fails. Some
41 work is needed here to improve the algorithm.
42 I.e., figure out how not to stack useless paths.
43 */
44
45 mawk_RT_STATE *mawk_RE_new_run_stack(mawk_state_t *MAWK)
46 {
47 int oldsize = MAWK->RE_run_stack_limit - MAWK->RE_run_stack_base;
48 int newsize = oldsize + STACKGROWTH;
49
50 #ifdef LMDOS /* large model DOS */
51 /* have to worry about overflow on multiplication (ugh) */
52 if (newsize >= 4096)
53 MAWK->RE_run_stack_base = (mawk_RT_STATE *) 0;
54 else
55 #endif
56
57 MAWK->RE_run_stack_base = (mawk_RT_STATE *) mawk_RE_realloc(MAWK, MAWK->RE_run_stack_base, oldsize * sizeof(mawk_RT_STATE), newsize * sizeof(mawk_RT_STATE));
58
59 if (!MAWK->RE_run_stack_base) {
60 fprintf(stderr, "out of memory for RE run time stack\n");
61 /* this is pretty unusual, I've only seen it happen on
62 weird input to mawk_REmatch() under 16bit DOS , the same
63 situation worked easily on 32bit machine. */
64 exit(100);
65 }
66
67 MAWK->RE_run_stack_limit = MAWK->RE_run_stack_base + newsize;
68 MAWK->RE_run_stack_empty = MAWK->RE_run_stack_base - 1;
69
70 /* return the new stackp */
71 return MAWK->RE_run_stack_base + oldsize;
72 }
73
74 #ifdef DEBUG
75 static mawk_RT_STATE *slow_push(mawk_state_t *MAWK, mawk_RT_STATE *sp, mawk_RESTATE *m, char *s, int u)
76 {
77 if (sp == MAWK->RE_run_stack_limit)
78 sp = mawk_RE_new_run_stack(MAWK);
79 sp->m = m;
80 sp->s = s;
81 sp->u = u;
82 return sp;
83 }
84 #endif
85
86 #ifdef DEBUG
87 #define push(mx,sx,ux) stackp = slow_push(MAWK, ++stackp, mx, sx, ux)
88 #else
89 #define push(mx,sx,ux) if (++stackp == MAWK->RE_run_stack_limit)\
90 stackp = mawk_RE_new_run_stack(MAWK) ;\
91 stackp->m=(mx);stackp->s=(sx);stackp->u=(ux)
92 #endif
93
94
95 #define CASE_UANY(x) case x + U_OFF : case x + U_ON
96
97 /* test if str ~ /machine/
98 */
99
100 int mawk_REtest(mawk_state_t *MAWK, char *str, PTR machine)
101 {
102 register mawk_RESTATE *m = (mawk_RESTATE *) machine;
103 register char *s = str;
104 register mawk_RT_STATE *stackp;
105 int u_flag;
106 char *str_end;
107 int t; /*convenient temps */
108 mawk_RESTATE *tm;
109
110 /* handle the easy case quickly */
111 if ((m + 1)->type == M_ACCEPT && m->type == M_STR)
112 return mawk_str_str(s, m->data.str, m->len) != (char *) 0;
113 else {
114 u_flag = U_ON;
115 str_end = (char *) 0;
116 stackp = MAWK->RE_run_stack_empty;
117 goto reswitch;
118 }
119
120 refill:
121 if (stackp == MAWK->RE_run_stack_empty)
122 return 0;
123 m = stackp->m;
124 s = stackp->s;
125 u_flag = stackp--->u;
126
127
128 reswitch:
129
130 switch (m->type + u_flag) {
131 case M_STR + U_OFF + END_OFF:
132 if (strncmp(s, m->data.str, m->len))
133 goto refill;
134 s += m->len;
135 m++;
136 goto reswitch;
137
138 case M_STR + U_OFF + END_ON:
139 if (strcmp(s, m->data.str))
140 goto refill;
141 s += m->len;
142 m++;
143 goto reswitch;
144
145 case M_STR + U_ON + END_OFF:
146 if (!(s = mawk_str_str(s, m->data.str, m->len)))
147 goto refill;
148 push(m, s + 1, U_ON);
149 s += m->len;
150 m++;
151 u_flag = U_OFF;
152 goto reswitch;
153
154 case M_STR + U_ON + END_ON:
155 if (!str_end)
156 str_end = s + strlen(s);
157 t = (str_end - s) - m->len;
158 if (t < 0 || memcmp(s + t, m->data.str, m->len))
159 goto refill;
160 s = str_end;
161 m++;
162 u_flag = U_OFF;
163 goto reswitch;
164
165 case M_CLASS + U_OFF + END_OFF:
166 if (!ison(*m->data.bvp, s[0]))
167 goto refill;
168 s++;
169 m++;
170 goto reswitch;
171
172 case M_CLASS + U_OFF + END_ON:
173 if (s[1] || !ison(*m->data.bvp, s[0]))
174 goto refill;
175 s++;
176 m++;
177 goto reswitch;
178
179 case M_CLASS + U_ON + END_OFF:
180 while (!ison(*m->data.bvp, s[0])) {
181 if (s[0] == 0)
182 goto refill;
183 else
184 s++;
185 }
186 s++;
187 push(m, s, U_ON);
188 m++;
189 u_flag = U_OFF;
190 goto reswitch;
191
192 case M_CLASS + U_ON + END_ON:
193 if (!str_end)
194 str_end = s + strlen(s);
195 if (s[0] == 0 || !ison(*m->data.bvp, str_end[-1]))
196 goto refill;
197 s = str_end;
198 m++;
199 u_flag = U_OFF;
200 goto reswitch;
201
202 case M_ANY + U_OFF + END_OFF:
203 if (s[0] == 0)
204 goto refill;
205 s++;
206 m++;
207 goto reswitch;
208
209 case M_ANY + U_OFF + END_ON:
210 if (s[0] == 0 || s[1] != 0)
211 goto refill;
212 s++;
213 m++;
214 goto reswitch;
215
216 case M_ANY + U_ON + END_OFF:
217 if (s[0] == 0)
218 goto refill;
219 s++;
220 push(m, s, U_ON);
221 m++;
222 u_flag = U_OFF;
223 goto reswitch;
224
225 case M_ANY + U_ON + END_ON:
226 if (s[0] == 0)
227 goto refill;
228 if (!str_end)
229 str_end = s + strlen(s);
230 s = str_end;
231 m++;
232 u_flag = U_OFF;
233 goto reswitch;
234
235 case M_START + U_OFF + END_OFF:
236 case M_START + U_ON + END_OFF:
237 if (s != str)
238 goto refill;
239 m++;
240 u_flag = U_OFF;
241 goto reswitch;
242
243 case M_START + U_OFF + END_ON:
244 case M_START + U_ON + END_ON:
245 if (s != str || s[0] != 0)
246 goto refill;
247 m++;
248 u_flag = U_OFF;
249 goto reswitch;
250
251 case M_END + U_OFF:
252 if (s[0] != 0)
253 goto refill;
254 m++;
255 goto reswitch;
256
257 case M_END + U_ON:
258 s += strlen(s);
259 m++;
260 u_flag = U_OFF;
261 goto reswitch;
262
263 CASE_UANY(M_U):
264 u_flag = U_ON;
265 m++;
266 goto reswitch;
267
268 CASE_UANY(M_1J):
269 m += m->data.jump;
270 goto reswitch;
271
272 CASE_UANY(M_2JA): /* take the non jump branch */
273 /* don't stack an ACCEPT */
274 if ((tm = m + m->data.jump)->type == M_ACCEPT)
275 return 1;
276 push(tm, s, u_flag);
277 m++;
278 goto reswitch;
279
280 CASE_UANY(M_2JB): /* take the jump branch */
281 /* don't stack an ACCEPT */
282 if ((tm = m + 1)->type == M_ACCEPT)
283 return 1;
284 push(tm, s, u_flag);
285 m += m->data.jump;
286 goto reswitch;
287
288 CASE_UANY(M_ACCEPT):
289 return 1;
290
291 default:
292 mawk_RE_panic("unexpected case in mawk_REtest");
293 }
294 return -1;
295 }
296
297
298
299 #ifndef NOT_FOR_MAWK
300
301 char *mawk_is_string_split(register mawk_RESTATE *p, unsigned *lenp)
302 {
303 if (p[0].type == M_STR && p[1].type == M_ACCEPT) {
304 *lenp = p->len;
305 return p->data.str;
306 }
307 else
308 return (char *) 0;
309 }
310 #else /* mawk provides its own mawk_str_str */
311
312 char *mawk_str_str(register char *target, register char *key, unsigned klen)
313 {
314 int c = key[0];
315
316 switch (klen) {
317 case 0:
318 return (char *) 0;
319
320 case 1:
321 return strchr(target, c);
322
323 case 2:
324 {
325 int c1 = key[1];
326
327 while (target = strchr(target, c)) {
328 if (target[1] == c1)
329 return target;
330 else
331 target++;
332 }
333 break;
334 }
335
336 default:
337 klen--;
338 key++;
339 while (target = strchr(target, c)) {
340 if (memcmp(target + 1, key, klen) == 0)
341 return target;
342 else
343 target++;
344 }
345 break;
346 }
347 return (char *) 0;
348 }
349
350
351 #endif /* FORMAWK */
0
1 /********************************************
2 rexp3.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 /* match a string against a machine */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include "rexp.h"
20
21
22 mawk_RT_STATE *mawk_RE_new_run_stack(mawk_state_t *MAWK);
23
24
25 #define push(mx,sx,ssx,ux) if (++stackp == MAWK->RE_run_stack_limit)\
26 stackp = mawk_RE_new_run_stack(MAWK) ;\
27 stackp->m=(mx);stackp->s=(sx);stackp->ss=(ssx);\
28 stackp->u = (ux)
29
30
31 #define CASE_UANY(x) case x + U_OFF : case x + U_ON
32
33 /* returns start of first longest match and the length by
34 reference. If no match returns NULL and length zero */
35
36 char *mawk_REmatch(mawk_state_t *MAWK, char *str, PTR machine, unsigned *lenp, int disable_match_at_start)
37 {
38 register mawk_RESTATE *m = (mawk_RESTATE *) machine;
39 register char *s = str;
40 char *ss;
41 register mawk_RT_STATE *stackp;
42 int u_flag, t;
43 char *str_end, *ts;
44
45 /* state of current best match stored here */
46 char *cb_ss; /* the start */
47 char *cb_e; /* the end , pts at first char not matched */
48
49 *lenp = 0;
50
51 /* check for the easy case */
52 if ((m + 1)->type == M_ACCEPT && m->type == M_STR) {
53 if ((ts = mawk_str_str(s, m->data.str, m->len)))
54 *lenp = m->len;
55 return ts;
56 }
57
58 u_flag = U_ON;
59 cb_ss = ss = str_end = (char *) 0;
60 stackp = MAWK->RE_run_stack_empty;
61 goto reswitch;
62
63 refill:
64 if (stackp == MAWK->RE_run_stack_empty) {
65 if (cb_ss)
66 *lenp = cb_e - cb_ss;
67 return cb_ss;
68 }
69 ss = stackp->ss;
70 s = stackp--->s;
71 if (cb_ss) { /* does new state start too late ? */
72 if (ss) {
73 if (cb_ss < ss)
74 goto refill;
75 }
76 else if (cb_ss < s)
77 goto refill;
78 }
79
80 m = (stackp + 1)->m;
81 u_flag = (stackp + 1)->u;
82
83
84 reswitch:
85
86 switch (m->type + u_flag) {
87 case M_STR + U_OFF + END_OFF:
88 if (strncmp(s, m->data.str, m->len))
89 goto refill;
90 if (!ss) {
91 if (cb_ss && s > cb_ss)
92 goto refill;
93 else
94 ss = s;
95 }
96 s += m->len;
97 m++;
98 goto reswitch;
99
100 case M_STR + U_OFF + END_ON:
101 if (strcmp(s, m->data.str))
102 goto refill;
103 if (!ss) {
104 if (cb_ss && s > cb_ss)
105 goto refill;
106 else
107 ss = s;
108 }
109 s += m->len;
110 m++;
111 goto reswitch;
112
113 case M_STR + U_ON + END_OFF:
114 if (!(s = mawk_str_str(s, m->data.str, m->len)))
115 goto refill;
116 push(m, s + 1, ss, U_ON);
117 if (!ss) {
118 if (cb_ss && s > cb_ss)
119 goto refill;
120 else
121 ss = s;
122 }
123 s += m->len;
124 m++;
125 u_flag = U_OFF;
126 goto reswitch;
127
128 case M_STR + U_ON + END_ON:
129 if (!str_end)
130 str_end = s + strlen(s);
131 t = (str_end - s) - m->len;
132 if (t < 0 || memcmp(ts = s + t, m->data.str, m->len))
133 goto refill;
134 if (!ss) {
135 if (cb_ss && ts > cb_ss)
136 goto refill;
137 else
138 ss = ts;
139 }
140 s = str_end;
141 m++;
142 u_flag = U_OFF;
143 goto reswitch;
144
145 case M_CLASS + U_OFF + END_OFF:
146 if (!ison(*m->data.bvp, s[0]))
147 goto refill;
148 if (!ss) {
149 if (cb_ss && s > cb_ss)
150 goto refill;
151 else
152 ss = s;
153 }
154 s++;
155 m++;
156 goto reswitch;
157
158 case M_CLASS + U_OFF + END_ON:
159 if (s[1] || !ison(*m->data.bvp, s[0]))
160 goto refill;
161 if (!ss) {
162 if (cb_ss && s > cb_ss)
163 goto refill;
164 else
165 ss = s;
166 }
167 s++;
168 m++;
169 goto reswitch;
170
171 case M_CLASS + U_ON + END_OFF:
172 while (!ison(*m->data.bvp, s[0])) {
173 if (s[0] == 0)
174 goto refill;
175 else
176 s++;
177 }
178 s++;
179 push(m, s, ss, U_ON);
180 if (!ss) {
181 if (cb_ss && s - 1 > cb_ss)
182 goto refill;
183 else
184 ss = s - 1;
185 }
186 m++;
187 u_flag = U_OFF;
188 goto reswitch;
189
190 case M_CLASS + U_ON + END_ON:
191 if (!str_end)
192 str_end = s + strlen(s);
193 if (s[0] == 0 || !ison(*m->data.bvp, str_end[-1]))
194 goto refill;
195 if (!ss) {
196 if (cb_ss && str_end - 1 > cb_ss)
197 goto refill;
198 else
199 ss = str_end - 1;
200 }
201 s = str_end;
202 m++;
203 u_flag = U_OFF;
204 goto reswitch;
205
206 case M_ANY + U_OFF + END_OFF:
207 if (s[0] == 0)
208 goto refill;
209 if (!ss) {
210 if (cb_ss && s > cb_ss)
211 goto refill;
212 else
213 ss = s;
214 }
215 s++;
216 m++;
217 goto reswitch;
218
219 case M_ANY + U_OFF + END_ON:
220 if (s[0] == 0 || s[1] != 0)
221 goto refill;
222 if (!ss) {
223 if (cb_ss && s > cb_ss)
224 goto refill;
225 else
226 ss = s;
227 }
228 s++;
229 m++;
230 goto reswitch;
231
232 case M_ANY + U_ON + END_OFF:
233 if (s[0] == 0)
234 goto refill;
235 s++;
236 push(m, s, ss, U_ON);
237 if (!ss) {
238 if (cb_ss && s - 1 > cb_ss)
239 goto refill;
240 else
241 ss = s - 1;
242 }
243 m++;
244 u_flag = U_OFF;
245 goto reswitch;
246
247 case M_ANY + U_ON + END_ON:
248 if (s[0] == 0)
249 goto refill;
250 if (!str_end)
251 str_end = s + strlen(s);
252 if (!ss) {
253 if (cb_ss && str_end - 1 > cb_ss)
254 goto refill;
255 else
256 ss = str_end - 1;
257 }
258 s = str_end;
259 m++;
260 u_flag = U_OFF;
261 goto reswitch;
262
263 case M_START + U_OFF + END_OFF:
264 case M_START + U_ON + END_OFF:
265 if ((disable_match_at_start) || (s != str))
266 goto refill;
267 ss = s;
268 m++;
269 u_flag = U_OFF;
270 goto reswitch;
271
272 case M_START + U_OFF + END_ON:
273 case M_START + U_ON + END_ON:
274 if (disable_match_at_start || s != str || s[0] != 0)
275 goto refill;
276 ss = s;
277 m++;
278 u_flag = U_OFF;
279 goto reswitch;
280
281 case M_END + U_OFF:
282 if (s[0] != 0)
283 goto refill;
284 if (!ss) {
285 if (cb_ss && s > cb_ss)
286 goto refill;
287 else
288 ss = s;
289 }
290 m++;
291 goto reswitch;
292
293 case M_END + U_ON:
294 s = str_end ? str_end : (str_end = s + strlen(s));
295 if (!ss) {
296 if (cb_ss && s > cb_ss)
297 goto refill;
298 else
299 ss = s;
300 }
301 m++;
302 u_flag = U_OFF;
303 goto reswitch;
304
305 CASE_UANY(M_U):
306 if (!ss) {
307 if (cb_ss && s > cb_ss)
308 goto refill;
309 else
310 ss = s;
311 }
312 u_flag = U_ON;
313 m++;
314 goto reswitch;
315
316 CASE_UANY(M_1J):
317 m += m->data.jump;
318 goto reswitch;
319
320 CASE_UANY(M_2JA): /* take the non jump branch */
321 push(m + m->data.jump, s, ss, u_flag);
322 m++;
323 goto reswitch;
324
325 CASE_UANY(M_2JB): /* take the jump branch */
326 push(m + 1, s, ss, u_flag);
327 m += m->data.jump;
328 goto reswitch;
329
330 case M_ACCEPT + U_OFF:
331 if (!ss)
332 ss = s;
333 if (!cb_ss || ss < cb_ss || (ss == cb_ss && s > cb_e)) {
334 /* we have a new current best */
335 cb_ss = ss;
336 cb_e = s;
337 }
338 else if (ss == cb_ss && s == cb_e) {
339 if (cb_ss)
340 *lenp = (unsigned) (cb_e - cb_ss);
341 return cb_ss;
342 }
343
344 goto refill;
345
346 case M_ACCEPT + U_ON:
347 if (!ss)
348 ss = s;
349 else
350 s = str_end ? str_end : (str_end = s + strlen(s));
351
352 if (!cb_ss || ss < cb_ss || (ss == cb_ss && s > cb_e)) {
353 /* we have a new current best */
354 cb_ss = ss;
355 cb_e = s;
356 }
357 else if (ss == cb_ss && s == cb_e) {
358 if (cb_ss)
359 *lenp = (unsigned) (cb_e - cb_ss);
360 return cb_ss;
361 }
362 goto refill;
363
364 default:
365 mawk_RE_panic("unexpected case in mawk_REmatch");
366 }
367
368 /* can't get here, but need return to suppress compiler warning; abort()
369 is just for extra paranoia. */
370 abort();
371 return NULL;
372 }
0
1 /********************************************
2 rexpdb.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15 #include "rexp.h"
16 #include <ctype.h>
17
18 /* print a machine for debugging */
19
20 static const char *xlat[] = {
21 "M_STR",
22 "M_CLASS",
23 "M_ANY",
24 "M_START",
25 "M_END",
26 "M_U",
27 "M_1J",
28 "M_2JA",
29 "M_2JB",
30 "M_ACCEPT"
31 };
32
33 void mawk_REmprint(PTR m, FILE *f)
34 {
35 register mawk_RESTATE *p = (mawk_RESTATE *) m;
36 char *end_on_string;
37
38 while (1) {
39 if (p->type >= END_ON) {
40 p->type -= END_ON;
41 end_on_string = "$";
42 }
43 else
44 end_on_string = "";
45
46 if (p->type < 0 || p->type >= END_ON) {
47 fprintf(f, "unknown mawk_RESTATE type\n");
48 return;
49 }
50
51 fprintf(f, "%-10s", xlat[(int)p->type]);
52 switch (p->type) {
53 case M_STR:
54 fprintf(f, "%s", p->data.str);
55 break;
56
57 case M_1J:
58 case M_2JA:
59 case M_2JB:
60 fprintf(f, "%d", p->data.jump);
61 break;
62 case M_CLASS:
63 {
64 unsigned char *q = (unsigned char *) p->data.bvp;
65 unsigned char *r = q + sizeof(mawk_BV);
66 while (q < r)
67 fprintf(f, "%x ", *q++);
68 }
69 break;
70 }
71 fprintf(f, "%s\n", end_on_string);
72 if (end_on_string[0])
73 p->type += END_ON;
74 if (p->type == M_ACCEPT)
75 return;
76 p++;
77 }
78 }
0
1 /********************************************
2 scan.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* help text editors to find out nesting without context */
17 #define CL_BRACE '{'
18
19 #define _POSIX_SOURCE
20 #define _BSD_SOURCE
21
22 #include "mawk.h"
23 #include <stdio.h>
24 #include <limits.h>
25 #include <string.h>
26 #include "scan.h"
27 #include "memory.h"
28 #include "field.h"
29 #include "init.h"
30 #include "fin.h"
31 #include "repl.h"
32 #include "code.h"
33 #include "bi_vars.h"
34 #include "vio.h"
35 #include "da_bin_helper.h"
36
37 #ifndef PATH_MAX
38 #define PATH_MAX 1024
39 #endif
40
41 #ifndef NO_FCNTL_H
42 #include <fcntl.h>
43 #endif
44
45 #include "files.h"
46
47
48 /* static functions */
49 static void scan_fillbuff(mawk_state_t * MAWK);
50 int mawk_scan_open(mawk_state_t * MAWK);
51 static int slow_next(mawk_state_t * MAWK);
52 static void eat_comment(mawk_state_t * MAWK);
53 static void eat_semi_colon(mawk_state_t * MAWK);
54 static mawk_num_t collect_decimal(mawk_state_t *, YYSTYPE *lvalp, int, int *);
55 static int collect_string(mawk_state_t *MAWK, YYSTYPE *lvalp);
56 static int collect_RE(mawk_state_t *MAWK, YYSTYPE *lvalp);
57
58
59
60 /*-----------------------------
61 program file management
62 *----------------------------*/
63
64 /* return 1 if no more processing is needed (was a binary file) */
65 int mawk_scan_init(mawk_state_t *MAWK, char *cmdline_program)
66 {
67 if (cmdline_program) {
68 MAWK->ps.program_fin = NULL; /* command line program */
69 MAWK->ps.program_string = mawk_new_STRING0(MAWK, strlen(cmdline_program) + 1);
70 strcpy(MAWK->ps.program_string->str, cmdline_program);
71 /* simulate file termination */
72 MAWK->ps.program_string->str[MAWK->ps.program_string->len - 1] = '\n';
73 MAWK->ps.buffp = (unsigned char *) MAWK->ps.program_string->str;
74 MAWK->ps.eof_flag = 1;
75 }
76 else { /* program from file[s] */
77
78 /* loading the script can not fail yet, as this is the first file */
79 if (mawk_scan_open(MAWK) == 2) {
80 un_next();
81 return 1;
82 }
83
84 if (MAWK->ps.buffer == NULL)
85 MAWK->ps.buffer = (unsigned char *) mawk_zmalloc(MAWK, BUFFSZ + 1);
86 MAWK->ps.buffp = MAWK->ps.buffer;
87 if (MAWK->do_exit)
88 return -1;
89 scan_fillbuff(MAWK);
90 }
91
92 #ifdef OS2 /* OS/2 "extproc" is similar to #! */
93 if (strnicmp(MAWK->ps.buffp, "extproc ", 8) == 0)
94 eat_comment(MAWK);
95 #endif
96 mawk_eat_nl(MAWK, NULL); /* scan to first token */
97 if (next(MAWK) == 0) {
98 /* no program */
99 mawk_exitval(MAWK, 0, -1);
100 }
101
102 un_next();
103 return 0;
104 }
105
106 /* open MAWK->pfile_name[0]; returns 1 on success, 0 if the file could not
107 be open (error is also set) or is duplicate and ignored (normal condition) */
108 int mawk_scan_open(mawk_state_t * MAWK)
109 { /* open pfile_name */
110 if (MAWK->ps.pfile_name[0] == '-' && MAWK->ps.pfile_name[1] == 0) {
111 MAWK->ps.program_fin = mawk_file_find_(MAWK, "/dev/stdin", F_IN, 1);
112 }
113 else {
114 const char *fn;
115 char *start, *end, *osp;
116 int len, nlen, uniq;
117 char bc;
118 char path[PATH_MAX];
119 #ifdef mawk_realpath
120 char rpath[PATH_MAX];
121 #else
122 # define rpath path
123 #endif
124 mawk_cell_t idx;
125
126 fn = MAWK->ps.pfile_name;
127 bc = MAWK->ps.pfile_bytecode;
128 if (*fn == '+') {
129 fn++;
130 uniq = 1;
131 }
132 else
133 uniq = 0;
134
135 nlen = strlen(fn);
136 osp = ((mawk_string_t *) LIBPATH->ptr)->str;
137 if ((osp == NULL) || (*osp == '\0') || (*fn == '/'))
138 osp = "";
139
140 for (end = start = osp; end != NULL; start = end + 1) {
141 end = strchr(start, ';');
142 if (end == NULL)
143 len = strlen(start);
144 else
145 len = end - start;
146
147 if (len > 0) {
148 memcpy(path, start, len);
149 path[len] = '/';
150 len++;
151 path[len] = '\0';
152 }
153 else
154 path[0] = '\0';
155
156 if (len + nlen > sizeof(path)) {
157 mawk_errmsg(MAWK, errno, "cannot load awk script - path too long ('%s' '%s' vs %d bytes)", path, MAWK->ps.pfile_name,
158 sizeof(path));
159 mawk_exitval(MAWK, 2, -1);
160 }
161 memcpy(path + len, fn, nlen);
162 path[len + nlen] = '\0';
163
164 #ifdef mawk_realpath
165 if (mawk_realpath(path, rpath) == NULL) {
166 mawk_errmsg(MAWK, errno, "cannot convert to realpath ('%s')", path);
167 mawk_exitval(MAWK, 2, -1);
168 }
169 #endif
170
171 idx.type = C_STRING;
172 idx.ptr = mawk_new_STRING(MAWK, rpath);
173 if (uniq) {
174 /* we assume if an entry is in the array, the file exists,
175 as we already could load it once and there is no reason to assume
176 it has disappeared meanwhile - well, in theory this is a race
177 condition as another process may have deleted the file, but then
178 we would fail with "not found" anyway. */
179 if (mawk_array_find(MAWK, MAWK->scripts_loaded, &idx, NULL, 0) != 0) {
180 free_STRING((mawk_string_t *)idx.ptr);
181 return 0;
182 }
183 }
184
185 MAWK->binary_loaded = 0;
186 if (bc) {
187 if (mawk_load_code_bin(MAWK, path) != 0) {
188 mawk_errmsg(MAWK, 0, "failed to load or link binary script %s", path);
189 mawk_exitval(MAWK, 2, -1);
190 return 0;
191 }
192 MAWK->binary_loaded = 1;
193 free_STRING((mawk_string_t *)idx.ptr);
194 return 2;
195 }
196 else if ((MAWK->ps.program_fin = mawk_file_find_(MAWK, path, F_IN, 1)) != NULL) {
197 mawk_cell_t one;
198 one.type = C_NUM;
199 one.d.dval = MAWK_NUM_ONE;
200 mawk_array_set(MAWK, MAWK->scripts_loaded, &idx, &one);
201 free_STRING((mawk_string_t *)idx.ptr);
202 return 1;
203 }
204 free_STRING((mawk_string_t *)idx.ptr);
205 }
206
207 mawk_errmsg(MAWK, errno, "cannot open script %s (used search path %s)", fn, osp);
208 mawk_exitval(MAWK, 2, -1);
209 }
210 return 0;
211 }
212
213 void mawk_scan_cleanup(mawk_state_t * MAWK)
214 {
215 if (MAWK->ps.program_fin != NULL) {
216 mawk_zfree(MAWK, MAWK->ps.buffer, BUFFSZ + 1);
217 MAWK->ps.buffer = NULL;
218 MAWK->ps.buffp = NULL;
219 }
220 else if (MAWK->ps.program_string != NULL) {
221 free_STRING(MAWK->ps.program_string);
222 }
223
224 if (MAWK->ps.program_fin != NULL) {
225 mawk_file_close_(MAWK, MAWK->ps.program_fin);
226 MAWK->ps.program_fin = NULL;
227 }
228
229 /* redefine SPACE as [ \t\n] */
230
231 MAWK->scan_code['\n'] = MAWK->posix_space_flag && MAWK->rs_shadow.type != SEP_MLR ? SC_UNEXPECTED : SC_SPACE;
232 MAWK->scan_code['\f'] = SC_UNEXPECTED; /*value doesn't matter */
233 MAWK->scan_code['\013'] = SC_UNEXPECTED; /* \v not space */
234 MAWK->scan_code['\r'] = SC_UNEXPECTED;
235 }
236
237 /*----------------------------------------
238 file reading functions
239 next() and un_next(c) are macros in scan.h
240
241 *---------------------*/
242
243 static void scan_fillbuff(mawk_state_t * MAWK)
244 {
245 unsigned r = 0;
246
247 if (MAWK->ps.program_fin != NULL)
248 r = mawk_fillbuff(MAWK, MAWK->ps.program_fin->fin, (char *) MAWK->ps.buffer, BUFFSZ, 0);
249 if (r < BUFFSZ) {
250 MAWK->ps.eof_flag = 1;
251 /* make sure eof is terminated */
252 MAWK->ps.buffer[r] = '\n';
253 MAWK->ps.buffer[r + 1] = 0;
254 }
255 }
256
257 /* read one character -- slowly */
258 static int slow_next(mawk_state_t * MAWK)
259 {
260
261 while (*MAWK->ps.buffp == 0) {
262
263 if (!MAWK->ps.eof_flag) {
264 MAWK->ps.buffp = MAWK->ps.buffer;
265 scan_fillbuff(MAWK);
266 }
267 else {
268 PFILE *q;
269
270 if (MAWK->ps.program_fin != NULL) {
271 mawk_file_close_(MAWK, MAWK->ps.program_fin);
272 MAWK->ps.program_fin = NULL;
273 }
274
275 if (mawk_parser_pop(MAWK) == 0) {
276 MAWK->ps.eof_flag = 0;
277 do {
278 if (MAWK->pfile_list != NULL) {
279 MAWK->ps.pfile_name = MAWK->pfile_list->fname;
280 MAWK->ps.pfile_bytecode = MAWK->pfile_list->bytecode;
281 q = MAWK->pfile_list;
282 MAWK->pfile_list = MAWK->pfile_list->link;
283 MAWK_ZFREE(MAWK, q);
284 }
285 else {
286 MAWK->ps.eof_flag = 1;
287 goto real_eof;
288 }
289 } while (mawk_scan_open(MAWK) != 1);
290 MAWK->token_lineno = MAWK->lineno = 1;
291 }
292 }
293 }
294
295 real_eof:;
296 return *MAWK->ps.buffp++; /* note can un_next() , eof which is zero */
297 }
298
299 static void eat_comment(mawk_state_t * MAWK)
300 {
301 register int c;
302
303 while ((c = next(MAWK)) != '\n' && MAWK->scan_code[c]);
304 un_next();
305 }
306
307 /* this is how we handle extra semi-colons that are
308 now allowed to separate pattern-action blocks
309
310 A proof that they are useless clutter to the language:
311 we throw them away
312 */
313
314 static void eat_semi_colon(mawk_state_t * MAWK)
315 /* eat one semi-colon on the current line */
316 {
317 register int c;
318
319 while (MAWK->scan_code[c = next(MAWK)] == SC_SPACE);
320 if (c != ';')
321 un_next();
322 }
323
324 void mawk_eat_nl(mawk_state_t * MAWK, YYSTYPE *lvalp)
325 { /* eat all space including newlines */
326 while (1)
327 switch (MAWK->scan_code[next(MAWK)]) {
328 case SC_COMMENT:
329 eat_comment(MAWK);
330 break;
331
332 case SC_NL:
333 MAWK->lineno++;
334 /* fall thru */
335
336 case SC_SPACE:
337 break;
338
339 case SC_ESCAPE:
340 /* bug fix - surprised anyone did this,
341 a csh user with backslash dyslexia.(Not a joke)
342 */
343 {
344 unsigned c;
345
346 while (MAWK->scan_code[c = next(MAWK)] == SC_SPACE);
347 if (c == '\n')
348 MAWK->token_lineno = ++MAWK->lineno;
349 else if (c == 0) {
350 un_next();
351 return;
352 }
353 else { /* error */
354
355 un_next();
356 /* can't un_next() twice so deal with it */
357 lvalp->ival = '\\';
358 mawk_unexpected_char(MAWK, lvalp);
359 if (++(MAWK->compile_error_count) == MAX_COMPILE_ERRORS)
360 mawk_exit(MAWK, 2);
361 return;
362 }
363 }
364 break;
365
366 default:
367 un_next();
368 return;
369 }
370 }
371
372 int Mawk_lex(YYSTYPE *lvalp, mawk_state_t * MAWK)
373 {
374 register int c;
375
376 if (MAWK->do_exit)
377 return -1;
378
379 MAWK->token_lineno = MAWK->lineno;
380 MAWK->lvalp = lvalp;
381
382 reswitch:
383
384 switch (MAWK->scan_code[c = next(MAWK)]) {
385 case 0:
386 ct_ret(EOF);
387
388 case SC_SPACE:
389 goto reswitch;
390
391 case SC_COMMENT:
392 eat_comment(MAWK);
393 goto reswitch;
394
395 case SC_NL:
396 MAWK->lineno++;
397 mawk_eat_nl(MAWK, lvalp);
398 ct_ret(NL);
399
400 case SC_ESCAPE:
401 while (MAWK->scan_code[c = next(MAWK)] == SC_SPACE);
402 if (c == '\n') {
403 MAWK->token_lineno = ++MAWK->lineno;
404 goto reswitch;
405 }
406
407 if (c == 0)
408 ct_ret(EOF);
409 un_next();
410 lvalp->ival = '\\';
411 ct_ret(UNEXPECTED);
412
413
414 case SC_SEMI_COLON:
415 mawk_eat_nl(MAWK, lvalp);
416 ct_ret(SEMI_COLON);
417
418 case SC_LBRACE:
419 mawk_eat_nl(MAWK, lvalp);
420 MAWK->brace_cnt++;
421 ct_ret(LBRACE);
422
423 case SC_PLUS:
424 switch (next(MAWK)) {
425 case '+':
426 lvalp->ival = '+';
427 string_buff[0] = string_buff[1] = '+';
428 string_buff[2] = 0;
429 ct_ret(INC_or_DEC);
430
431 case '=':
432 ct_ret(ADD_ASG);
433
434 default:
435 un_next();
436 ct_ret(PLUS);
437 }
438
439 case SC_MINUS:
440 switch (next(MAWK)) {
441 case '-':
442 lvalp->ival = '-';
443 string_buff[0] = string_buff[1] = '-';
444 string_buff[2] = 0;
445 ct_ret(INC_or_DEC);
446
447 case '=':
448 ct_ret(SUB_ASG);
449
450 default:
451 un_next();
452 ct_ret(MINUS);
453 }
454
455 case SC_COMMA:
456 mawk_eat_nl(MAWK, lvalp);
457 ct_ret(COMMA);
458
459 case SC_MUL:
460 mawk_test1_ret('=', MUL_ASG, MUL);
461
462 case SC_DIV:
463 {
464 static const int can_precede_div[] = { DOUBLE, STRING_, RPAREN, ID, D_ID, RE, RBOX, FIELD,
465 GETLINE, INC_or_DEC, -1
466 };
467
468 const int *p = can_precede_div;
469
470 do {
471 if (*p == MAWK->current_token) {
472 if (*p != INC_or_DEC) {
473 mawk_test1_ret('=', DIV_ASG, DIV);
474 }
475
476 if (next(MAWK) == '=') {
477 un_next();
478 ct_ret(collect_RE(MAWK, lvalp));
479 }
480 }
481 }
482 while (*++p != -1);
483
484 ct_ret(collect_RE(MAWK, lvalp));
485 }
486
487 case SC_MOD:
488 mawk_test1_ret('=', MOD_ASG, MOD);
489
490 case SC_POW:
491 mawk_test1_ret('=', POW_ASG, POW);
492
493 case SC_LPAREN:
494 MAWK->paren_cnt++;
495 ct_ret(LPAREN);
496
497 case SC_RPAREN:
498 if (--MAWK->paren_cnt < 0) {
499 mawk_compile_error(MAWK, "extra ')'");
500 MAWK->paren_cnt = 0;
501 goto reswitch;
502 }
503
504 ct_ret(RPAREN);
505
506 case SC_LBOX:
507 ct_ret(LBOX);
508
509 case SC_RBOX:
510 ct_ret(RBOX);
511
512 case SC_MATCH:
513 string_buff[0] = '~';
514 string_buff[0] = 0;
515 lvalp->ival = 1;
516 ct_ret(MATCH);
517
518 case SC_EQUAL:
519 mawk_test1_ret('=', EQ, ASSIGN);
520
521 case SC_NOT: /* ! */
522 if ((c = next(MAWK)) == '~') {
523 string_buff[0] = '!';
524 string_buff[1] = '~';
525 string_buff[2] = 0;
526 lvalp->ival = 0;
527 ct_ret(MATCH);
528 }
529 else if (c == '=')
530 ct_ret(NEQ);
531
532 un_next();
533 ct_ret(NOT);
534
535
536 case SC_LT: /* '<' */
537 if (next(MAWK) == '=')
538 ct_ret(LTE);
539 else
540 un_next();
541
542 if (MAWK->getline_flag) {
543 MAWK->getline_flag = 0;
544 ct_ret(IO_IN);
545 }
546 else
547 ct_ret(LT);
548
549 case SC_GT: /* '>' */
550 if (MAWK->print_flag && MAWK->paren_cnt == 0) {
551 MAWK->print_flag = 0;
552 /* there are 3 types of IO_OUT
553 -- build the error string in string_buff */
554 string_buff[0] = '>';
555 if (next(MAWK) == '>') {
556 lvalp->ival = F_APPEND;
557 string_buff[1] = '>';
558 string_buff[2] = 0;
559 }
560 else {
561 un_next();
562 lvalp->ival = F_TRUNC;
563 string_buff[1] = 0;
564 }
565 return MAWK->current_token = IO_OUT;
566 }
567
568 mawk_test1_ret('=', GTE, GT);
569
570 case SC_OR:
571 if (next(MAWK) == '|') {
572 mawk_eat_nl(MAWK, lvalp);
573 ct_ret(OR);
574 }
575 else {
576 un_next();
577
578 if (MAWK->print_flag && MAWK->paren_cnt == 0) {
579 MAWK->print_flag = 0;
580 lvalp->ival = PIPE_OUT;
581 string_buff[0] = '|';
582 string_buff[1] = 0;
583 ct_ret(IO_OUT);
584 }
585 else
586 ct_ret(PIPE);
587 }
588
589 case SC_AND:
590 if (next(MAWK) == '&') {
591 mawk_eat_nl(MAWK, lvalp);
592 ct_ret(AND);
593 }
594 else {
595 un_next();
596 lvalp->ival = '&';
597 ct_ret(UNEXPECTED);
598 }
599
600 case SC_QMARK:
601 ct_ret(QMARK);
602
603 case SC_COLON:
604 ct_ret(COLON);
605
606 case SC_RBRACE:
607 if (--MAWK->brace_cnt < 0) {
608 mawk_compile_error(MAWK, "extra '}'");
609 eat_semi_colon(MAWK);
610 MAWK->brace_cnt = 0;
611 goto reswitch;
612 }
613
614 if ((c = MAWK->current_token) == NL || c == SEMI_COLON || c == SC_FAKE_SEMI_COLON || c == RBRACE) {
615 /* if the brace_cnt is zero , we've completed
616 a pattern action block. If the user insists
617 on adding a semi-colon on the same line
618 we will eat it. Note what we do below:
619 physical law -- conservation of semi-colons */
620
621 if (MAWK->brace_cnt == 0)
622 eat_semi_colon(MAWK);
623 mawk_eat_nl(MAWK, lvalp);
624 ct_ret(RBRACE);
625 }
626
627 /* supply missing semi-colon to statement that
628 precedes a '}' */
629 MAWK->brace_cnt++;
630 un_next();
631 MAWK->current_token = SC_FAKE_SEMI_COLON;
632 return SEMI_COLON;
633
634 case SC_DIGIT:
635 case SC_DOT:
636 {
637 mawk_num_t d;
638 int flag;
639 static const mawk_num_t double_zero = MAWK_NUM_ZERO;
640 static const mawk_num_t double_one = MAWK_NUM_ONE;
641
642 if ((d = collect_decimal(MAWK, lvalp, c, &flag)) == MAWK_NUM_ZERO) {
643 if (flag)
644 ct_ret(flag);
645 else
646 lvalp->ptr = (PTR) & double_zero;
647 }
648 else if (d == 1.0) {
649 lvalp->ptr = (PTR) & double_one;
650 }
651 else {
652 lvalp->ptr = (PTR) MAWK_ZMALLOC(MAWK, mawk_num_t);
653 *(mawk_num_t *) lvalp->ptr = d;
654 }
655 ct_ret(DOUBLE);
656 }
657
658 case SC_DOLLAR: /* '$' */
659 {
660 mawk_num_t d;
661 int flag;
662
663 while (MAWK->scan_code[c = next(MAWK)] == SC_SPACE);
664 if (MAWK->scan_code[c] != SC_DIGIT && MAWK->scan_code[c] != SC_DOT) {
665 un_next();
666 ct_ret(DOLLAR);
667 }
668
669 /* compute field address at compile time */
670 if ((d = collect_decimal(MAWK, lvalp, c, &flag)) == 0.0) {
671 if (flag)
672 ct_ret(flag); /* an error */
673 else
674 lvalp->cp = &MAWK->field[0];
675 }
676 else {
677 if (d > MAX_FIELD) {
678 mawk_compile_error(MAWK, "$%g exceeds maximum field(%d)", d, MAX_FIELD);
679 d = MAX_FIELD;
680 }
681 lvalp->cp = field_ptr((int) d);
682 }
683
684 ct_ret(FIELD);
685 }
686
687 case SC_DQUOTE:
688 return MAWK->current_token = collect_string(MAWK, lvalp);
689
690 case SC_IDCHAR: /* collect an identifier */
691 {
692 unsigned char *p = (unsigned char *) string_buff + 1;
693 SYMTAB *stp;
694
695 string_buff[0] = c;
696
697 while ((c = MAWK->scan_code[*p++ = next(MAWK)]) == SC_IDCHAR || c == SC_DIGIT);
698
699 un_next();
700 *--p = 0;
701
702 switch ((stp = mawk_find(MAWK, string_buff, 1))->type) {
703 case ST_NONE:
704 /* check for function call before defined */
705 if (next(MAWK) == '(') {
706 stp->type = ST_FUNCT;
707 stp->stval.fbp = (FBLOCK *)
708 mawk_zmalloc(MAWK, sizeof(FBLOCK));
709 stp->stval.fbp->name = stp->name;
710 stp->stval.fbp->code = (INST *) 0;
711 lvalp->fbp = stp->stval.fbp;
712 MAWK->current_token = FUNCT_ID;
713 }
714 else {
715 lvalp->stp = stp;
716 MAWK->current_token = MAWK->current_token == DOLLAR ? D_ID : ID;
717 }
718 un_next();
719 break;
720
721 case ST_NR:
722 MAWK->NR_flag = 1;
723 stp->type = ST_VAR;
724 /* fall thru */
725
726 case ST_VAR:
727 case ST_ARRAY:
728 case ST_LOCAL_NONE:
729 case ST_LOCAL_VAR:
730 case ST_LOCAL_ARRAY:
731
732 lvalp->stp = stp;
733 MAWK->current_token = MAWK->current_token == DOLLAR ? D_ID : ID;
734 break;
735
736 case ST_FUNCT:
737 lvalp->fbp = stp->stval.fbp;
738 MAWK->current_token = FUNCT_ID;
739 break;
740
741 case ST_C_FUNCTION:
742 lvalp->fbp = calloc(sizeof(FBLOCK), 1);
743 lvalp->fbp->name = mawk_strdup_(string_buff);
744 lvalp->fbp->code = NULL;
745 lvalp->fbp->c_next = MAWK->c_funcs;
746 MAWK->c_funcs = lvalp->fbp;
747 MAWK->current_token = C_FUNCT_ID;
748 break;
749
750
751 case ST_KEYWORD:
752 MAWK->current_token = stp->stval.kw;
753 break;
754
755 case ST_BUILTIN:
756 lvalp->bip = stp->stval.bip;
757 MAWK->current_token = BUILTIN;
758 break;
759
760 case ST_LENGTH:
761
762 lvalp->bip = stp->stval.bip;
763
764 /* check for length alone, this is an ugly
765 hack */
766 while (MAWK->scan_code[c = next(MAWK)] == SC_SPACE);
767 un_next();
768
769 MAWK->current_token = c == '(' ? BUILTIN : LENGTH;
770 break;
771
772 case ST_FIELD:
773 lvalp->cp = stp->stval.cp;
774 MAWK->current_token = FIELD;
775 break;
776
777
778 default:
779 fprintf(stderr, "stp type:%d\n", stp->type);
780 mawk_bozo(MAWK, "mawk_find returned bad st type");
781 }
782 return MAWK->current_token;
783 }
784
785
786 case SC_UNEXPECTED:
787 lvalp->ival = c & 0xff;
788 ct_ret(UNEXPECTED);
789 }
790 return 0; /* never get here make lint happy */
791 }
792
793 /* collect a decimal constant in temp_buff.
794 Return the value and error conditions by reference */
795
796 static mawk_num_t collect_decimal(mawk_state_t *MAWK, YYSTYPE *lvalp, int c, int *flag)
797 {
798 register unsigned char *p = (unsigned char *) string_buff + 1;
799 unsigned char *endp;
800 mawk_num_t d;
801
802 *flag = 0;
803 string_buff[0] = c;
804
805 if (c == '.') {
806 if (MAWK->scan_code[*p++ = next(MAWK)] != SC_DIGIT) {
807 *flag = UNEXPECTED;
808 lvalp->ival = '.';
809 return MAWK_NUM_ZERO;
810 }
811 }
812 else {
813 while (MAWK->scan_code[*p++ = next(MAWK)] == SC_DIGIT);
814 if (p[-1] != '.') {
815 un_next();
816 p--;
817 }
818 }
819 /* get rest of digits after decimal point */
820 while (MAWK->scan_code[*p++ = next(MAWK)] == SC_DIGIT);
821
822 /* check for exponent */
823 if (p[-1] != 'e' && p[-1] != 'E') {
824 un_next();
825 *--p = 0;
826 }
827 else { /* get the exponent */
828
829 if (MAWK->scan_code[*p = next(MAWK)] != SC_DIGIT && *p != '-' && *p != '+') {
830 *++p = 0;
831 *flag = BAD_DECIMAL;
832 return MAWK_NUM_ZERO;
833 }
834 else { /* get the rest of the exponent */
835
836 p++;
837 while (MAWK->scan_code[*p++ = next(MAWK)] == SC_DIGIT);
838 un_next();
839 *--p = 0;
840 }
841 }
842
843 errno = 0; /* check for mawk_overflow/underflow */
844 d = strtonum(string_buff, (char **) &endp);
845
846 #ifndef STRTOD_UNDERFLOW_ON_ZERO_BUG
847 if (errno)
848 mawk_compile_error(MAWK, "%s : decimal %sflow", string_buff, d == 0.0 ? "under" : "over");
849 #else /* ! sun4 bug */
850 if (errno && d != 0.0)
851 mawk_compile_error(MAWK, "%s : decimal mawk_overflow", string_buff);
852 #endif
853
854 if (endp < p) {
855 *flag = BAD_DECIMAL;
856 return 0.0;
857 }
858 return d;
859 }
860
861 /*---------- process escape characters ---------------*/
862 static int collect_string(mawk_state_t * MAWK, YYSTYPE *lvalp)
863 {
864 register unsigned char *p = (unsigned char *) string_buff;
865 int c;
866 int e_flag = 0; /* on if have an escape char */
867
868 while (1)
869 switch (MAWK->scan_code[*p++ = next(MAWK)]) {
870 case SC_DQUOTE: /* done */
871 *--p = 0;
872 goto out;
873
874 case SC_NL:
875 p[-1] = 0;
876 /* fall thru */
877
878 case 0: /* unterminated string */
879 mawk_compile_error(MAWK, "runaway string constant \"%.10s ...", string_buff, MAWK->token_lineno);
880 mawk_exitval(MAWK, 2, -1);
881
882 case SC_ESCAPE:
883 if ((c = next(MAWK)) == '\n') {
884 p--;
885 MAWK->lineno++;
886 }
887 else if (c == 0)
888 un_next();
889 else {
890 *p++ = c;
891 e_flag = 1;
892 }
893
894 break;
895
896 default:
897 break;
898 }
899
900 out:
901 lvalp->ptr = (PTR) mawk_new_STRING(MAWK, e_flag ? mawk_rm_escape(MAWK, string_buff)
902 : string_buff);
903 return STRING_;
904 }
905
906
907 static int collect_RE(mawk_state_t * MAWK, YYSTYPE *lvalp)
908 {
909 register unsigned char *p = (unsigned char *) string_buff;
910 int c;
911 mawk_string_t *sval;
912
913 while (1)
914 switch (MAWK->scan_code[*p++ = next(MAWK)]) {
915 case SC_DIV: /* done */
916 *--p = 0;
917 goto out;
918
919 case SC_NL:
920 p[-1] = 0;
921 /* fall thru */
922
923 case 0: /* unterminated re */
924 mawk_compile_error(MAWK, "runaway regular expression /%.10s ...", string_buff, MAWK->token_lineno);
925 mawk_exitval(MAWK, 2, -1);
926
927 case SC_ESCAPE:
928 switch (c = next(MAWK)) {
929 case '/':
930 p[-1] = '/';
931 break;
932
933 case '\n':
934 p--;
935 break;
936
937 case 0:
938 un_next();
939 break;
940
941 default:
942 *p++ = c;
943 break;
944 }
945 break;
946 }
947
948 out:
949 /* now we've got the RE, so compile it */
950 sval = mawk_new_STRING(MAWK, string_buff);
951 lvalp->ptr = mawk_re_compile(MAWK, sval);
952 free_STRING(sval);
953 return RE;
954 }
955
956 void mawk_parser_push(mawk_state_t * MAWK)
957 {
958 if (MAWK->pstack_used >= MAWK->pstack_alloced) {
959 MAWK->pstack_alloced += 8;
960 MAWK->mawk_parser_stack = realloc(MAWK->mawk_parser_stack, sizeof(mawk_parse_state_t) * MAWK->pstack_alloced);
961 }
962 memcpy(&MAWK->mawk_parser_stack[MAWK->pstack_used], &MAWK->ps, sizeof(mawk_parse_state_t));
963 MAWK->pstack_used++;
964 memset(&MAWK->ps, 0, sizeof(mawk_parse_state_t));
965 }
966
967 int mawk_parser_pop(mawk_state_t * MAWK)
968 {
969 if (MAWK->pstack_used <= 0)
970 return 0;
971
972 mawk_zfree(MAWK, MAWK->ps.buffer, BUFFSZ + 1);
973 MAWK->ps.buffer = NULL;
974 MAWK->ps.buffp = NULL;
975
976 MAWK->pstack_used--;
977 memcpy(&MAWK->ps, &MAWK->mawk_parser_stack[MAWK->pstack_used], sizeof(mawk_parse_state_t));
978
979 if (MAWK->pstack_used == 0) {
980 free(MAWK->mawk_parser_stack);
981 MAWK->mawk_parser_stack = NULL;
982 MAWK->pstack_alloced = 0;
983 }
984
985 return 1;
986 }
987
988 /* error handling */
989
990 void mawk_unexpected_char(mawk_state_t * MAWK, YYSTYPE *lvalp)
991 {
992 int c = lvalp->ival;
993
994 fprintf(stderr, "%s: %u: ", MAWK->progname, MAWK->token_lineno);
995 if (c > ' ' && c < 127)
996 fprintf(stderr, "unexpected character '%c'\n", c);
997 else
998 fprintf(stderr, "unexpected character 0x%02x\n", c);
999 }
1000
1001
1002 static void missing(mawk_state_t *, int, const char *, int);
1003
1004 static const struct token_str {
1005 short token;
1006 char *str;
1007 } token_str[] = { /* read-only */
1008 {EOF, "end of file"},
1009 {NL, "end of line"},
1010 {SEMI_COLON, ";"},
1011 {LBRACE, "{"},
1012 {RBRACE, "}"},
1013 {SC_FAKE_SEMI_COLON, "}"},
1014 {LPAREN, "("},
1015 {RPAREN, ")"},
1016 {LBOX, "["},
1017 {RBOX, "]"},
1018 {QMARK, "?"},
1019 {COLON, ":"},
1020 {OR, "||"},
1021 {AND, "&&"},
1022 {ASSIGN, "="},
1023 {ADD_ASG, "+="},
1024 {SUB_ASG, "-="},
1025 {MUL_ASG, "*="},
1026 {DIV_ASG, "/="},
1027 {MOD_ASG, "%="},
1028 {POW_ASG, "^="},
1029 {EQ, "=="},
1030 {NEQ, "!="},
1031 {LT, "<"},
1032 {LTE, "<="},
1033 {GT, ">"},
1034 {GTE, ">="},
1035 {MATCH, NULL},
1036 {PLUS, "+"},
1037 {MINUS, "-"},
1038 {MUL, "*"},
1039 {DIV, "/"},
1040 {MOD, "%"},
1041 {POW, "^"},
1042 {NOT, "!"},
1043 {COMMA, ","},
1044 {INC_or_DEC, NULL},
1045 {DOUBLE, NULL},
1046 {STRING_, NULL},
1047 {ID, NULL},
1048 {FUNCT_ID, NULL},
1049 {BUILTIN, NULL},
1050 {IO_OUT, NULL},
1051 {IO_IN, "<"},
1052 {PIPE, "|"},
1053 {DOLLAR, "$"},
1054 {FIELD, "$"},
1055 {0, NULL}
1056 };
1057
1058 /* if paren_cnt >0 and we see one of these, we are missing a ')' */
1059 static const int missing_rparen[] = /* read-only */
1060 { EOF, NL, SEMI_COLON, SC_FAKE_SEMI_COLON, RBRACE, 0 };
1061
1062 /* ditto for '}' */
1063 static const int missing_rbrace[] = /* read-only */
1064 { EOF, BEGIN, END, 0 };
1065
1066 void Mawk_error(mawk_state_t *MAWK, char *s_unused)
1067 {
1068 const struct token_str *p;
1069 const int *ip;
1070 const char *s;
1071
1072 s = (char *) 0;
1073
1074 for (p = token_str; p->token; p++)
1075 if (MAWK->current_token == p->token) {
1076 s = (p->str == NULL) ? string_buff : p->str;
1077 break;
1078 }
1079
1080 if (!s) /* search the keywords */
1081 s = mawk_find_kw_str(MAWK->current_token);
1082
1083 if (s) {
1084 if (MAWK->paren_cnt)
1085 for (ip = missing_rparen; *ip; ip++)
1086 if (*ip == MAWK->current_token) {
1087 missing(MAWK, ')', s, MAWK->token_lineno);
1088 MAWK->paren_cnt = 0;
1089 goto done;
1090 }
1091
1092 if (MAWK->brace_cnt)
1093 for (ip = missing_rbrace; *ip; ip++)
1094 if (*ip == MAWK->current_token) {
1095 missing(MAWK, CL_BRACE, s, MAWK->token_lineno);
1096 MAWK->brace_cnt = 0;
1097 goto done;
1098 }
1099
1100 mawk_compile_error(MAWK, "syntax error at or near %s", s);
1101
1102 }
1103 else /* special cases */
1104 switch (MAWK->current_token) {
1105 case UNEXPECTED:
1106 mawk_unexpected_char(MAWK, (YYSTYPE *)MAWK->lvalp);
1107 goto done;
1108
1109 case BAD_DECIMAL:
1110 mawk_compile_error(MAWK, "syntax error in decimal constant %s", string_buff);
1111 break;
1112
1113 case RE:
1114 mawk_compile_error(MAWK, "syntax error at or near /%s/", string_buff);
1115 break;
1116
1117 default:
1118 mawk_compile_error(MAWK, "syntax error");
1119 break;
1120 }
1121 return;
1122
1123 done:
1124 if (++(MAWK->compile_error_count) == MAX_COMPILE_ERRORS)
1125 mawk_exit(MAWK, 2);
1126 }
1127
1128 static void missing(mawk_state_t *MAWK, int c, const char *n, int ln)
1129 {
1130 const char *s0, *s1;
1131
1132 if (MAWK->ps.pfile_name) {
1133 s0 = MAWK->ps.pfile_name;
1134 s1 = ": ";
1135 }
1136 else
1137 s0 = s1 = "";
1138
1139 mawk_errmsg(MAWK, 0, "%s%sline %u: missing %c near %s", s0, s1, ln, c, n);
1140 }
0
1 /********************************************
2 scan.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef SCAN_H_INCLUDED
17 #define SCAN_H_INCLUDED 1
18
19
20 #ifndef MAKESCAN
21 #include <libmawk/symtype.h>
22 #include <libmawk/parse.h>
23
24 void mawk_parser_push(mawk_state_t * MAWK);
25 int mawk_parser_pop(mawk_state_t * MAWK);
26 int mawk_scan_open(mawk_state_t * MAWK);
27
28 void mawk_parse(mawk_state_t *);
29 int Mawk_lex(YYSTYPE *lvalp, mawk_state_t *);
30 int Mawk_parse(mawk_state_t *);
31 void Mawk_error(mawk_state_t *MAWK, char *s_unused);
32 void mawk_scan_cleanup(mawk_state_t *);
33 void mawk_unexpected_char(mawk_state_t * MAWK, YYSTYPE *lvalp);
34 #endif
35
36
37 extern const char mawk_scan_code[256]; /* read-only */
38
39 /* the scan codes to compactify the main switch */
40
41 #define SC_SPACE 1
42 #define SC_NL 2
43 #define SC_SEMI_COLON 3
44 #define SC_FAKE_SEMI_COLON 4
45 #define SC_LBRACE 5
46 #define SC_RBRACE 6
47 #define SC_QMARK 7
48 #define SC_COLON 8
49 #define SC_OR 9
50 #define SC_AND 10
51 #define SC_PLUS 11
52 #define SC_MINUS 12
53 #define SC_MUL 13
54 #define SC_DIV 14
55 #define SC_MOD 15
56 #define SC_POW 16
57 #define SC_LPAREN 17
58 #define SC_RPAREN 18
59 #define SC_LBOX 19
60 #define SC_RBOX 20
61 #define SC_IDCHAR 21
62 #define SC_DIGIT 22
63 #define SC_DQUOTE 23
64 #define SC_ESCAPE 24
65 #define SC_COMMENT 25
66 #define SC_EQUAL 26
67 #define SC_NOT 27
68 #define SC_LT 28
69 #define SC_GT 29
70 #define SC_COMMA 30
71 #define SC_DOT 31
72 #define SC_MATCH 32
73 #define SC_DOLLAR 33
74 #define SC_UNEXPECTED 34
75 #define SC_INCLUDE 35
76
77 #ifndef MAKESCAN
78
79 void mawk_eat_nl(mawk_state_t * MAWK, YYSTYPE *lvalp);
80
81 #define ct_ret(x) return MAWK->current_token = (x)
82
83 #define next(MAWK) (*MAWK->ps.buffp ? *MAWK->ps.buffp++ : slow_next(MAWK))
84 #define un_next() MAWK->ps.buffp--
85
86 #define mawk_test1_ret(c,x,d) if ( next(MAWK) == (c) ) ct_ret(x) ;\
87 else { un_next() ; ct_ret(d) ; }
88
89 #define mawk_test2_ret(c1,x1,c2,x2,d) switch( next(MAWK) )\
90 { case c1: ct_ret(x1) ;\
91 case c2: ct_ret(x2) ;\
92 default: un_next() ;\
93 ct_ret(d) ; }
94 #endif /* ! MAKESCAN */
95
96
97 #endif
0
1
2 /* scancode.c */
3
4
5 const char mawk_scan_code[256] = {
6 0,34,34,34,34,34,34,34,34, 1, 2, 1, 1, 1,34,34,
7 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
8 1,27,23,25,33,15,10,34,17,18,13,11,30,12,31,14,
9 22,22,22,22,22,22,22,22,22,22, 8, 3,28,26,29, 7,
10 34,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
11 21,21,21,21,21,21,21,21,21,21,21,19,24,20,16,21,
12 34,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
13 21,21,21,21,21,21,21,21,21,21,21, 5, 9, 6,32,34,
14 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
15 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
16 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
18 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
19 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
20 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
21 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34
22 } ;
0
1 /********************************************
2 sizes.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, 1992. Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef SIZES_H
17 #define SIZES_H
18
19 #ifndef MAX__INT
20 #include <limits.h>
21 #define MAX__INT INT_MAX
22 #define MAX__LONG LONG_MAX
23 #endif /* MAX__INT */
24
25 #if MAX__INT <= 0x7fff
26 #define SHORT_INTS
27 #define INT_FMT "%ld"
28 typedef long Int;
29 #define Max_Int MAX__LONG
30 #else
31 #define INT_FMT "%d"
32 typedef int Int;
33 #define Max_Int MAX__INT
34 #endif
35
36 #define EVAL_STACK_SIZE 256 /* initial size , can grow */
37 /* number of fields at startup, must be a power of 2
38 and FBANK_SZ-1 must be divisible by 3! */
39 #define FBANK_SZ 256
40 #define FB_SHIFT 8 /* lg(FBANK_SZ) */
41 #define NUM_FBANK 128 /* see MAX_FIELD below */
42
43
44 #define MAX_SPLIT (FBANK_SZ-1) /* needs to be divisble by 3 */
45 #define MAX_FIELD (NUM_FBANK*FBANK_SZ - 1)
46
47 #define MIN_SPRINTF 400
48
49
50 #define BUFFSZ 4096
51 /* starting buffer size for input files, grows if
52 necessary */
53
54 #define HASH_PRIME 53
55 #define A_HASH_PRIME 199
56
57
58 #define MAX_COMPILE_ERRORS 5 /* quit if more than 4 errors */
59
60 #endif /* SIZES_H */
0
1 /********************************************
2 split.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* For all splitting up to MAX_SPLIT fields go into
17 split_buff[], the rest go onto split_ov_list ( split
18 mawk_overflow list)
19
20 We can split one of three ways:
21 (1) By space:
22 mawk_space_split() and space_ov_split()
23 (2) By regular expression:
24 mawk_re_split() and re_ov_split()
25 (3) By "" (null -- split into characters)
26 mawk_null_split() and null_ov_split()
27 */
28
29 #define TEMPBUFF_GOES_HERE
30
31 #include "mawk.h"
32 #include "symtype.h"
33 #include "bi_vars.h"
34 #include "bi_funct.h"
35 #include "memory.h"
36 #include "scan.h"
37 #include "regexp.h"
38 #include "field.h"
39
40 static int re_ov_split(mawk_state_t *, char *, PTR);
41 static int space_ov_split(mawk_state_t *, char *, char *);
42 static int null_ov_split(mawk_state_t *, char *);
43
44 /* split string s of length slen on SPACE without changing s.
45 load the pieces into STRINGS and ptrs into
46 split_buff[]
47 return the number of pieces */
48
49 int mawk_space_split(mawk_state_t *MAWK, register char *s, unsigned slen)
50 {
51 char *back = s + slen;
52 int i = 0;
53 int len;
54 char *q;
55 mawk_string_t *sval;
56 int lcnt = MAX_SPLIT / 3;
57
58 #define EAT_SPACE() while ( MAWK->scan_code[*(unsigned char*)s] ==\
59 SC_SPACE ) s++
60 #define EAT_NON_SPACE() \
61 *back = ' ' ; /* sentinel */\
62 while ( MAWK->scan_code[*(unsigned char*)s] != SC_SPACE ) s++ ;\
63 *back = 0
64
65
66 while (lcnt--) {
67 EAT_SPACE();
68 if (*s == 0)
69 goto done;
70 /* mark the front with q */
71 q = s++;
72 EAT_NON_SPACE();
73 sval = split_buff[i++] = mawk_new_STRING0(MAWK, len = s - q);
74 memcpy(sval->str, q, len);
75
76 EAT_SPACE();
77 if (*s == 0)
78 goto done;
79 q = s++;
80 EAT_NON_SPACE();
81 sval = split_buff[i++] = mawk_new_STRING0(MAWK, len = s - q);
82 memcpy(sval->str, q, len);
83
84 EAT_SPACE();
85 if (*s == 0)
86 goto done;
87 q = s++;
88 EAT_NON_SPACE();
89 sval = split_buff[i++] = mawk_new_STRING0(MAWK, len = s - q);
90 memcpy(sval->str, q, len);
91
92 }
93 /* we've mawk_overflowed */
94 return i + space_ov_split(MAWK, s, back);
95
96 done:
97 return i;
98 }
99
100 static int space_ov_split(mawk_state_t *MAWK, register char *s, char *back)
101 {
102 SPLIT_OV dummy;
103 register SPLIT_OV *tail = &dummy;
104 char *q;
105 int cnt = 0;
106 unsigned len;
107
108 while (1) {
109 EAT_SPACE();
110 if (*s == 0)
111 break; /* done */
112 q = s++;
113 EAT_NON_SPACE();
114
115 tail = tail->link = MAWK_ZMALLOC(MAWK, SPLIT_OV);
116 tail->sval = mawk_new_STRING0(MAWK, len = s - q);
117 memcpy(tail->sval->str, q, len);
118 cnt++;
119 }
120
121 tail->link = (SPLIT_OV *) 0;
122 MAWK->split_ov_list = dummy.link;
123 return cnt;
124 }
125
126 /* match a string with a regular expression, but
127 only matches of positive length count */
128 char *mawk_re_pos_match(mawk_state_t *MAWK, register char *s, PTR re, unsigned *lenp)
129 {
130 while ((s = mawk_REmatch(MAWK, s, re, lenp, 0)))
131 if (*lenp)
132 return s;
133 else if (*s == 0)
134 break;
135 else
136 s++;
137
138 return (char *) 0;
139 }
140
141 int mawk_re_split(mawk_state_t *MAWK, char *s, PTR re)
142 {
143 register char *t;
144 int i = 0;
145 unsigned mlen, len;
146 mawk_string_t *sval;
147 int lcnt = MAX_SPLIT / 3;
148
149 while (lcnt--) {
150 if (!(t = mawk_re_pos_match(MAWK, s, re, &mlen)))
151 goto done;
152 sval = split_buff[i++] = mawk_new_STRING0(MAWK, len = t - s);
153 memcpy(sval->str, s, len);
154 s = t + mlen;
155
156 if (!(t = mawk_re_pos_match(MAWK, s, re, &mlen)))
157 goto done;
158 sval = split_buff[i++] = mawk_new_STRING0(MAWK, len = t - s);
159 memcpy(sval->str, s, len);
160 s = t + mlen;
161
162 if (!(t = mawk_re_pos_match(MAWK, s, re, &mlen)))
163 goto done;
164 sval = split_buff[i++] = mawk_new_STRING0(MAWK, len = t - s);
165 memcpy(sval->str, s, len);
166 s = t + mlen;
167 }
168 /* we've mawk_overflowed */
169 return i + re_ov_split(MAWK, s, re);
170
171 done:
172 split_buff[i++] = mawk_new_STRING(MAWK, s);
173 return i;
174 }
175
176 /*
177 we've mawk_overflowed split_buff[] , put
178 the rest on the split_ov_list
179 return number of pieces
180 */
181
182 static int re_ov_split(mawk_state_t *MAWK, char *s, PTR re)
183 {
184 SPLIT_OV dummy;
185 register SPLIT_OV *tail = &dummy;
186 int cnt = 1;
187 char *t;
188 unsigned len, mlen;
189
190 while ((t = mawk_re_pos_match(MAWK, s, re, &mlen))) {
191 tail = tail->link = MAWK_ZMALLOC(MAWK, SPLIT_OV);
192 tail->sval = mawk_new_STRING0(MAWK, len = t - s);
193 memcpy(tail->sval->str, s, len);
194 s = t + mlen;
195 cnt++;
196 }
197 /* and one more */
198 tail = tail->link = MAWK_ZMALLOC(MAWK, SPLIT_OV);
199 tail->sval = mawk_new_STRING(MAWK, s);
200 tail->link = (SPLIT_OV *) 0;
201 MAWK->split_ov_list = dummy.link;
202
203 return cnt;
204 }
205
206
207 int mawk_null_split(mawk_state_t *MAWK, char *s)
208 {
209 int cnt = 0; /* number of fields split */
210 mawk_string_t *sval;
211 int i = 0; /* indexes split_buff[] */
212
213 while (*s) {
214 if (cnt == MAX_SPLIT)
215 return cnt + null_ov_split(MAWK, s);
216
217 sval = mawk_new_STRING0(MAWK, 1);
218 sval->str[0] = *s++;
219 split_buff[i++] = sval;
220 cnt++;
221 }
222 return cnt;
223 }
224
225 static int null_ov_split(mawk_state_t *MAWK, char *s)
226 {
227 SPLIT_OV dummy;
228 SPLIT_OV *ovp = &dummy;
229 int cnt = 0;
230
231 while (*s) {
232 ovp = ovp->link = MAWK_ZMALLOC(MAWK, SPLIT_OV);
233 ovp->sval = mawk_new_STRING0(MAWK, 1);
234 ovp->sval->str[0] = *s++;
235 cnt++;
236 }
237 ovp->link = (SPLIT_OV *) 0;
238 MAWK->split_ov_list = dummy.link;
239 return cnt;
240 }
241
242
243 /* split(s, X, r)
244 split s into array X on r
245
246 entry: sp[0] holds r
247 sp[-1] pts at X
248 sp[-2] holds s
249 */
250 mawk_cell_t *mawk_bi_split(mawk_state_t *MAWK, register mawk_cell_t *sp)
251 {
252 int cnt; /* the number of pieces */
253
254
255 if (sp->type < C_RE)
256 mawk_cast_for_split(MAWK, sp);
257 /* can be C_RE, C_SPACE or C_SNULL */
258 sp -= 2;
259 if (sp->type < C_STRING)
260 mawk_cast1_to_str(MAWK, sp);
261
262 if (string(sp)->len == 0) /* nothing to split */
263 cnt = 0;
264 else
265 switch ((sp + 2)->type) {
266 case C_RE:
267 cnt = mawk_re_split(MAWK, string(sp)->str, (sp + 2)->ptr);
268 break;
269
270 case C_SPACE:
271 cnt = mawk_space_split(MAWK, string(sp)->str, string(sp)->len);
272 break;
273
274 case C_SNULL: /* split on empty string */
275 cnt = mawk_null_split(MAWK, string(sp)->str);
276 break;
277
278 default:
279 mawk_bozo(MAWK, "bad splitting cell in bi_split");
280 }
281
282
283 free_STRING(string(sp));
284 sp->type = C_NUM;
285 sp->d.dval = (mawk_num_t) cnt;
286
287 mawk_array_load(MAWK, (mawk_array_t) (sp + 1)->ptr, cnt);
288
289 return sp;
290 }
0 /* Walk the split buffer (first the list above SPLIT_MAX then the
1 array below SPLIT_MAX, unordered walk) and run action_macro
2 for each item. Action_macro is pasted twice: once for the list,
3 then for the array.
4
5 cnt is the number of fields.
6
7 If free_list is non-zero, the ov list items are freed after
8 action_macro. Not deleting the list is useful if multiple runs
9 are required.
10
11 Calling convention for the action macro is:
12 action(idx, sval)
13 where idx is an integer index numbered from 0 and sval is a mawk_string_t.
14 */
15 #define mawk_split_walk(MAWK, cnt, free_list, action_macro) \
16 do { \
17 int spwlk__cnt = cnt; \
18 mawk_split_walk_top(MAWK, spwlk__cnt, free_list, action_macro); \
19 mawk_split_walk_bottom(MAWK, spwlk__cnt, action_macro); \
20 } while(0)
21
22
23 /* walk items above MAX_SPLIT from a linked list
24 sets cnt to MAX_SPLIT if it was larger than MAX_SPLIT;
25 NOTE: this is half of the job mawk_split_walk does */
26 #define mawk_split_walk_top(MAWK, cnt, free_list, action_macro) \
27 do { \
28 if (cnt > MAX_SPLIT) { \
29 SPLIT_OV *spwlk__p = MAWK->split_ov_list; \
30 SPLIT_OV *spwlk__q; \
31 int spwlk__i; \
32 MAWK->split_ov_list = (SPLIT_OV *) 0; \
33 spwlk__i = MAX_SPLIT; \
34 while (spwlk__p) { \
35 { action_macro(spwlk__i, (spwlk__p->sval)); } \
36 spwlk__q = spwlk__p; \
37 spwlk__p = spwlk__q->link; \
38 if (free_list) \
39 MAWK_ZFREE(MAWK, spwlk__q); \
40 spwlk__i++; \
41 } \
42 cnt = MAX_SPLIT; \
43 } \
44 } while(0)
45
46 /* walk items below MAX_SPLIT from the split buff, up to cnt;
47 cnt must not be larger or equal to MAX_SPLIT! cnt is not modified
48 NOTE: this is half of the job mawk_split_walk does */
49 #define mawk_split_walk_bottom(MAWK, cnt, action_macro) \
50 do { \
51 int spwlk__i; \
52 for (spwlk__i = 0; spwlk__i < cnt; spwlk__i++) { \
53 action_macro(spwlk__i, split_buff[spwlk__i]); \
54 } \
55 } while(0)
56
57
0
1 /********************************************
2 str.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16
17 #include "mawk.h"
18 #include "scan.h"
19
20 static const char hex_val['f' - 'A' + 1] = /* read-only */
21 {
22 10, 11, 12, 13, 14, 15, 0, 0,
23 0, 0, 0, 0, 0, 0, 0, 0,
24 0, 0, 0, 0, 0, 0, 0, 0,
25 0, 0, 0, 0, 0, 0, 0, 0,
26 10, 11, 12, 13, 14, 15
27 };
28
29
30 #define isoctal(x) ((x)>='0'&&(x)<='7')
31
32 #define hex_value(x) hex_val[(x)-'A']
33
34 #define ishex(x) (MAWK->scan_code[x] == SC_DIGIT ||\
35 ('A' <= (x) && (x) <= 'f' && hex_value(x)))
36
37 static int octal(char **);
38 static int hex(mawk_state_t *, char **);
39
40 /* process one , two or three octal digits
41 moving a pointer forward by reference */
42 static int octal(char **start_p)
43 {
44 register char *p = *start_p;
45 register unsigned x;
46
47 x = *p++ - '0';
48 if (isoctal(*p)) {
49 x = (x << 3) + *p++ - '0';
50 if (isoctal(*p))
51 x = (x << 3) + *p++ - '0';
52 }
53 *start_p = p;
54 return x & 0xff;
55 }
56
57 /* process one or two hex digits
58 moving a pointer forward by reference */
59
60 static int hex(mawk_state_t *MAWK, char **start_p)
61 {
62 register unsigned char *p = (unsigned char *) *start_p;
63 register unsigned x;
64 unsigned t;
65
66 if (MAWK->scan_code[*p] == SC_DIGIT)
67 x = *p++ - '0';
68 else
69 x = hex_value(*p++);
70
71 if (MAWK->scan_code[*p] == SC_DIGIT)
72 x = (x << 4) + *p++ - '0';
73 else if ('A' <= *p && *p <= 'f' && (t = hex_value(*p))) {
74 x = (x << 4) + t;
75 p++;
76 }
77
78 *start_p = (char *) p;
79 return x;
80 }
81
82
83 /* process the escape characters in a string, in place . */
84 char *mawk_rm_escape(mawk_state_t *MAWK, char *s)
85 {
86 register char *p, *q;
87 char *t;
88 int i;
89
90 q = p = s;
91
92 while (*p) {
93 if (*p == '\\') {
94 MAWK->escape_test[ET_END].in = *++p; /* sentinal */
95 i = 0;
96 while (MAWK->escape_test[i].in != *p)
97 i++;
98
99 if (i != ET_END) { /* in table */
100 p++;
101 *q++ = MAWK->escape_test[i].out;
102 }
103 else if (isoctal(*p)) {
104 t = p;
105 *q++ = octal(&t);
106 p = t;
107 }
108 else if ((*p == 'x') && (ishex(*(unsigned char *) (p + 1)))) {
109 t = p + 1;
110 *q++ = hex(MAWK, &t);
111 p = t;
112 }
113 else if (*p == 0) /* can only happen with command line assign */
114 *q++ = '\\';
115 else { /* not an escape sequence */
116
117 *q++ = '\\';
118 *q++ = *p++;
119 }
120 }
121 else
122 *q++ = *p++;
123 }
124
125 *q = 0;
126 return s;
127 }
0
1 /********************************************
2 symtype.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* types related to symbols are defined here */
17
18 #ifndef SYMTYPE_H
19 #define SYMTYPE_H
20
21 /*---------------------------
22 structures and types for arrays
23 *--------------------------*/
24
25 #include <libmawk/array.h>
26
27 /* for parsing (i,j) in A */
28 typedef struct {
29 int start; /* offset to code_base */
30 int cnt;
31 } ARG2_REC;
32
33 void mawk_add_to_fdump_list(mawk_state_t *, FBLOCK *);
34 int mawk_fdump(mawk_state_t * MAWK);
35
36 /*-------------------------
37 elements of the symbol table
38 -----------------------*/
39
40 #define ST_NONE 0
41 #define ST_VAR 1
42 #define ST_KEYWORD 2
43 #define ST_BUILTIN 3 /* a pointer to a builtin record */
44 #define ST_ARRAY 4 /* a void * ptr to a mawk_hash table */
45 #define ST_FIELD 5 /* a cell ptr to a field */
46 #define ST_FUNCT 6
47 #define ST_NR 7 /* NR is special */
48 /* ST_ENV 8 used to be ENVIRON[] before virtual array support*/
49 #define ST_LENGTH 9 /* ditto and mawk_bozo */
50 #define ST_LOCAL_NONE 10
51 #define ST_LOCAL_VAR 11
52 #define ST_LOCAL_ARRAY 12
53 #define ST_C_FUNCTION 13 /* call from the awk script to a c function - stores a function pointer */
54
55 #define is_local(stp) ((stp)->type>=ST_LOCAL_NONE)
56
57
58 /*****************************
59 structures for type checking function calls
60 ******************************/
61
62 typedef struct ca_rec {
63 struct ca_rec *link;
64 short type;
65 short arg_num; /* position in callee's stack */
66 /*--------- this mawk_data only set if we'll need to patch -------*/
67 /* happens if argument is an ID or type ST_NONE or ST_LOCAL_NONE */
68
69 int call_offset;
70 /* where the type is stored */
71 SYMTAB *sym_p; /* if type is ST_NONE */
72 char *type_p; /* if type is ST_LOCAL_NONE */
73 } CA_REC; /* call argument record */
74
75 /* type field of CA_REC matches with ST_ types */
76 #define CA_EXPR ST_LOCAL_VAR
77 #define CA_ARRAY ST_LOCAL_ARRAY
78
79 struct fcall {
80 struct fcall *link;
81 FBLOCK *callee;
82 short call_scope;
83 short move_level;
84 FBLOCK *call; /* only used if call_scope == SCOPE_FUNCT */
85 INST *call_start; /* computed later as code may be moved */
86 CA_REC *arg_list;
87 short arg_cnt_checked;
88 unsigned line_no; /* for error messages */
89 };
90
91 extern FCALL_REC *resolve_list;
92
93 void mawk_resolve_fcalls(mawk_state_t * MAWK);
94 void mawk_check_fcall(mawk_state_t *, FBLOCK *, int, int, FBLOCK *, CA_REC *, unsigned);
95 void mawk_relocate_resolve_list(mawk_state_t *MAWK, int, int, FBLOCK *, int, unsigned, int);
96
97 /* mawk_hash.c */
98 unsigned mawk_hash(const char *);
99
100 /* register a symbol; name is not copied, the pointer is stored in the table! */
101 SYMTAB *mawk_insert(mawk_state_t *, const char *name);
102
103 #ifdef MAWK_MEM_PEDANTIC
104 /* remove a symbol */
105 void mawk_delete(mawk_state_t *MAWK, const char *name, int cell_destroy);
106 #endif
107
108 SYMTAB *mawk_find(mawk_state_t *, const char *, int);
109 extern const char *mawk_reverse_uk;
110 const char *mawk_reverse_find(mawk_state_t *, int, PTR);
111 SYMTAB *mawk_save_id(mawk_state_t * MAWK, const char *);
112 void mawk_restore_ids(mawk_state_t * MAWK);
113
114 /* error.c */
115 void mawk_type_error(mawk_state_t *, SYMTAB *);
116
117 #endif /* SYMTYPE_H */
0 # stop after the first test that fails
1 #STOP_WHEN_TEST_FAILS=1
2
3 # change which awk implementation to test
4 #AWK=mawk
5
6 # change where vendor and the 3rd party tests are checked out
7 #TROOT_DIR=../../../../vendor/3rd_tests
8
9 # change which tests to run
10 #TEST_FILES=g.*.sh
0 #!/bin/sh
1
2 AWK=../lmawk
3 TROOT_DIR=../../../../vendor/3rd_tests
4
5 if test -f ./Test.conf
6 then
7 . ./Test.conf
8 fi
9
10 if test -z "$TEST_FILES"
11 then
12 TEST_FILES=g.*.sh
13 fi
14
15 if test -z "$TEST_GAWK_DEFAULT" -a -f gawk_default.list
16 then
17 TEST_GAWK_DEFAULT=`grep -v "^#" gawk_default.list`
18 fi
19
20
21 if test -z "$TEST_GAWK_ERROR" -a -f gawk_error.list
22 then
23 TEST_GAWK_ERROR=`grep -v "^#" gawk_error.list`
24 fi
25
26 GAWK_DIR=$TROOT_DIR/gawk-4.1.1/test
27 BWK_DIR=$TROOT_DIR/bwk/test
28
29 pass_cnt=0
30 fail_cnt=0
31 unkn_cnt=0
32
33 implementation=`basename $AWK`
34
35 announce()
36 {
37 announced=1
38 if test "$1" = 0
39 then
40 echo -n "pass"
41 pass_cnt=$(($pass_cnt + 1))
42 else
43 echo -n "FAIL"
44 fail_cnt=$(($fail_cnt + 1))
45 fail_list="$fail_list $2"
46 echo "$3" > "$2.diff"
47 if test ! -z "$STOP_WHEN_TEST_FAILS"
48 then
49 echo ""
50 echo "First failure, have to stop because STOP_WHEN_TEST_FAILS sais so."
51 exit 1
52 fi
53 fi
54 if test ! -z "$4" -a "$1" = 0
55 then
56 rm "$4"
57 fi
58 }
59
60 pre_ann()
61 {
62 announced=0
63 echo -n "$n: "
64 }
65
66 post_ann()
67 {
68 if test "$announced" -gt 0
69 then
70 echo ""
71 else
72 echo "???"
73 unkn_cnt=$(($unkn_cnt+1))
74 fi
75 }
76
77 gen_testname()
78 {
79 testname=${n%%.sh}
80 testname=${testname##g.}
81 testname=${testname##t.}
82 }
83
84 gawk_run_()
85 {
86 if test -f "$GAWK_DIR/$1.in"
87 then
88 $AWK -v "SRCDIR=$GAWK_DIR" -v "srcdir=$GAWK_DIR" -f "$GAWK_DIR/$1.awk" <"$GAWK_DIR/$1.in" >"$1.out" 2>&1
89 else
90 echo "" | $AWK -v "SRCDIR=$GAWK_DIR" -v "srcdir=$GAWK_DIR" -f "$GAWK_DIR/$1.awk" >"$1.out" 2>&1
91 fi
92 }
93
94 gawk_default_test()
95 {
96 local okfile
97 gawk_run_ "$1"
98 if test -f "local.$implementation/$1.ok"
99 then
100 okfile="local.$implementation/$1.ok"
101 else
102 okfile="$GAWK_DIR/$1.ok"
103 fi
104 dif=`diff -u "$okfile" "$1.out"`
105 announce "$?" "$1" "$dif" "$1.out"
106 }
107
108 gawk_error_test()
109 {
110 local res err
111 gawk_run_ "$1"
112 if test "$?" == 0
113 then
114 # should have returned false but it's true!
115 res=1
116 echo ""
117 echo "*** exit status 0 ***" >> "$1.out"
118 else
119 case $AWK in
120 *mawk*)
121 # it's false, but check for a compile-time error
122 err=`grep ": line [0-9]\+:" "$1.out"; grep ": run time error:" "$1.out"`
123 if test -z "$err"
124 then
125 res=1
126 echo "*** doesn't look like a compile time or run time error ***" >> "$1.out"
127 else
128 res=0
129 fi
130 ;;
131 *) res=0 ;;
132 esac
133 fi
134 announce "$res" "$1" "$dif" "$1.out"
135 }
136
137 if test ! -z "$TEST_FILES"
138 then
139 for n in $TEST_FILES
140 do
141 gen_testname $n
142 pre_ann $n
143 . ./$n
144 post_ann
145 done
146 fi
147
148 if test ! -z "$TEST_GAWK_DEFAULT"
149 then
150 for n_ in $TEST_GAWK_DEFAULT
151 do
152 n=g.$n_
153 testname=$n_
154 pre_ann
155 gawk_default_test $testname
156 post_ann
157 done
158 fi
159
160 if test ! -z "$TEST_GAWK_ERROR"
161 then
162 for n_ in $TEST_GAWK_ERROR
163 do
164 n=g.$n_
165 testname=$n_
166 pre_ann
167 gawk_error_test $testname
168 post_ann
169 done
170 fi
171
172 echo "================"
173 echo "All: $(($pass_cnt + $fail_cnt + $unkn_cnt)) pass: $pass_cnt ???: $unkn_cnt fail: $fail_cnt"
174 if test ! -z "$fail_list"
175 then
176 echo "Tests failed:$fail_list"
177 fi
0 fn=argarray
1
2 cp $GAWK_DIR/$fn.in $fn.in
3 echo "" | $AWK -f $GAWK_DIR/$fn.awk $fn.in >$fn.out 2>&1
4 dif=`diff -u "local.$implementation/$fn.ok" "$fn.out"`
5 announce "$?" "$fn" "$dif" "$fn.out"
6 rm $fn.in
0 fn=argtest
1
2 echo "" | $AWK -f $GAWK_DIR/$fn.awk $fn.in Makefile >$fn.out 2>&1
3 dif=`diff -u "local.$implementation/$fn.ok" "$fn.out"`
4 announce "$?" "$fn" "$dif" "$fn.out"
5
0 fn=compare
1
2 cp $GAWK_DIR/$fn.in $fn.in
3 echo "" | $AWK -f $GAWK_DIR/$fn.awk WILL_BE_DELETED $fn.in $fn.in >$fn.out 2>&1
4 dif=`diff -u "local.$implementation/$fn.ok" "$fn.out"`
5 announce "$?" "$fn" "$dif" "$fn.out"
6 rm $fn.in
0 fn=devfd1
1
2 cp $GAWK_DIR/devfd.in1 $fn.in
3 $AWK -f $GAWK_DIR/$fn.awk $fn.in $fn.in 4<$GAWK_DIR/devfd.in4 5<$GAWK_DIR/devfd.in5 >$fn.out 2>&1
4
5
6 dif=`diff -u "local.$implementation/$fn.ok" "$fn.out"`
7 announce "$?" "$fn" "$dif" "$fn.out"
8 rm $fn.in
0 fn=exitval1
1
2 echo "hello world" | $AWK -f $GAWK_DIR/$fn.awk $fn.in >$fn.out 2>&1
3 echo "EXITVAL=$?" >> $fn.out
4 dif=`diff -u "local.$implementation/$fn.ok" "$fn.out"`
5 announce "$?" "$fn" "$dif" "$fn.out"
6
0 fn=fcall_exit
1
2 echo "" >$fn.out
3 for i in 1 2 3
4 do
5 echo "" | $AWK -f $GAWK_DIR/$fn.awk $i >>$fn.out 2>&1
6 echo "EXITVAL=$?" >> $fn.out
7 done
8 dif=`diff -u "local.$implementation/$fn.ok" "$fn.out"`
9 announce "$?" "$fn" "$dif" "$fn.out"
10
0 fn=fcall_exit2
1
2 echo "" >$fn.out
3 echo "oops" > 2
4 for i in 1 2
5 do
6 echo "*** $i" >> $fn.out
7 echo "" | $AWK -f $GAWK_DIR/$fn.awk $GAWK_DIR/$fn.in $i >>$fn.out 2>&1
8 echo "EXITVAL=$?" >> $fn.out
9 done
10 dif=`diff -u "local.$implementation/$fn.ok" "$fn.out"`
11 announce "$?" "$fn" "$dif" "$fn.out"
12 rm 2
13
0 fn=fsspcoln
1
2 echo "" >$fn.out
3 for fs in "[ :]" "[ :]+" "[ :]*" "A"
4 do
5 echo "*** FS=$fs" >>$fn.out
6 cat $GAWK_DIR/$fn.in | $AWK -f $GAWK_DIR/$fn.awk -F "$fs" >>$fn.out 2>&1
7 done
8 dif=`diff -u "local.$implementation/$fn.ok" "$fn.out"`
9 announce "$?" "$fn" "$dif" "$fn.out"
10
0 fn=getline2
1
2 echo "" | $AWK -f $GAWK_DIR/$fn.awk $GAWK_DIR/$fn.awk $GAWK_DIR/$fn.awk >$fn.out 2>&1
3 dif=`diff -u "$GAWK_DIR/$fn.ok" "$fn.out"`
4 announce "$?" "$fn" "$dif" "$fn.out"
5
0 fn=iobug1
1
2 echo "" | $AWK -f $GAWK_DIR/$fn.awk >$fn.out 2>&1
3 dif=`diff -u "$GAWK_DIR/$fn.ok" "$fn.out"`
4 announce "$?" "$fn" "$dif" "$fn.out"
5
0 fn=manyfiles
1
2 mkdir junk
3
4 echo "*** stdout:" >$fn.out
5 echo "foo bar
6 baz BAZ" | $AWK -f $GAWK_DIR/$fn.awk >>$fn.out 2>&1
7
8 for n in foo baz
9 do
10 echo "*** junk/$n:"
11 cat junk/$n
12 rm junk/$n
13 done >>$fn.out
14
15 dif=`diff -u "local.$implementation/$fn.ok" "$fn.out"`
16
17 announce "$?" "$fn" "$dif" "$fn.out"
18 rmdir junk
19
0 fn=messages
1
2 echo "*** stdout: " >$fn.out
3 echo "" | $AWK -f $GAWK_DIR/$fn.awk $fn.in >>$fn.out 2>$fn.fd2
4 (echo "*** stderr: "; cat $fn.fd2) >>$fn.out
5 (echo "*** _out1: "; cat _out1) >>$fn.out
6
7 dif=`diff -u "local.$implementation/$fn.ok" "$fn.out"`
8 announce "$?" "$fn" "$dif" "$fn.out"
9 rm $fn.fd2 _out1
0 # *TODO means it's already in the central TODO list with references to test_3rd
1 #
2 addcomma
3 anchgsub
4 arrayprm2
5 arrayprm3
6 arrayref
7 arrymem1
8 arryref2
9 arynasty
10 arynocls
11 aryprm8
12 arysubnm
13 asgext
14 back89
15 backbigs1
16 childin
17 clobber
18 closebad
19 clsflnam
20 compare2
21 concat1
22 concat2
23 concat3
24 concat4
25 convfmt
26 delargv
27 delarpm2
28 delarprm
29 # delsub TODO: check if we need to reimplement this
30 # dfastress TODO: fails badly
31 dynlj
32 eofsplit
33 exit2
34 exitval2
35 fldchg
36 fldchgnf
37 # fmtspcl TODO: figure out what to do with the NaNs
38 fmttest
39 fnarydel
40 fnparydl
41 fordel
42 forref
43 fsbs
44 fsfwfs
45 fsrs
46 fstabplus
47 # funlen *TODO: check posix: should length(array) work?
48 funsemnl
49 # getline *TODO: concat precedence over IO
50 getline3
51 getline4
52 getline5
53 getlnbuf
54 getlndir
55 getlnhd
56 getnr2tb
57 getnr2tm
58 gsubtest
59 gsubtst2
60 # gsubtst3 TODO: ???
61 # gsubtst4 TODO: extended regex?
62 gsubtst5
63 gsubtst7
64 gsubtst8
65 hello
66 hsprint
67 igncdym
68 inftest
69 # inputred concat precedence over IO: it is implementation defined by POSIX, portable awk programs shall use ()
70 intest
71 intprec
72 # jarebug *TODO: regex on binary
73 leadnl
74 litoct
75 longsub
76 manglprm
77 math
78 # mbprintf1 TODO: lmawk binary
79 mbprintf2
80 mbprintf3
81 # mbprintf4 TODO: lmawk binary
82 mbstr1
83 membug1
84 minusstr
85 mpfrnegzero
86 mtchi18n
87 nasty
88 nasty2
89 negexp
90 negrange
91 nested
92 nfldstr
93 nfloop
94 nfset
95 nlfldsep
96 nlinstr
97 nlstrina
98 noloop1
99 noloop2
100 nonl
101 # nulrsend TODO: POSIX: RS null = separate by blank line
102 numindex
103 numsubstr
104 octsub
105 ofmt
106 ofmta
107 ofmtfidl
108 ofmts
109 # ofs1 TODO: mawk doesn't respect FS or OFS?
110 onlynl
111 opasnidx
112 opasnslf
113 paramtyp
114 paramuninitglobal
115 parse1
116 pcntplus
117 pid
118 pipeio1
119 pipeio2
120 posix
121 posix2008sub
122 prdupval
123 prec
124 # printf0 *TODO: printf with no arg - UB?
125 printf1
126 printfbad3
127 # printfloat TODO: very strange format breaks
128 prmreuse
129 prt1eval
130 prtoeval
131 rand
132 range1
133 rebt8b1
134 # rebt8b2 TODO: binary?
135 rebuf
136 redfilnm
137 regeq
138 regexprange
139 # regx8bit *TODO: binary regex?
140 # reindops *TODO: regex "^+" ; should we interpret the + as a literal?
141 reparse
142 resplit
143 rri1
144 rs
145 rsnul1nl
146 rsstart1
147 rstest1
148 rstest2
149 rstest3
150 rstest4
151 rstest5
152 rstest6
153 rswhite
154 shadow
155 splitargv
156 splitarr
157 splitdef
158 splitvar
159 splitwht
160 sprintfc
161 strcat1
162 strnum1
163 subamp
164 subi18n
165 subsepnm
166 subslash
167 substr
168 swaplns
169 tradanch
170 tweakfld
171 uninit2
172 uninit3
173 uninit4
174 # uninit5 *TODO: length() on array?
175 uninitialized
176 # uparrfs *TODO: ^ in FS
177 wideidx
178 wideidx2
179 widesub
180 widesub2
181 widesub3
182 wjposer1
183 # xref regex [:alnum:]
184 zero2
185 zeroe0
186 zeroflag
0 arrayparm
1 arryref3
2 arryref4
3 arryref5
4 aryprm1
5 aryprm2
6 aryprm3
7 aryprm4
8 aryprm5
9 aryprm6
10 aryprm7
11 badassign1
12 defref
13 delfunc
14 fnamedat
15 fnarray
16 fnarray2
17 fnaryscl
18 fnasgnm
19 fnmisc
20 funsmnam
21 gsubasgn
22 nastyparm
23 nfneg
24 nofmtch
25 noparms
26 paramdup
27 paramres
28 parseme
29 printfbad1
30 printfbad2
31 prmarscl
32 scalar
33 sclforin
34 sclifin
35 synerr1
36 synerr2
37 unterm
38
0 here we have 2 arguments
1 which are
2 lmawk
3 argarray.in
4 Environment variable TEST=
5 and the current input file is called ""
6 in main loop, this input file is known as "argarray.in"
0 ARGV[0] = lmawk
1 ARGV[1] = argtest.in
2 ARGV[2] = Makefile
0 Error `' closing input file
0 length of ARGV[0] is 5
1 length of ARGV[1] is 9
2 length of ARGV[3] is 9
0 file on fd 4
1 file on fd 5
0
1 true(1, 1, crash()) => crash properly.
2 EXITVAL=1
3 true(1, crash(), 1) => do not crash properly.
4 EXITVAL=1
5 true(1, crash()) => do not crash properly.
6 EXITVAL=1
0
1 *** 1
2 <BEGIN CONTEXT> true(1, crash()) => crash properly.
3 EXITVAL=1
4 *** 2
5 <RULE CONTEXT> true(1, crash()) => do not crash properly.
6 EXITVAL=1
0
1 *** FS=[ :]
2 b
3 *** FS=[ :]+
4 b
5 *** FS=[ :]*
6 b
7 *** FS=A
8
0 lmawk: read error (Is a directory)
1 4, 0, Is a directory
0 100000 100
1 100000000 100000
2 1e+11 100000000
3 1e+14 1e+11
4 1e+17 1e+14
5 1e+20 1e+17
6 1e+23 1e+20
7 1e+26 1e+23
8 1e+29 1e+26
9 1e+32 1e+29
10 1e+35 1e+32
11 1e+38 1e+35
12 1e+41 1e+38
13 1e+44 1e+41
14 1e+47 1e+44
15 1e+50 1e+47
16 1e+53 1e+50
17 1e+56 1e+53
18 1e+59 1e+56
19 1e+62 1e+59
20 1e+65 1e+62
21 1e+68 1e+65
22 1e+71 1e+68
23 1e+74 1e+71
24 1e+77 1e+74
25 1e+80 1e+77
26 1e+83 1e+80
27 1e+86 1e+83
28 1e+89 1e+86
29 1e+92 1e+89
30 1e+95 1e+92
31 1e+98 1e+95
32 1e+101 1e+98
33 1e+104 1e+101
34 1e+107 1e+104
35 1e+110 1e+107
36 1e+113 1e+110
37 1e+116 1e+113
38 1e+119 1e+116
39 1e+122 1e+119
40 1e+125 1e+122
41 1e+128 1e+125
42 1e+131 1e+128
43 1e+134 1e+131
44 1e+137 1e+134
45 1e+140 1e+137
46 1e+143 1e+140
47 1e+146 1e+143
48 1e+149 1e+146
49 1e+152 1e+149
50 1e+155 1e+152
51 1e+158 1e+155
52 1e+161 1e+158
53 1e+164 1e+161
54 1e+167 1e+164
55 1e+170 1e+167
56 1e+173 1e+170
57 1e+176 1e+173
58 1e+179 1e+176
59 1e+182 1e+179
60 1e+185 1e+182
61 1e+188 1e+185
62 1e+191 1e+188
63 1e+194 1e+191
64 1e+197 1e+194
65 1e+200 1e+197
66 1e+203 1e+200
67 1e+206 1e+203
68 1e+209 1e+206
69 1e+212 1e+209
70 1e+215 1e+212
71 1e+218 1e+215
72 1e+221 1e+218
73 1e+224 1e+221
74 1e+227 1e+224
75 1e+230 1e+227
76 1e+233 1e+230
77 1e+236 1e+233
78 1e+239 1e+236
79 1e+242 1e+239
80 1e+245 1e+242
81 1e+248 1e+245
82 1e+251 1e+248
83 1e+254 1e+251
84 1e+257 1e+254
85 1e+260 1e+257
86 1e+263 1e+260
87 1e+266 1e+263
88 1e+269 1e+266
89 1e+272 1e+269
90 1e+275 1e+272
91 1e+278 1e+275
92 1e+281 1e+278
93 1e+284 1e+281
94 1e+287 1e+284
95 1e+290 1e+287
96 1e+293 1e+290
97 1e+296 1e+293
98 1e+299 1e+296
99 1e+302 1e+299
100 1e+305 1e+302
101 1e+308 1e+305
102 inf 1e+308
103 inf inf
104 loop terminated
0 *** stdout:
1 *** junk/foo:
2 bar
3 *** junk/baz:
4 BAZ
0 *** stdout:
1 Normal print statement
2 This printed on stdout
3 *** stderr:
4 You blew it!
5 *** _out1:
6 Goes to a file out1
0 40 27 38 60 66 15 4 4 81 16 56 50 11 17 59 2 3 16 21
0
1 /********************************************
2 types.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef MAWK_TYPES_H
17 #define MAWK_TYPES_H
18
19 #include <libmawk/sizes.h>
20 #include <libmawk/num.h>
21
22 /* mawk_cell_t types */
23
24 typedef enum {
25 C_NOINIT = 0,
26 #ifdef CELLDEBUG
27 /* catch invalid access */
28 C_FREED = 1,
29 #endif
30
31 C_NUM = 2,
32 C_ARR_REF = 3, /* array reference when using with WRARR: two adjacent cells represend index and array (on the stack, normally) */
33 C_ARR_REF_BT=4, /* array reference for bifunct_target references it is a single cell with ptr pointing to the array and d.idx_str containing the index string */
34
35 C_EXE_STTYPE=5,
36 C_EXE_STATE=6,
37 C_REQ_NOMORE=7,
38 C_REQ_CALL=8,
39
40 /* #### WARNING #### anything that is >= C_STRING is treated as a string:
41 refco, free(), etc. */
42 C_STRING = 16,
43 C_STRNUM = 17,
44 C_MBSTRN = 18, /*could be STRNUM, has not been checked */
45 C_RE = 19,
46 C_SPACE = 20, /* split on space */
47 C_SNULL = 21, /* split on the empty string */
48 C_REPL = 22, /* a replacement string '\&' changed to & */
49 C_REPLV = 23, /* a vector replacement -- broken on & */
50 NUM_CELL_TYPES
51 } mawk_celltype_t;
52
53 /* these defines are used to check types for two
54 CELLs which are adjacent in memory */
55 #define TWO_NOINITS (2*(1<<C_NOINIT))
56 #define TWO_NUMS (2*(1<<C_NUM))
57 #define TWO_STRINGS (2*(1<<C_STRING))
58 #define TWO_STRNUMS (2*(1<<C_STRNUM))
59 #define TWO_MBSTRNS (2*(1<<C_MBSTRN))
60 #define NOINIT_AND_NUM ((1<<C_NOINIT)+(1<<C_NUM))
61 #define NOINIT_AND_STRING ((1<<C_NOINIT)+(1<<C_STRING))
62 #define NOINIT_AND_STRNUM ((1<<C_NOINIT)+(1<<C_STRNUM))
63 #define NUM_AND_STRING ((1<<C_NUM)+(1<<C_STRING))
64 #define NUM_AND_STRNUM ((1<<C_STRNUM)+(1<<C_NUM))
65 #define STRING_AND_STRNUM ((1<<C_STRING)+(1<<C_STRNUM))
66 #define NOINIT_AND_MBSTRN ((1<<C_NOINIT)+(1<<C_MBSTRN))
67 #define NUM_AND_MBSTRN ((1<<C_NUM)+(1<<C_MBSTRN))
68 #define STRING_AND_MBSTRN ((1<<C_STRING)+(1<<C_MBSTRN))
69 #define STRNUM_AND_MBSTRN ((1<<C_STRNUM)+(1<<C_MBSTRN))
70
71 typedef struct {
72 unsigned len;
73 unsigned short ref_cnt;
74 char str[2];
75 } mawk_string_t;
76
77 /* number of bytes more than the characters to store a
78 string */
79 #define STRING_OH (sizeof(mawk_string_t)-1)
80
81 /* macro to get at the string part of a mawk_cell_t */
82 #define string(cp) ((mawk_string_t *)(cp)->ptr)
83
84 typedef struct mawk_cell_s mawk_cell_t;
85
86 struct mawk_cell_s {
87 mawk_celltype_t type;
88 PTR ptr; /* payload 1 - can not be in payload 2 because of STRNUMs that use both ptr for string and d.dval for num in the same time */
89 union { /* payload 2 */
90 mawk_num_t dval; /* number */
91 int vcnt; /* regex lib: only used if type == C_REPLV */
92 mawk_cell_t *idx_cell; /* zmalloc'd index for bifunct_target array refs */
93 } d;
94 };
95
96
97 /* all builtins are passed the evaluation stack pointer and
98 return its new value, here is the type */
99
100 #include "mawk.h"
101 typedef mawk_cell_t *(*PF_CP) (mawk_state_t *, mawk_cell_t *);
102
103 /* an element of code (instruction) */
104 typedef union {
105 unsigned long op; /* must be unsigned and at least 32 bits for da_bin */
106 PTR ptr;
107 } INST;
108
109 #endif /* MAWK_TYPES_H */
0
1 /********************************************
2 vargs.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1992 Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 /* provides common interface to <stdarg.h> or <varargs.h>
17 only used for error messages
18 */
19
20 #if NO_STDARG_H
21 #include <varargs.h>
22
23 #ifdef VA_ALIST
24 #define VA_ALIST(mawk_state_t *MAWK; type arg) (va_alist) va_dcl
25 #define VA_ALIST2(mawk_state_t *MAWK; t1 a1 ; t2 a2) (va_alist) va_dcl
26 #endif
27
28 #define VA_START(p,type, last) va_start(p) ;\
29 MAWK = va_arg(p,mawk_state_t *); \
30 last = va_arg(p,type)
31
32
33 #define VA_START2(p,t1,a1,t2,a2) va_start(p) ;\
34 MAWK = va_arg(p,mawk_state_t *); \
35 a1 = va_arg(p,t1);\
36 a2 = va_arg(p,t2)
37
38 #else /* have stdarg.h */
39 #include <stdarg.h>
40
41 #ifndef VA_ALIST
42 #define VA_ALIST(type, arg) (mawk_state_t *MAWK, type arg, ...)
43 #define VA_ALIST2(t1,a1,t2,a2) (mawk_state_t *MAWK, t1 a1,t2 a2,...)
44 #endif
45
46 #define VA_START(p,type,last) va_start(p,last)
47
48 #define VA_START2(p,t1,a1,t2,a2) va_start(p,a2)
49
50 #endif
0 /********************************************
1 vars.c
2
3 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991, Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14
15 #include "vars.h"
16 #include "symtype.h"
17 #include "zmalloc.h"
18 #include "cell.h"
19
20 mawk_cell_t *mawk_get_var(mawk_state_t *MAWK, const char *vname)
21 {
22 SYMTAB *fs;
23
24 fs = mawk_find(MAWK, vname, 0);
25
26 /* does symbol exist at all? */
27 if (fs == NULL)
28 return NULL;
29
30 /* return it if it is a variable */
31 if ((fs->type == ST_VAR) || (fs->type == ST_NR) || (fs->type == ST_FIELD) || (fs->type == ST_ARRAY))
32 return fs->stval.cp;
33
34 return NULL;
35 }
36
37 mawk_cell_t *mawk_create_var(mawk_state_t *MAWK, const char *name, mawk_cell_t **fp)
38 {
39 SYMTAB *stp;
40 mawk_cell_t *cp;
41 static mawk_cell_t cell; /* used if command line assign to pseudo field */
42
43 stp = mawk_find(MAWK, name, 1);
44
45 switch (stp->type) {
46 case ST_NONE:
47 stp->type = ST_VAR;
48 stp->stval.cp = cp = MAWK_ZMALLOC(MAWK, mawk_cell_t);
49 break;
50
51 case ST_VAR:
52 case ST_NR: /* !! no one will do this */
53 cp = stp->stval.cp;
54 mawk_cell_destroy(MAWK, cp);
55 break;
56
57 case ST_FIELD:
58 if (fp == NULL)
59 return NULL;
60 /* must be pseudo field */
61 *fp = stp->stval.cp;
62 cp = &cell;
63 break;
64
65 default:
66 return NULL;
67 }
68 return cp;
69 }
0 /********************************************
1 vars.h
2
3 libmawk changes (C) 2009-2012, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991, Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14
15 #include "mawk.h"
16
17 /* look up an existing variable */
18 mawk_cell_t *mawk_get_var(mawk_state_t *MAWK, const char *vname);
19
20 /* create a variable and return mawk_cell_t; overwrite/clear existing variable;
21 return NULL if an object that can not be overwritten already exist on this
22 name. fp should be NULL if field assignment is not needed */
23 mawk_cell_t *mawk_create_var(mawk_state_t *MAWK, const char *name, mawk_cell_t **fp);
0
1 /********************************************
2 version.c
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991-95. Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include "mawk.h"
17 #include "vio_orig.h"
18
19 /* mawk 1.3 */
20 #define PATCHLEVEL 3
21 #define PATCH_STRING ".3"
22 #define DATE_STRING "Nov 1996"
23 #define MAWK_ID "@(#)mawk 1.3.3"
24
25 #define VERSION_STRING \
26 "lmawk " LMAWK_VER ", Copyright (C) Tibor 'Igor2' Palinkas\n" \
27 " (http://repo.hu/projects/libmawk; email: libmawk (at) igor2.repo.hu)\n" \
28 " based on mawk 1.3%s %s, Copyright (C) Michael D. Brennan\n\n"
29
30
31 static const char fmt[] = "%-14s%10lu\n";
32
33 /* print VERSION and exit */
34 void mawk_print_version(mawk_state_t * MAWK)
35 {
36 mawk_vio_orig_setup_stdio(MAWK, 0, 1, 1);
37
38 MAWK->fnode_stdout->vf->imp->vprintf(MAWK, MAWK->fnode_stdout->vf, VERSION_STRING, PATCH_STRING, DATE_STRING);
39 mawk_vio_flush(MAWK, MAWK->fnode_stdout->vf);
40
41 MAWK->fnode_stdout->vf->imp->vprintf(MAWK, MAWK->fnode_stderr->vf, "compiled limits:\n");
42 MAWK->fnode_stdout->vf->imp->vprintf(MAWK, MAWK->fnode_stderr->vf, fmt, "max NF", (long) MAX_FIELD);
43 MAWK->fnode_stdout->vf->imp->vprintf(MAWK, MAWK->fnode_stderr->vf, fmt, "sprintf buffer", (long) SPRINTF_SZ);
44 exit(0);
45 }
46
0 /* The actual version information is #defined in Makefile.conf.in */
1
2 extern void mawk_print_version(mawk_state_t * MAWK);
0 #ifndef MAWK_VIO_H
1 #define MAWK_VIO_H
2 /* virtual I/O */
3 typedef enum mawk_vio_open_mode_e {
4 MAWK_VIO_O_TRUNC,
5 MAWK_VIO_O_APPEND,
6 MAWK_VIO_I
7 } mawk_vio_open_mode_t;
8
9 /**** init-type entry points: used to create a new vio or do a one-time-thing
10 without an existing vio; MAWK->vio_init.* point to the defaults
11 but the application is free to create a vf using a different
12 implementation directly ****/
13 /* open a normal file */
14 typedef mawk_vio_t *mawk_vio_open_t(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode);
15
16 /* open and close pipe (background process) */
17 typedef mawk_vio_t *mawk_vio_open_pipe_t(mawk_state_t *MAWK, const char *name, int type);
18
19 /* execute a shell command (system()-like wrapper around execl()) */
20 typedef void mawk_vio_exec_shell_t(mawk_state_t *MAWK, const char *cmd);
21
22
23 /**** regular vio calls on existing vios - vf->imp points to these ****/
24
25 /* write data to a vio * */
26 typedef int mawk_vio_putc_t(mawk_state_t *MAWK, mawk_vio_t *vf, char c);
27 typedef int mawk_vio_write_str_t(mawk_state_t *MAWK, mawk_vio_t *vf, const char *str);
28 typedef int mawk_vio_write_t(mawk_state_t *MAWK, mawk_vio_t *vf, const char *data, int len);
29 typedef int mawk_vio_printf_t(mawk_state_t *MAWK, mawk_vio_t *vf, const char *fmt, ...);
30
31 /* return -2 if there's no more input at the moment */
32 typedef int mawk_vio_read_t(mawk_state_t *MAWK, mawk_vio_t *f, char *dst, long int size);
33
34
35 typedef int mawk_vio_close_t(mawk_state_t *MAWK, mawk_vio_t *vf);
36 typedef int mawk_vio_flush_t(mawk_state_t *MAWK, mawk_vio_t *vf);
37
38 /* check the error state of a file node (ferror()-style) */
39 typedef int mawk_vio_error_t(mawk_state_t *MAWK, mawk_vio_t *vf);
40
41 /* mark the file no-close; this is useful for working on files that are
42 not really open by the vio implementation, for example stdout/stderr
43 in vio_orig. */
44 typedef void mawk_vio_mark_no_close_t(mawk_state_t *MAWK, mawk_vio_t *vf);
45
46 /* stdio hacks */
47
48 /* per file hooks */
49 typedef struct mawk_vio_imp_s {
50 mawk_vio_putc_t *vputc;
51 mawk_vio_write_str_t *vwrite_str;
52 mawk_vio_write_t *vwrite;
53 mawk_vio_printf_t *vprintf;
54 mawk_vio_read_t *vread;
55 mawk_vio_close_t *vclose;
56 mawk_vio_flush_t *vflush;
57 mawk_vio_error_t *error;
58 mawk_vio_mark_no_close_t *mark_no_close;
59 } mawk_vio_imp_t;
60
61 /* per file struct */
62 struct mawk_vio_s {
63 /* common header */
64 const mawk_vio_imp_t *imp;
65 int refco; /* how many times this vf is open (and referenced from the FILE_NODEs) */
66 /* implementations may have further fields here, never depend on sizeof(mawk_vio_t)! */
67 };
68
69 /* per script instance hooks */
70 typedef struct mawk_vio_init_s {
71 mawk_vio_open_t *vopen;
72 mawk_vio_open_pipe_t *vopen_pipe;
73 mawk_vio_exec_shell_t *exec_shell;
74 int inited;
75 } mawk_vio_init_t;
76
77 #define mawk_vio_putc(MAWK, vf, c) (vf)->imp->vputc(MAWK, (vf), (c))
78 #define mawk_vio_write_str(MAWK, vf, str) (vf)->imp->vwrite_str(MAWK, (vf), (str))
79 #define mawk_vio_write(MAWK, vf, data, len) (vf)->imp->vwrite(MAWK, (vf), (data), (len))
80 /* can not be implemented without C99 vararg macros:
81 #define mawk_vio_printf_t(MAWK, vf, const char *fmt, ...); */
82 #define mawk_vio_read(MAWK, vf, dst, size) (vf)->imp->vread(MAWK, (vf), (dst), (size))
83 #define mawk_vio_close(MAWK, vf) ((((vf) == NULL) || ((vf)->imp->vclose == NULL)) ? (-1) : ((vf)->imp->vclose(MAWK, (vf))))
84 #define mawk_vio_flush(MAWK, vf) (vf)->imp->vflush(MAWK, (vf))
85 #define mawk_vio_error(MAWK, vf) (vf)->imp->error(MAWK, (vf))
86
87 /* default init (entry) hooks */
88 #define mawk_vio_open(MAWK, name, mode) MAWK->vio_init.vopen(MAWK, (name), (mode))
89 #define mawk_vio_open_pipe(MAWK, name, type) MAWK->vio_init.vopen_pipe(MAWK, (name), (type))
90 #define mawk_vio_exec_shell(MAWK, cmd) MAWK->vio_init.exec_shell(MAWK, (cmd))
91 #define mawk_vio_setup_stdouts(MAWK) MAWK->vio_init.mawk_vio_setup_stdouts(MAWK)
92
93 #endif
0 /********************************************
1 libmawk (C) 2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9 #include "vio_fifo.h"
10 #include "memory.h"
11
12 mawk_vio_t *mawk_vio_fifo_open(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode)
13 {
14 mawk_vio_fifo_t *v;
15 v = mawk_zmalloc(MAWK, sizeof(mawk_vio_fifo_t));
16 v->eof_from_awk = 0;
17 v->eof_from_app = 0;
18 v->vio_common_head.imp = &mawk_vio_fifo_imp;
19 v->vio_common_head.refco = 0;
20 mawk_zfifo_alloc(MAWK, &(v->fifo), -1);
21 switch(mode) {
22 case MAWK_VIO_O_TRUNC:
23 case MAWK_VIO_O_APPEND:
24 v->is_awk2app = 1;
25 break;
26 case MAWK_VIO_I:
27 v->is_awk2app = 0;
28 break;
29 }
30 return (mawk_vio_t *)v;
31 }
32
33 /* write data to a vio * */
34 int mawk_vio_fifo_putc(mawk_state_t *MAWK, mawk_vio_t *vf, char c)
35 {
36 mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
37 if (!v->is_awk2app)
38 return -1;
39 return mawk_zfifo_write(MAWK, &(v->fifo), &c, 1);
40 }
41
42 int mawk_vio_fifo_write_str(mawk_state_t *MAWK, mawk_vio_t *vf, const char *str)
43 {
44 mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
45 int len = strlen(str);
46
47 if (!v->is_awk2app)
48 return -1;
49
50 return mawk_zfifo_write(MAWK, &(v->fifo), str, len);
51 }
52
53 int mawk_vio_fifo_write_app(mawk_state_t *MAWK, mawk_vio_t *vf, const char *data, int len)
54 {
55 mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
56 if (v->is_awk2app)
57 return -1;
58 return mawk_zfifo_write(MAWK, &(v->fifo), data, len);
59 }
60
61 int mawk_vio_fifo_write(mawk_state_t *MAWK, mawk_vio_t *vf, const char *data, int len)
62 {
63 mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
64 if (!v->is_awk2app)
65 return -1;
66 return mawk_zfifo_write(MAWK, &(v->fifo), data, len);
67 }
68
69 int mawk_vio_fifo_printf(mawk_state_t *MAWK, mawk_vio_t *vf, const char *fmt, ...)
70 {
71 mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
72 if (!v->is_awk2app)
73 return -1;
74 #warning TODO
75 abort();
76 return -1;
77 }
78
79
80 int mawk_vio_fifo_read(mawk_state_t *MAWK, mawk_vio_t *vf, char *dst, long int size)
81 {
82 mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
83 int len;
84
85 if (v->is_awk2app)
86 return -1;
87
88 len = mawk_zfifo_read(MAWK, &(v->fifo), dst, size);
89 if (len == 0) {
90 /* there's no more data and the app has finished: pass on eof */
91 if (v->eof_from_app)
92 return 0;
93
94 /* there's no more data at the moment, but the app didn't say eof yet */
95 return -2;
96 }
97
98 return len;
99 }
100
101 int mawk_vio_fifo_read_app(mawk_state_t *MAWK, mawk_vio_t *vf, char *dst, long int size)
102 {
103 mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
104 int len;
105
106 if (!v->is_awk2app)
107 return -1;
108
109 len = mawk_zfifo_read(MAWK, &(v->fifo), dst, size);
110 if (len == 0) {
111 /* there's no more data and the app has finished: pass on eof */
112 if (v->eof_from_awk)
113 return 0;
114
115 /* there's no more data at the moment, but the app didn't say eof yet */
116 return -2;
117 }
118
119 return len;
120 }
121
122 static void close_on_eof(mawk_state_t *MAWK, mawk_vio_fifo_t *v)
123 {
124 if ((v->eof_from_app) && (v->eof_from_awk)) {
125 mawk_zfifo_free(MAWK, &(v->fifo));
126 mawk_zfree(MAWK, v, sizeof(mawk_vio_fifo_t));
127 }
128 }
129
130
131 int mawk_vio_fifo_close(mawk_state_t *MAWK, mawk_vio_t *vf)
132 {
133 mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
134
135 v->eof_from_awk = 1;
136 close_on_eof(MAWK, v);
137 return 0;
138 }
139
140 int mawk_vio_fifo_eof_from_app(mawk_state_t *MAWK, mawk_vio_t *vf)
141 {
142 mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
143
144 v->eof_from_app = 1;
145 close_on_eof(MAWK, v);
146 return 0;
147 }
148
149 int mawk_vio_fifo_flush(mawk_state_t *MAWK, mawk_vio_t *vf)
150 {
151 /* nothing to do on flush */
152 return 0;
153 }
154
155 int mawk_vio_fifo_error(mawk_state_t *MAWK, mawk_vio_t *vf)
156 {
157 return (vf == NULL);
158 }
159
160 void mawk_vio_fifo_mark_no_close(mawk_state_t *MAWK, mawk_vio_t *vf)
161 {
162 /* fifos are always closed when both awk and the app closes them and
163 there are no inherited pipes anyway */
164 }
165
166 const mawk_vio_imp_t mawk_vio_fifo_imp = {
167 mawk_vio_fifo_putc,
168 mawk_vio_fifo_write_str,
169 mawk_vio_fifo_write,
170 mawk_vio_fifo_printf,
171 mawk_vio_fifo_read,
172 mawk_vio_fifo_close,
173 mawk_vio_fifo_flush,
174 mawk_vio_fifo_error,
175 mawk_vio_fifo_mark_no_close
176 };
0 #ifndef MAWK_VIO_FIFO_H
1 #define MAWK_VIO_FIFO_H
2
3 #include "mawk.h"
4 #include "vio.h"
5 #include "zfifo.h"
6
7 typedef struct mawk_vio_fifo_s {
8 mawk_vio_t vio_common_head;
9 mawk_zfifo_t fifo;
10 int is_awk2app; /* 1 if pipe is awk->app */
11 int is_stdout; /* 1 if pipe is an stdout */
12 int eof_from_awk; /* 1 if there won't be more from awk or awk won't accept more data (close()) */
13 int eof_from_app; /* 1 if there won't be more from the app or the app won't accept more data */
14 } mawk_vio_fifo_t;
15
16 const mawk_vio_imp_t mawk_vio_fifo_imp;
17
18 mawk_vio_t *mawk_vio_fifo_open(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode);
19
20
21 int mawk_vio_fifo_eof_from_app(mawk_state_t *MAWK, mawk_vio_t *vf);
22
23 /* app writes an input buffer */
24 int mawk_vio_fifo_write_app(mawk_state_t *MAWK, mawk_vio_t *vf, const char *data, int len);
25
26 /* app reads an output buffer */
27 int mawk_vio_fifo_read_app(mawk_state_t *MAWK, mawk_vio_t *vf, char *dst, long int size);
28
29 #endif
0 /********************************************
1 vio_orig.c - virtual IO: original mawk file/pipe IO implementation
2
3 libmawk changes (C) 2009-2013, Tibor 'Igor2' Palinkas;
4 based on mawk code coming with the below copyright:
5
6 copyright 1991-94. Michael D. Brennan
7
8 This is a source file for mawk, an implementation of
9 the AWK programming language.
10
11 Mawk is distributed without warranty under the terms of
12 the GNU General Public License, version 2, 1991.
13 ********************************************/
14 #include "conf.h"
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <stdarg.h>
20 #include "mawk.h"
21 #include "files.h"
22 #include "memory.h"
23 #include "fin.h"
24 #include "field.h"
25 #include "vio.h"
26 #include "array_environ.h"
27
28 /* The original mawk file IO layer uses FILE * for output (because fprintf()
29 and fflush() works on them) and int fd for input (probably for short reads
30 and manual buffering). Pipes (background processes) also need a pid for
31 wait(). In some cases stdin was read by fgets().
32
33 The vio reimplementation follows the same conventions, defining mawk_vio_t
34 to contain a FILE *, an int fd and a pid. For output FILE * is required,
35 input is done exclusively using int fd.
36 */
37
38 #ifdef V7
39 #include <sgtty.h> /* defines FIOCLEX */
40 #endif
41 #ifndef NO_FCNTL_H
42
43 #include <fcntl.h>
44 #define CLOSE_ON_EXEC(fd) fcntl(fd, F_SETFD, 1)
45
46 #else
47 #define CLOSE_ON_EXEC(fd) ioctl(fd, FIOCLEX, (PTR) 0)
48 #endif
49
50 typedef struct mawk_vio_orig_s {
51 mawk_vio_t vio_common_head;
52 pid_t pid; /* we need to wait() when we close a pipe */
53 FILE *f;
54 int fd;
55 int at_eof;
56 int no_close;
57 } mawk_vio_orig_t;
58
59
60 const mawk_vio_imp_t mawk_vio_orig_imp;
61
62 static mawk_vio_orig_t *vio_alloc_(mawk_state_t *MAWK)
63 {
64 mawk_vio_orig_t *vf;
65 vf = mawk_zmalloc(MAWK, sizeof(mawk_vio_orig_t));
66 vf->vio_common_head.imp = &mawk_vio_orig_imp;
67 vf->vio_common_head.refco = 0;
68 vf->pid = -1;
69 vf->fd = -1;
70 vf->f = NULL;
71 vf->at_eof = 0;
72 vf->no_close = 0;
73 return vf;
74 }
75
76 int mawk_vio_orig_close(mawk_state_t *MAWK, mawk_vio_t *vf_)
77 {
78 mawk_vio_orig_t *vf = (mawk_vio_orig_t *)vf_;
79
80 if (vf->f != NULL) {
81 if (!vf->no_close) {
82 fclose(vf->f);
83 vf->f = NULL;
84 }
85 }
86 if (vf->fd >= 0) {
87 if (!vf->no_close) {
88 close(vf->fd);
89 vf->fd = -1;
90 }
91 }
92 #ifndef MAWK_NO_FORK
93 if (vf->pid > 0) {
94 if (!vf->no_close) {
95 mawk_wait_for(MAWK, vf->pid);
96 vf->pid = -1;
97 }
98 }
99 #endif
100 mawk_zfree(MAWK, vf, sizeof(mawk_vio_orig_t));
101 return 0;
102 }
103
104 int mawk_vio_orig_flush(mawk_state_t *MAWK, mawk_vio_t *vf_)
105 {
106 mawk_vio_orig_t *vf = (mawk_vio_orig_t *)vf_;
107 if (vf->f != NULL) {
108 if (fflush(vf->f) < 0) {
109 mawk_errmsg(MAWK, errno, "unexpected write error");
110 mawk_exitval(MAWK, 2, -1);
111 }
112 }
113 return 0;
114 }
115
116 static void bufsetup(FILE *f)
117 {
118 if (isatty(fileno(f)))
119 setbuf(f, (char *) 0);
120 }
121
122 /* fopen() but no buffering to ttys */
123 static FILE *tfopen(const char *name, const char *mode)
124 {
125 FILE *retval = fopen(name, mode);
126 if (retval)
127 bufsetup(retval);
128
129 return retval;
130 }
131
132 static mawk_vio_t *mawk_vio_orig_fdopen(mawk_state_t *MAWK, int fd, mawk_vio_open_mode_t mode)
133 {
134 mawk_vio_orig_t *vf;
135 FILE *f;
136
137 switch(mode) {
138 case MAWK_VIO_O_TRUNC:
139 f = fdopen(fd, "w");
140 if (f == NULL)
141 return NULL;
142 bufsetup(f);
143 break;
144 case MAWK_VIO_O_APPEND:
145 f = fdopen(fd, "a");
146 if (f == NULL)
147 return NULL;
148 bufsetup(f);
149 break;
150 case MAWK_VIO_I:
151 f = NULL;
152 break;
153 }
154
155 vf = vio_alloc_(MAWK);
156 vf->f = f;
157 vf->fd = fd;
158 return (mawk_vio_t *)vf;
159 }
160
161
162
163
164 #warning TODO print runtime warnings
165 mawk_vio_t *mawk_vio_orig_open(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode)
166 {
167 mawk_vio_orig_t *vf;
168 FILE *f;
169 int fd = -1;
170
171 if (((name[0] == '-') && (name[1] == 0)) || (strcmp(name, "/dev/stdin") == 0))
172 return mawk_vio_orig_fdopen(MAWK, 0, mode);
173
174 /* /dev/fd/xxx should be fdopen */
175 if (strncmp(name, "/dev/fd/", 8) == 0) {
176 int fd;
177 char *end;
178 fd = strtol(name+8, &end, 10);
179 if (*end == '\0')
180 return mawk_vio_orig_fdopen(MAWK, fd, mode);
181 }
182
183 switch(mode) {
184 case MAWK_VIO_O_TRUNC:
185 f = tfopen(name, "w");
186 if (f == NULL)
187 return NULL;
188 break;
189 case MAWK_VIO_O_APPEND:
190 f = tfopen(name, "a");
191 if (f == NULL)
192 return NULL;
193 break;
194 case MAWK_VIO_I:
195 f = NULL;
196 fd = open(name, O_RDONLY);
197 if (fd < 0)
198 return NULL;
199 }
200
201 vf = vio_alloc_(MAWK);
202 vf->f = f;
203 vf->fd = fd;
204 return (mawk_vio_t *)vf;
205 }
206
207 #ifdef MAWK_NO_FORK
208 mawk_vio_t *mawk_vio_orig_open_pipe(mawk_state_t *MAWK, const char *name, int type)
209 {
210 if (!MAWK->do_exit)
211 mawk_rt_error(MAWK, "process execution not supported");
212 return NULL;
213 }
214
215 void mawk_vio_orig_exec_shell(mawk_state_t *MAWK, const char *cmd)
216 {
217 if (!MAWK->do_exit)
218 mawk_rt_error(MAWK, "process execution not supported");
219 }
220 #else
221
222 void mawk_vio_orig_exec_shell(mawk_state_t *MAWK, const char *cmd)
223 {
224 char **envp = mawk_environ_extract(MAWK);
225
226 if (envp == NULL) {
227 mawk_errmsg(MAWK, errno, "failed to exec %s -c %s: can't set up environ[]", MAWK->shell, cmd);
228 fflush(stderr);
229 _exit(128);
230 }
231 execle(MAWK->shell, MAWK->shell, "-c", cmd, (char *) 0, envp);
232 mawk_errmsg(MAWK, errno, "failed to exec %s -c %s", MAWK->shell, cmd);
233 fflush(stderr);
234 _exit(128);
235 }
236
237 #ifdef MAWK_NO_PIPE
238 mawk_vio_t *mawk_vio_orig_open_pipe(mawk_state_t *MAWK, const char *name, int type)
239 {
240 if (!MAWK->do_exit)
241 mawk_rt_error(MAWK, "pipes (and background processes) not supported");
242 return NULL;
243 }
244 #else
245
246 mawk_vio_t *mawk_vio_orig_open_pipe(mawk_state_t *MAWK, const char *name, int type)
247 {
248 int the_pipe[2], local_fd, remote_fd;
249 mawk_vio_orig_t *vf;
250 pid_t pid;
251 FILE *f;
252
253 if (pipe(the_pipe) < 0)
254 return NULL;
255
256 local_fd = the_pipe[type == PIPE_OUT];
257 remote_fd = the_pipe[type == PIPE_IN];
258
259 /* output files shall have a FILE * */
260 if (type == PIPE_OUT) {
261 f = fdopen(local_fd, "w");
262 if (f == NULL) {
263 close(local_fd);
264 close(remote_fd);
265 return NULL;
266 }
267 }
268
269 /* to keep output ordered correctly */
270 fflush(stdout);
271 fflush(stderr);
272
273 pid = fork();
274 switch (pid) {
275 case -1:
276 close(local_fd);
277 close(remote_fd);
278 return NULL;
279 case 0:
280 close(local_fd);
281 close(type == PIPE_IN);
282 dup(remote_fd);
283 close(remote_fd);
284 mawk_vio_exec_shell(MAWK, name);
285 default:
286 close(remote_fd);
287 /* we could deadlock if future child inherit the local fd ,
288 set close on exec flag */
289 #warning TODO: better do this by hand - close on exec is not really portable
290 CLOSE_ON_EXEC(local_fd);
291 break;
292 }
293
294 vf = vio_alloc_(MAWK);
295 vf->pid = pid;
296
297 /* for an output pipe store FILE * for consistent writes */
298 if (type == PIPE_OUT)
299 vf->f = f;
300 else
301 vf->fd = local_fd;
302
303 return (mawk_vio_t *)vf;
304 }
305 #endif
306 #endif
307
308 int mawk_vio_orig_putc(mawk_state_t *MAWK, mawk_vio_t *vf_, char c)
309 {
310 mawk_vio_orig_t *vf = (mawk_vio_orig_t *)vf_;
311 if (vf->f == NULL)
312 return -1;
313 if (fputc(c, vf->f) != c)
314 return -1;
315 return 0;
316 }
317
318 int mawk_vio_orig_write(mawk_state_t *MAWK, mawk_vio_t *vf_, const char *data, int len)
319 {
320 mawk_vio_orig_t *vf = (mawk_vio_orig_t *)vf_;
321 if (vf->f == NULL)
322 return -1;
323 if (fwrite(data, 1, len, vf->f) == 1)
324 return 0;
325 return -1;
326 }
327
328 int mawk_vio_orig_write_str(mawk_state_t *MAWK, mawk_vio_t *vf_, const char *str)
329 {
330 mawk_vio_orig_t *vf = (mawk_vio_orig_t *)vf_;
331 if (vf->f == NULL)
332 return -1;
333 return fprintf(vf->f, "%s", str);
334 }
335
336 int mawk_vio_orig_printf(mawk_state_t *MAWK, mawk_vio_t *vf_, const char *fmt, ...)
337 {
338 mawk_vio_orig_t *vf = (mawk_vio_orig_t *)vf_;
339 int len;
340 va_list ap;
341
342 if (vf->f == NULL)
343 return -1;
344
345 va_start(ap, fmt);
346 len = vfprintf(vf->f, fmt, ap);
347 va_end(ap);
348 return len;
349 }
350
351 int mawk_vio_orig_error(mawk_state_t *MAWK, mawk_vio_t *vf_)
352 {
353 mawk_vio_orig_t *vf = (mawk_vio_orig_t *)vf_;
354 if (vf->f == NULL)
355 return -1;
356 return ferror(vf->f);
357 }
358
359 int mawk_vio_orig_setbuf(mawk_state_t *MAWK, mawk_vio_t *vf_, int buf_enable)
360 {
361 mawk_vio_orig_t *vf = (mawk_vio_orig_t *)vf_;
362 if (vf->f == NULL)
363 return -1;
364
365 if (buf_enable)
366 setbuf(vf->f, "");
367 else
368 setbuf(vf->f, NULL);
369
370 return 0;
371 }
372
373 int mawk_vio_orig_read(mawk_state_t *MAWK, mawk_vio_t *vf_, char *dst, long int size)
374 {
375 mawk_vio_orig_t *vf = (mawk_vio_orig_t *)vf_;
376 int len;
377
378 /* input file must not have a FILE * */
379 if (vf->f != NULL)
380 return -1;
381
382 /* already at eof, don't attempt to read any more */
383 if (vf->at_eof)
384 return 0;
385
386 /* invalid fd, how did we get here? */
387 if (vf->fd < 0)
388 return -1;
389
390 len = read(vf->fd, dst, size);
391 if (len <= 0)
392 vf->at_eof = 1;
393 return len;
394 }
395
396 void mawk_vio_orig_mark_no_close(mawk_state_t *MAWK, mawk_vio_t *vf_)
397 {
398 mawk_vio_orig_t *vf = (mawk_vio_orig_t *)vf_;
399 vf->no_close = 1;
400 }
401
402 const mawk_vio_imp_t mawk_vio_orig_imp = {
403 mawk_vio_orig_putc,
404 mawk_vio_orig_write_str,
405 mawk_vio_orig_write,
406 mawk_vio_orig_printf,
407 mawk_vio_orig_read,
408 mawk_vio_orig_close,
409 mawk_vio_orig_flush,
410 mawk_vio_orig_error,
411 mawk_vio_orig_mark_no_close
412 };
413
414 const mawk_vio_init_t mawk_vio_orig_init = {
415 mawk_vio_orig_open,
416 mawk_vio_orig_open_pipe,
417 mawk_vio_orig_exec_shell,
418 1
419 };
420
421
422 void mawk_vio_orig_setup_stdio(mawk_state_t * MAWK, int enable_stdin, int enable_stdout, int enable_stderr)
423 {
424 mawk_vio_orig_t *vf;
425
426 if (enable_stdin) {
427 vf = (mawk_vio_orig_t *)mawk_vio_orig_open(MAWK, "/dev/stdin", MAWK_VIO_I);
428 mawk_file_register(MAWK, "/dev/stdin", F_IN, (mawk_vio_t *)vf);
429 mawk_vio_orig_mark_no_close(MAWK, (mawk_vio_t *)vf);
430 }
431
432 if (enable_stdout) {
433 vf = vio_alloc_(MAWK);
434 vf->f = stdout;
435 mawk_file_register_nofin(MAWK, "/dev/stdout", F_TRUNC, (mawk_vio_t *)vf);
436 mawk_vio_orig_mark_no_close(MAWK, (mawk_vio_t *)vf);
437 /* don't buffer stdout in interactive mode */
438 if (MAWK->interactive_flag)
439 mawk_vio_orig_setbuf(MAWK, (mawk_vio_t *)vf, 0);
440 }
441
442 if (enable_stderr) {
443 vf = vio_alloc_(MAWK);
444 vf->f = stderr;
445 mawk_file_register_nofin(MAWK, "/dev/stderr", F_TRUNC, (mawk_vio_t *)vf);
446 mawk_vio_orig_mark_no_close(MAWK, (mawk_vio_t *)vf);
447 /* never buffer stderr */
448 mawk_vio_orig_setbuf(MAWK, (mawk_vio_t *)vf, 0);
449 }
450 }
0 extern const mawk_vio_imp_t mawk_vio_orig_imp;
1 extern const mawk_vio_init_t mawk_vio_orig_init;
2
3 /* set up /dev/stdin, /dev/stdout and /dev/stderr (depending on which ones
4 are enabled) in the original way (stdin to fd0, stdout and stderr to the
5 FILE * variants*/
6 void mawk_vio_orig_setup_stdio(mawk_state_t * MAWK, int enable_stdin, int enable_stdout, int enable_stderr);
7
8 /* manually enable/disable buffering of a vio_orig */
9 int mawk_vio_orig_setbuf(mawk_state_t *MAWK, mawk_vio_t *vf_, int buf_enable);
0 /********************************************
1 libmawk (C) 2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9
10 #include "mawk.h"
11 #include "field.h"
12
13 extern int isatty(int);
14
15 void mawk_detect_interactive(mawk_state_t *MAWK)
16 {
17 if (isatty(0) && MAWK->rs_shadow.type == SEP_CHAR && MAWK->rs_shadow.c == '\n') {
18 /* interactive line buffered mode */
19 MAWK->interactive_flag = 1;
20 }
21 }
0 /* functions which are somewhat hackish and won't fit in the vio paradigm but
1 are required in the lmawk executable */
2
3 /* check whether we need to be interactive and chaneg the interactive flag
4 accordingly (isatty() and other heuristics) */
5 void mawk_detect_interactive(mawk_state_t *MAWK);
0 /********************************************
1 libmawk (C) 2009-2014, Tibor 'Igor2' Palinkas;
2
3 This is a source file for libmawk, an implementation of
4 the AWK programming language, fork of mawk.
5
6 Libmawk is distributed without warranty under the terms of
7 the GNU General Public License, version 2, 1991.
8 ********************************************/
9
10 #include <string.h>
11 #include "mawk.h"
12 #include "zfifo.h"
13 #include "zmalloc.h"
14
15 mawk_zfifo_t *mawk_zfifo_alloc(mawk_state_t *MAWK, mawk_zfifo_t *sfifo, int max_size)
16 {
17 if (sfifo == NULL) {
18 sfifo = mawk_zmalloc(MAWK, sizeof(mawk_zfifo_t));
19 sfifo->zalloced = 1;
20 }
21 else
22 sfifo->zalloced = 0;
23
24 sfifo->size = 0;
25 sfifo->max_size = max_size;
26 sfifo->stage_used = 0;
27 sfifo->head = NULL;
28 sfifo->tail = NULL;
29 return sfifo;
30 }
31
32 void mawk_zfifo_free(mawk_state_t *MAWK, mawk_zfifo_t *fifo)
33 {
34 mawk_zfifo_block_t *b, *next;
35 for(b = fifo->head; b != NULL; b = next) {
36 next = b->next;
37 mawk_zfree(MAWK, b, sizeof(mawk_zfifo_block_t));
38 }
39 if (fifo->zalloced)
40 mawk_zfree(MAWK, fifo, sizeof(mawk_zfifo_t));
41 }
42
43 int mawk_zfifo_write(mawk_state_t *MAWK, mawk_zfifo_t *fifo, const char *data, int size)
44 {
45 mawk_zfifo_block_t *b;
46
47 /* don't write more than we should */
48 if ((fifo->max_size > 0) && (fifo->size + size > fifo->max_size))
49 return 0;
50
51 /* small write, append to stage buffer */
52 if (fifo->stage_used + size < sizeof(fifo->stage_buf)) {
53 memcpy(fifo->stage_buf + fifo->stage_used, data, size);
54 fifo->stage_used += size;
55 fifo->size += size;
56 return size;
57 }
58
59 /* can't stage, alloc a new block at the end of the list and append
60 the stage _and_ new data there */
61 b = mawk_zmalloc(MAWK, sizeof(mawk_zfifo_block_t) + size + fifo->stage_used);
62 b->size = size + fifo->stage_used;
63 memcpy(b->buf, fifo->stage_buf, fifo->stage_used);
64 memcpy(b->buf + fifo->stage_used, data, size);
65 fifo->stage_used = 0;
66 fifo->size += size;
67 b->next = NULL;
68 b->readp = 0;
69
70 /* append the block to the list */
71 if (fifo->tail == NULL) {
72 fifo->head = b;
73 fifo->tail = b;
74 }
75 else {
76 fifo->tail->next = b;
77 fifo->tail = b;
78 }
79
80 return size;
81 }
82
83 int mawk_zfifo_read(mawk_state_t *MAWK, mawk_zfifo_t *fifo, char *data, int size)
84 {
85 mawk_zfifo_block_t *b, *next;
86 char *end = data;
87 int left = size;
88
89 #define append(from, asize) \
90 do { \
91 int append_asize = asize; \
92 memcpy(end, from, append_asize); \
93 end += append_asize; \
94 left -= append_asize; \
95 fifo->size -= append_asize; \
96 } while(0)
97
98 /* start appending blocks from head */
99 for(b = fifo->head; b != NULL; b = next) {
100 next = b->next;
101 if ((b->size - b->readp) < left) {
102 /* whole block append */
103 append(b->buf + b->readp, b->size - b->readp);
104 mawk_zfree(MAWK, b, sizeof(mawk_zfifo_block_t));
105 fifo->head = next;
106 }
107 else {
108 int old_left;
109 /* partial append */
110 old_left = left;
111 append(b->buf+b->readp, left);
112 b->readp += old_left;
113 break; /* don't even look at further blocks, we are full! */
114 }
115 }
116
117 /* removed all blocks */
118 if (fifo->head == NULL)
119 fifo->tail = NULL;
120
121 /* if there's nothing else left, read from the staging buff */
122 if (fifo->stage_used > 0) {
123 int amount, stage_left;
124
125 /* can we copy the whole buff? */
126 if (fifo->stage_used < left) {
127 amount = fifo->stage_used;
128 stage_left = 0;
129 }
130 else {
131 /* the rare case when the end of a read cuts the staging buff in half */
132 amount = left;
133 stage_left = fifo->stage_used - amount;
134 }
135 append(fifo->stage_buf, amount);
136 if (stage_left > 0)
137 memmove(fifo->stage_buf, fifo->stage_buf + amount, stage_left);
138 fifo->stage_used = stage_left;
139 }
140
141 return end - data;
142 }
143
144
0 #include "mawk.h"
1
2 #define MAWK_ZFIFO_STAGE 64
3
4 /* zmalloc based binary fifo; a linked list of zmalloc'd blocks of writes.
5 Small writes are cached until they reach MAWK_ZFIFO_STAGE to avoid a lot
6 of blocks when writing the fifo char-by-char */
7
8 typedef struct mawk_zfifo_block_s mawk_zfifo_block_t;
9
10 struct mawk_zfifo_block_s {
11 mawk_zfifo_block_t *next; /* next block to jump to when this one is exhausted */
12 int size;
13 int readp; /* next character to read from this buffer */
14 char buf[1]; /* start of the buffer */
15 };
16
17 typedef struct {
18 int size, max_size; /* current and maximum size; max size is in data bytes hold by the buffer, there's an overhead of allocation; max_size = -1 means no limit */
19 char stage_buf[MAWK_ZFIFO_STAGE]; /* staging: buffer small writes to avoid very small zmalloc(); this also assumes read happens in bigger chunks so stage buffer is most likely read at once */
20 int stage_used;
21 mawk_zfifo_block_t *head, *tail; /* singly linked list of blocks with head and tail */
22 int zalloced; /* whether the fifo was zalloc()'d */
23 } mawk_zfifo_t;
24
25 /* set up fifo; if sfifo is NULL, the fifo is zalloc()'d, else all fields
26 are reset */
27 mawk_zfifo_t *mawk_zfifo_alloc(mawk_state_t *MAWK, mawk_zfifo_t *sfifo, int max_size);
28
29 /* discard all data and free the buffer; if it was auto-zalloc()'d
30 in mawk_zfifo_alloc(), fifo is zfree()d here */
31 void mawk_zfifo_free(mawk_state_t *MAWK, mawk_zfifo_t *fifo);
32
33 /* append data to the end of a fifo; return size written
34 (no short write: if max_size prevents the write, no bytes are appended and 0 is returned) */
35 int mawk_zfifo_write(mawk_state_t *MAWK, mawk_zfifo_t *fifo, const char *data, int size);
36
37 /* pop data from the beginning of the fifo; return size read
38 (short read: when there's not enough data in the fifo) */
39 int mawk_zfifo_read(mawk_state_t *MAWK, mawk_zfifo_t *fifo, char *data, int size);
40
0
1 /********************************************
2 zmalloc.c
3
4 libmawk changes (C) 2009-2012, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include "mawk.h"
17 #include "zmalloc.h"
18 #include "memory.h"
19
20 /*
21 mawk_zmalloc() gets mem from malloc() in CHUNKS of 2048 bytes
22 and cuts these blocks into smaller pieces that are multiples
23 of eight bytes. When a piece is returned via mawk_zfree(), it goes
24 on a linked linear list indexed by its size. The lists are
25 an array, pool[].
26
27 E.g., if you ask for 22 bytes with p = mawk_zmalloc(22), you actually get
28 a piece of size 24. When you free it with mawk_zfree(p,22) , it is added
29 to the list at pool[2].
30
31
32 In more details:
33 When a block-allocated area is free'd, put it in pool[blocksize], which
34 is a linked list. When a new reuqest comes in, try to serve it from the
35 pool.
36
37 If that fails: there is a single chunk allocated, called MAWK->avail,
38 with an index (MAWK->amt_avail) pointing to the first unclaimed block; cut
39 down the requested size from there, from the end of the ->avail chunk. If
40 it is impossible (not enough unclaimed blocks at the end), put the unclaimed
41 part of ->avail in the pool and open a new ->avail chunk.
42
43 For corner cases see comments there.
44 */
45
46 #define CHUNK 256
47 /* number of blocks to get from malloc */
48
49 static void out_of_mem(mawk_state_t * MAWK);
50
51
52 static void out_of_mem(mawk_state_t * MAWK)
53 {
54 static const char out[] = "out of memory";
55
56 if (MAWK->mawk_state == EXECUTION)
57 mawk_rt_error(MAWK, out);
58 else {
59 /* I don't think this will ever happen */
60 mawk_compile_error(MAWK, out);
61 mawk_exit(MAWK, 2);
62 }
63 }
64
65 /* mawk_zmalloc() is a macro in front of mawk_bmalloc "BLOCK malloc" */
66 PTR mawk_bmalloc(mawk_state_t *MAWK, register unsigned blocks)
67 {
68 register ZBLOCK *p;
69
70 if (blocks > POOLSZ) {
71 /* larger than pooled allocations */
72 p = (ZBLOCK *) mawk_malloc(MAWK, blocks << ZSHIFT);
73 if (!p)
74 out_of_mem(MAWK);
75 return (PTR) p;
76 }
77
78 if ((p = MAWK->pool[blocks - 1])) {
79 /* remove the first item of the linked list and return it */
80 MAWK->pool[blocks - 1] = p->link;
81 return (PTR) p;
82 }
83
84 if (blocks > MAWK->amt_avail) {
85 if (MAWK->amt_avail != 0) {
86 /* block is bigger than what's available in the last chunk
87 mark the reamining of the last chunk free and put it in the
88 corresponding pool. We can do this because blocks is small
89 enough to be pooled and unclaimed area is even smaller
90 so there is a pool for it for sure. */
91
92 MAWK->avail->link = MAWK->pool[--MAWK->amt_avail];
93 MAWK->pool[MAWK->amt_avail] = MAWK->avail;
94 }
95
96 /* no unclaimed memory is available in the last chunk, alloc a new chunk */
97
98 if ((MAWK->avail = (ZBLOCK *) mawk_malloc(MAWK, CHUNK * ZBLOCKSZ)) == NULL) {
99 /* if we get here, almost out of memory - couldn't allocate a whole
100 new chunk; try to allocate the current request out-of-pool, as the
101 request may be smaller than a chunk
102
103 WARNING: this means pool[] contains not only allocated-in-chunk blocks
104 but plain mallocs as well.
105
106 */
107 MAWK->amt_avail = 0;
108 p = mawk_malloc(MAWK, blocks << ZSHIFT);
109 if (!p)
110 out_of_mem(MAWK);
111 return (PTR) p;
112 }
113 else {
114 /* we have a new chunk to play with */
115 MAWK->amt_avail = CHUNK;
116 }
117 }
118
119 /* get p from the end of the avail chunk - by now we made sure
120 we have enough unclaimed blocks at the end */
121 p = MAWK->avail;
122 MAWK->avail += blocks;
123 MAWK->amt_avail -= blocks;
124 return (PTR) p;
125 }
126
127 void mawk_bfree(mawk_state_t *MAWK, register PTR p, register unsigned blocks)
128 {
129 if (blocks > POOLSZ)
130 mawk_free(MAWK, p);
131 else {
132 ((ZBLOCK *) p)->link = MAWK->pool[--blocks];
133 MAWK->pool[blocks] = (ZBLOCK *) p;
134 }
135 }
136
137 PTR mawk_zrealloc(mawk_state_t *MAWK, register PTR p, unsigned old_size, unsigned new_size)
138 {
139 register PTR q;
140
141 if (new_size > (POOLSZ << ZSHIFT) && old_size > (POOLSZ << ZSHIFT)) {
142 /* was not a pool allocation, just realloc */
143 if (!(q = mawk_realloc(MAWK, p, new_size)))
144 out_of_mem(MAWK);
145 }
146 else {
147 /* pool allocation: zalloc new, zfree old */
148 q = mawk_zmalloc(MAWK, new_size);
149 if (p != NULL) {
150 memcpy(q, p, old_size < new_size ? old_size : new_size);
151 mawk_zfree(MAWK, p, old_size);
152 }
153 }
154 return q;
155 }
156
157 char *mawk_zstrclone(mawk_state_t *MAWK, const char *s)
158 {
159 int l;
160 char *ret;
161
162 if (s == NULL)
163 return NULL;
164
165 l = strlen(s);
166 ret = mawk_zmalloc(MAWK, l+1);
167 memcpy(ret, s, l+1);
168 return ret;
169 }
170
171
172 #ifndef __GNUC__
173 /* pacifier for Bison , this is really dead code */
174 PTR alloca(unsigned sz)
175 {
176 /* hell just froze over */
177 exit(100);
178 return (PTR) 0;
179 }
180 #endif
0
1 /********************************************
2 zmalloc.h
3
4 libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #ifndef ZMALLOC_H
17 #define ZMALLOC_H
18
19 #include <libmawk/nstd.h>
20
21 PTR mawk_bmalloc(mawk_state_t *, unsigned);
22 void mawk_bfree(mawk_state_t *, PTR, unsigned);
23 PTR mawk_zrealloc(mawk_state_t *MAWK, register PTR p, unsigned old_size, unsigned new_size);
24 char *mawk_zstrclone(mawk_state_t *, const char *s);
25
26 #define mawk_zmalloc(MAWK, size) mawk_bmalloc(MAWK, (((unsigned)size)+ZBLOCKSZ-1)>>ZSHIFT)
27 #define mawk_zfree(MAWK, p,size) mawk_bfree(MAWK, p,(((unsigned)size)+ZBLOCKSZ-1)>>ZSHIFT)
28
29 #define MAWK_ZMALLOC(MAWK, type) ((type*)mawk_zmalloc(MAWK, sizeof(type)))
30 #define MAWK_ZFREE(MAWK, p) mawk_zfree(MAWK, p, sizeof(*(p)))
31
32
33 #endif /* ZMALLOC_H */
0
1 /********************************************
2 zmalloc.c
3
4 libmawk changes (C) 2009-2012, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include "mawk.h"
17 #include "zmalloc.h"
18 #include "memory.h"
19 #include "nstd.h"
20
21 /* zmalloc alternative using native malloc/realloc/free */
22
23 static void out_of_mem(mawk_state_t * MAWK)
24 {
25 static const char out[] = "out of memory";
26
27 if (MAWK->mawk_state == EXECUTION)
28 mawk_rt_error(MAWK, out);
29 else {
30 /* I don't think this will ever happen */
31 mawk_compile_error(MAWK, out);
32 mawk_exit(MAWK, 2);
33 }
34 }
35
36 /* mawk_zmalloc() is a macro in front of mawk_bmalloc "BLOCK malloc" */
37 PTR mawk_bmalloc(mawk_state_t *MAWK, register unsigned blocks)
38 {
39 PTR q;
40 q = malloc(blocks << ZSHIFT);
41 if (q == NULL)
42 out_of_mem(MAWK);
43 }
44
45 void mawk_bfree(mawk_state_t *MAWK, register PTR p, register unsigned blocks)
46 {
47 free(p);
48 }
49
50 PTR mawk_zrealloc(mawk_state_t *MAWK, register PTR p, unsigned old_size, unsigned new_size)
51 {
52 PTR q;
53 q = realloc(p, new_size);
54 if (q == NULL)
55 out_of_mem(MAWK);
56 }
57
58 char *mawk_zstrclone(mawk_state_t *MAWK, const char *s)
59 {
60 int l;
61 char *ret;
62
63 if (s == NULL)
64 return NULL;
65
66 l = strlen(s);
67 ret = mawk_zmalloc(MAWK, l+1);
68 memcpy(ret, s, l+1);
69 return ret;
70 }
71
72
73 #ifndef __GNUC__
74 /* pacifier for Bison , this is really dead code */
75 PTR alloca(unsigned sz)
76 {
77 /* hell just froze over */
78 exit(100);
79 return (PTR) 0;
80 }
81 #endif
0
1 /********************************************
2 zmalloc.c
3
4 libmawk changes (C) 2009-2012, Tibor 'Igor2' Palinkas;
5 based on mawk code coming with the below copyright:
6
7 copyright 1991, Michael D. Brennan
8
9 This is a source file for mawk, an implementation of
10 the AWK programming language.
11
12 Mawk is distributed without warranty under the terms of
13 the GNU General Public License, version 2, 1991.
14 ********************************************/
15
16 #include "mawk.h"
17 #include "zmalloc.h"
18 #include "memory.h"
19 #include "nstd.h"
20
21 /* zmalloc alternative using native malloc/realloc/free */
22
23 static void out_of_mem(mawk_state_t * MAWK)
24 {
25 static const char out[] = "out of memory";
26
27 if (MAWK->mawk_state == EXECUTION)
28 mawk_rt_error(MAWK, out);
29 else {
30 /* I don't think this will ever happen */
31 mawk_compile_error(MAWK, out);
32 mawk_exit(MAWK, 2);
33 }
34 }
35
36 /* mawk_zmalloc() is a macro in front of mawk_bmalloc "BLOCK malloc" */
37 PTR mawk_bmalloc(mawk_state_t *MAWK, register unsigned blocks)
38 {
39 PTR q;
40 q = mawk_malloc(MAWK, blocks << ZSHIFT);
41 if (q == NULL)
42 out_of_mem(MAWK);
43 }
44
45 void mawk_bfree(mawk_state_t *MAWK, register PTR p, register unsigned blocks)
46 {
47 mawk_free(MAWK, p);
48 }
49
50 PTR mawk_zrealloc(mawk_state_t *MAWK, register PTR p, unsigned old_size, unsigned new_size)
51 {
52 PTR q;
53 q = mawk_realloc(MAWK, p, new_size);
54 if (q == NULL)
55 out_of_mem(MAWK);
56 }
57
58 char *mawk_zstrclone(mawk_state_t *MAWK, const char *s)
59 {
60 int l;
61 char *ret;
62
63 if (s == NULL)
64 return NULL;
65
66 l = strlen(s);
67 ret = mawk_zmalloc(MAWK, l+1);
68 memcpy(ret, s, l+1);
69 return ret;
70 }
71
72
73 #ifndef __GNUC__
74 /* pacifier for Bison , this is really dead code */
75 PTR alloca(unsigned sz)
76 {
77 /* hell just froze over */
78 exit(100);
79 return (PTR) 0;
80 }
81 #endif
0 #include <libmawk/libmawk.h>
0 #!/bin/sh
1 svn log -r$1:HEAD | grep -v "^\(-*$\|r[0-9]\+\)"
0 #!/bin/sh
1
2 # read the outpot of chlog.sh and split it per topic and save the lines
3 # into changelog-formatted files
4
5 awk '
6 BEGIN {
7 IGNORE["todo"]=1
8 IGNORE["devlog"]=1
9 IGNORE["bugreport"]=1
10 IGNORE["blog_queue"]=1
11 }
12
13 ($1 ~ "^[[][^]]*\]$") {
14 tag=tolower($1)
15 sub("[[]", "", tag)
16 sub("\]", "", tag)
17
18 if (tag in IGNORE)
19 next
20
21 $1=""
22 line=$0
23 if (!(tag in SEEN)) {
24 SEEN[tag]++
25 }
26 print " [" tag "]" line > "CHG." tag
27 next
28 }
29 {
30 line=$0
31 print line > "CHG.MISC"
32 }
33 '
0 #!/bin/sh
1 # copy or link this file in trunk/src
2
3 ctags ../src/libmawk/* > tags
4 grep " v" tags | grep -v "static const" > Global_variables
5
0 #!/bin/sh
1 for n in *.h *.c
2 do
3 sed "/PROTO(/ { s/PROTO(//; s/[,][ ]*[(]/(/; s/);[ ]*$/;/; }" < $n > $n.tmp
4 mv $n.tmp $n
5 done
0 #!/bin/sh
1
2 for n in *.h *.c *.y
3 do
4 case $n in
5 parse.c) ;;
6 mawk.h);;
7 *)
8 mv $n $n.old
9 sed "s/\([^A-Za-z_>]\)$1/\1mawk_$1/g;s/^$1/mawk_$1/" < $n.old > $n
10 rm -f $n.old
11 ;;
12 esac
13 done
0 #!/bin/sh
1 # list public symbols without proper prefix (mawk_) in object files
2 nm $* | grep " T " | grep -v " mawk_"
3
0 #!/bin/sh
1
2 # symbol validation; this script lists globally visible symbols with missing
3 # prefix and persistent states (global vars)
4
5 # ./gloals.sh is in libporty work/c99scripts/globals.sh
6
7 list_macros()
8 {
9 awk -v "fn=$1" '
10 /^[ \t]*#define[ \t]*/ {
11 name=$0
12 sub("^[ \t]*#define[ \t]*", "", name)
13 sub("[ \t(].*", "", name)
14 print "macro", name, "(" fn ":" NR ")"
15 }
16
17 ' < $1
18 }
19
20 (
21 echo ""
22 echo "### missing prefix ###"
23
24 (for n in *.c
25 do
26 echo $n >&2
27 ./globals.sh -g -I../.. -I.. -DLMAWK_VER=\"1\" $n
28 done
29
30 # list macros in the headers
31 for n in *.h
32 do
33 list_macros $n
34 done
35 ) | awk '($2 ~ "^mawk_") || ($2 ~ "^Mawk_") || ($2 ~ "^libmawk_") || /CLASS extern/ || ($2 == "main") { next } { print $0 }'
36
37 echo ""
38 echo "### persistent state ###"
39 for n in *.c
40 do
41 ./globals.sh -s -I../.. -I.. -DLMAWK_VER=\"1\" $n
42 done
43 )
0 #!/bin/sh
1
2 # This file is placed in the Public Domain.
3
4 # Comment all #warnings in a file given as $1.
5 # Useful on systems with CC with no support for #warning.
6
7 sed '
8 /^#[ \t]*warning.*/ {
9 s@^@/*@
10 s@$@*/@
11 }
12 ' < "$1" > "$1.tmp" && mv "$1.tmp" "$1"
0 #!/bin/sh
1
2 # This file is placed in the Public Domain.
3
4 # Comment all #warnings in all .h and .c files, recursively.
5 # Useful on systems with CC with no support for #warning.
6
7 action=`echo "$0" | sed "s/_all//"`
8
9 find . -name '*.[ch]' -exec $action {} \;