Magellan Linux

Contents of /tags/mkinitrd-6_1_11/busybox/editors/awk.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 928 - (show annotations) (download)
Wed Oct 28 13:31:19 2009 UTC (14 years, 7 months ago) by niro
File MIME type: text/plain
File size: 64854 byte(s)
tagged 'mkinitrd-6_1_11'
1 /* vi: set sw=4 ts=4: */
2 /*
3 * awk implementation for busybox
4 *
5 * Copyright (C) 2002 by Dmitry Zakharov <dmit@crp.bank.gov.ua>
6 *
7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8 */
9
10 #include "libbb.h"
11 #include "xregex.h"
12 #include <math.h>
13
14 /* This is a NOEXEC applet. Be very careful! */
15
16
17 #define MAXVARFMT 240
18 #define MINNVBLOCK 64
19
20 /* variable flags */
21 #define VF_NUMBER 0x0001 /* 1 = primary type is number */
22 #define VF_ARRAY 0x0002 /* 1 = it's an array */
23
24 #define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
25 #define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
26 #define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
27 #define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
28 #define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
29 #define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
30 #define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
31
32 /* these flags are static, don't change them when value is changed */
33 #define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
34
35 /* Variable */
36 typedef struct var_s {
37 unsigned type; /* flags */
38 double number;
39 char *string;
40 union {
41 int aidx; /* func arg idx (for compilation stage) */
42 struct xhash_s *array; /* array ptr */
43 struct var_s *parent; /* for func args, ptr to actual parameter */
44 char **walker; /* list of array elements (for..in) */
45 } x;
46 } var;
47
48 /* Node chain (pattern-action chain, BEGIN, END, function bodies) */
49 typedef struct chain_s {
50 struct node_s *first;
51 struct node_s *last;
52 const char *programname;
53 } chain;
54
55 /* Function */
56 typedef struct func_s {
57 unsigned nargs;
58 struct chain_s body;
59 } func;
60
61 /* I/O stream */
62 typedef struct rstream_s {
63 FILE *F;
64 char *buffer;
65 int adv;
66 int size;
67 int pos;
68 smallint is_pipe;
69 } rstream;
70
71 typedef struct hash_item_s {
72 union {
73 struct var_s v; /* variable/array hash */
74 struct rstream_s rs; /* redirect streams hash */
75 struct func_s f; /* functions hash */
76 } data;
77 struct hash_item_s *next; /* next in chain */
78 char name[1]; /* really it's longer */
79 } hash_item;
80
81 typedef struct xhash_s {
82 unsigned nel; /* num of elements */
83 unsigned csize; /* current hash size */
84 unsigned nprime; /* next hash size in PRIMES[] */
85 unsigned glen; /* summary length of item names */
86 struct hash_item_s **items;
87 } xhash;
88
89 /* Tree node */
90 typedef struct node_s {
91 uint32_t info;
92 unsigned lineno;
93 union {
94 struct node_s *n;
95 var *v;
96 int i;
97 char *s;
98 regex_t *re;
99 } l;
100 union {
101 struct node_s *n;
102 regex_t *ire;
103 func *f;
104 int argno;
105 } r;
106 union {
107 struct node_s *n;
108 } a;
109 } node;
110
111 /* Block of temporary variables */
112 typedef struct nvblock_s {
113 int size;
114 var *pos;
115 struct nvblock_s *prev;
116 struct nvblock_s *next;
117 var nv[0];
118 } nvblock;
119
120 typedef struct tsplitter_s {
121 node n;
122 regex_t re[2];
123 } tsplitter;
124
125 /* simple token classes */
126 /* Order and hex values are very important!!! See next_token() */
127 #define TC_SEQSTART 1 /* ( */
128 #define TC_SEQTERM (1 << 1) /* ) */
129 #define TC_REGEXP (1 << 2) /* /.../ */
130 #define TC_OUTRDR (1 << 3) /* | > >> */
131 #define TC_UOPPOST (1 << 4) /* unary postfix operator */
132 #define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
133 #define TC_BINOPX (1 << 6) /* two-opnd operator */
134 #define TC_IN (1 << 7)
135 #define TC_COMMA (1 << 8)
136 #define TC_PIPE (1 << 9) /* input redirection pipe */
137 #define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
138 #define TC_ARRTERM (1 << 11) /* ] */
139 #define TC_GRPSTART (1 << 12) /* { */
140 #define TC_GRPTERM (1 << 13) /* } */
141 #define TC_SEMICOL (1 << 14)
142 #define TC_NEWLINE (1 << 15)
143 #define TC_STATX (1 << 16) /* ctl statement (for, next...) */
144 #define TC_WHILE (1 << 17)
145 #define TC_ELSE (1 << 18)
146 #define TC_BUILTIN (1 << 19)
147 #define TC_GETLINE (1 << 20)
148 #define TC_FUNCDECL (1 << 21) /* `function' `func' */
149 #define TC_BEGIN (1 << 22)
150 #define TC_END (1 << 23)
151 #define TC_EOF (1 << 24)
152 #define TC_VARIABLE (1 << 25)
153 #define TC_ARRAY (1 << 26)
154 #define TC_FUNCTION (1 << 27)
155 #define TC_STRING (1 << 28)
156 #define TC_NUMBER (1 << 29)
157
158 #define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
159
160 /* combined token classes */
161 #define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
162 #define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
163 #define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
164 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
165
166 #define TC_STATEMNT (TC_STATX | TC_WHILE)
167 #define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
168
169 /* word tokens, cannot mean something else if not expected */
170 #define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
171 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
172
173 /* discard newlines after these */
174 #define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
175 | TC_BINOP | TC_OPTERM)
176
177 /* what can expression begin with */
178 #define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
179 /* what can group begin with */
180 #define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
181
182 /* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
183 /* operator is inserted between them */
184 #define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
185 | TC_STRING | TC_NUMBER | TC_UOPPOST)
186 #define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
187
188 #define OF_RES1 0x010000
189 #define OF_RES2 0x020000
190 #define OF_STR1 0x040000
191 #define OF_STR2 0x080000
192 #define OF_NUM1 0x100000
193 #define OF_CHECKED 0x200000
194
195 /* combined operator flags */
196 #define xx 0
197 #define xV OF_RES2
198 #define xS (OF_RES2 | OF_STR2)
199 #define Vx OF_RES1
200 #define VV (OF_RES1 | OF_RES2)
201 #define Nx (OF_RES1 | OF_NUM1)
202 #define NV (OF_RES1 | OF_NUM1 | OF_RES2)
203 #define Sx (OF_RES1 | OF_STR1)
204 #define SV (OF_RES1 | OF_STR1 | OF_RES2)
205 #define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
206
207 #define OPCLSMASK 0xFF00
208 #define OPNMASK 0x007F
209
210 /* operator priority is a highest byte (even: r->l, odd: l->r grouping)
211 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
212 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
213 */
214 #define P(x) (x << 24)
215 #define PRIMASK 0x7F000000
216 #define PRIMASK2 0x7E000000
217
218 /* Operation classes */
219
220 #define SHIFT_TIL_THIS 0x0600
221 #define RECUR_FROM_THIS 0x1000
222
223 enum {
224 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
225 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
226
227 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
228 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
229 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
230
231 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
232 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
233 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
234 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
235 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
236 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
237 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
238 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
239 OC_DONE = 0x2800,
240
241 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
242 ST_WHILE = 0x3300
243 };
244
245 /* simple builtins */
246 enum {
247 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
248 F_ti, F_le, F_sy, F_ff, F_cl
249 };
250
251 /* builtins */
252 enum {
253 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up,
254 B_ge, B_gs, B_su,
255 B_an, B_co, B_ls, B_or, B_rs, B_xo,
256 };
257
258 /* tokens and their corresponding info values */
259
260 #define NTC "\377" /* switch to next token class (tc<<1) */
261 #define NTCC '\377'
262
263 #define OC_B OC_BUILTIN
264
265 static const char tokenlist[] ALIGN1 =
266 "\1(" NTC
267 "\1)" NTC
268 "\1/" NTC /* REGEXP */
269 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
270 "\2++" "\2--" NTC /* UOPPOST */
271 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
272 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
273 "\2*=" "\2/=" "\2%=" "\2^="
274 "\1+" "\1-" "\3**=" "\2**"
275 "\1/" "\1%" "\1^" "\1*"
276 "\2!=" "\2>=" "\2<=" "\1>"
277 "\1<" "\2!~" "\1~" "\2&&"
278 "\2||" "\1?" "\1:" NTC
279 "\2in" NTC
280 "\1," NTC
281 "\1|" NTC
282 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
283 "\1]" NTC
284 "\1{" NTC
285 "\1}" NTC
286 "\1;" NTC
287 "\1\n" NTC
288 "\2if" "\2do" "\3for" "\5break" /* STATX */
289 "\10continue" "\6delete" "\5print"
290 "\6printf" "\4next" "\10nextfile"
291 "\6return" "\4exit" NTC
292 "\5while" NTC
293 "\4else" NTC
294
295 "\3and" "\5compl" "\6lshift" "\2or"
296 "\6rshift" "\3xor"
297 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
298 "\3cos" "\3exp" "\3int" "\3log"
299 "\4rand" "\3sin" "\4sqrt" "\5srand"
300 "\6gensub" "\4gsub" "\5index" "\6length"
301 "\5match" "\5split" "\7sprintf" "\3sub"
302 "\6substr" "\7systime" "\10strftime"
303 "\7tolower" "\7toupper" NTC
304 "\7getline" NTC
305 "\4func" "\10function" NTC
306 "\5BEGIN" NTC
307 "\3END" "\0"
308 ;
309
310 static const uint32_t tokeninfo[] = {
311 0,
312 0,
313 OC_REGEXP,
314 xS|'a', xS|'w', xS|'|',
315 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
316 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M',
317 OC_FIELD|xV|P(5),
318 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74),
319 OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
320 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/',
321 OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
322 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-',
323 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
324 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%',
325 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
326 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
327 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
328 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
329 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
330 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
331 OC_COLON|xx|P(67)|':',
332 OC_IN|SV|P(49),
333 OC_COMMA|SS|P(80),
334 OC_PGETLINE|SV|P(37),
335 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',
336 OC_UNARY|xV|P(19)|'!',
337 0,
338 0,
339 0,
340 0,
341 0,
342 ST_IF, ST_DO, ST_FOR, OC_BREAK,
343 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
344 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
345 OC_RETURN|Vx, OC_EXIT|Nx,
346 ST_WHILE,
347 0,
348
349 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
350 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
351 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
352 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
353 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
354 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
355 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
356 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b),
357 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
358 OC_GETLINE|SV|P(0),
359 0, 0,
360 0,
361 0
362 };
363
364 /* internal variable names and their initial values */
365 /* asterisk marks SPECIAL vars; $ is just no-named Field0 */
366 enum {
367 CONVFMT, OFMT, FS, OFS,
368 ORS, RS, RT, FILENAME,
369 SUBSEP, ARGIND, ARGC, ARGV,
370 ERRNO, FNR,
371 NR, NF, IGNORECASE,
372 ENVIRON, F0, NUM_INTERNAL_VARS
373 };
374
375 static const char vNames[] ALIGN1 =
376 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
377 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
378 "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0"
379 "ERRNO\0" "FNR\0"
380 "NR\0" "NF\0*" "IGNORECASE\0*"
381 "ENVIRON\0" "$\0*" "\0";
382
383 static const char vValues[] ALIGN1 =
384 "%.6g\0" "%.6g\0" " \0" " \0"
385 "\n\0" "\n\0" "\0" "\0"
386 "\034\0"
387 "\377";
388
389 /* hash size may grow to these values */
390 #define FIRST_PRIME 61
391 static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
392
393
394 /* Globals. Split in two parts so that first one is addressed
395 * with (mostly short) negative offsets.
396 * NB: it's unsafe to put members of type "double"
397 * into globals2 (gcc may fail to align them).
398 */
399 struct globals {
400 double t_double;
401 chain beginseq, mainseq, endseq;
402 chain *seq;
403 node *break_ptr, *continue_ptr;
404 rstream *iF;
405 xhash *vhash, *ahash, *fdhash, *fnhash;
406 const char *g_progname;
407 int g_lineno;
408 int nfields;
409 int maxfields; /* used in fsrealloc() only */
410 var *Fields;
411 nvblock *g_cb;
412 char *g_pos;
413 char *g_buf;
414 smallint icase;
415 smallint exiting;
416 smallint nextrec;
417 smallint nextfile;
418 smallint is_f0_split;
419 };
420 struct globals2 {
421 uint32_t t_info; /* often used */
422 uint32_t t_tclass;
423 char *t_string;
424 int t_lineno;
425 int t_rollback;
426
427 var *intvar[NUM_INTERNAL_VARS]; /* often used */
428
429 /* former statics from various functions */
430 char *split_f0__fstrings;
431
432 uint32_t next_token__save_tclass;
433 uint32_t next_token__save_info;
434 uint32_t next_token__ltclass;
435 smallint next_token__concat_inserted;
436
437 smallint next_input_file__files_happen;
438 rstream next_input_file__rsm;
439
440 var *evaluate__fnargs;
441 unsigned evaluate__seed;
442 regex_t evaluate__sreg;
443
444 var ptest__v;
445
446 tsplitter exec_builtin__tspl;
447
448 /* biggest and least used members go last */
449 tsplitter fsplitter, rsplitter;
450 };
451 #define G1 (ptr_to_globals[-1])
452 #define G (*(struct globals2 *)ptr_to_globals)
453 /* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
454 /*char G1size[sizeof(G1)]; - 0x74 */
455 /*char Gsize[sizeof(G)]; - 0x1c4 */
456 /* Trying to keep most of members accessible with short offsets: */
457 /*char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
458 #define t_double (G1.t_double )
459 #define beginseq (G1.beginseq )
460 #define mainseq (G1.mainseq )
461 #define endseq (G1.endseq )
462 #define seq (G1.seq )
463 #define break_ptr (G1.break_ptr )
464 #define continue_ptr (G1.continue_ptr)
465 #define iF (G1.iF )
466 #define vhash (G1.vhash )
467 #define ahash (G1.ahash )
468 #define fdhash (G1.fdhash )
469 #define fnhash (G1.fnhash )
470 #define g_progname (G1.g_progname )
471 #define g_lineno (G1.g_lineno )
472 #define nfields (G1.nfields )
473 #define maxfields (G1.maxfields )
474 #define Fields (G1.Fields )
475 #define g_cb (G1.g_cb )
476 #define g_pos (G1.g_pos )
477 #define g_buf (G1.g_buf )
478 #define icase (G1.icase )
479 #define exiting (G1.exiting )
480 #define nextrec (G1.nextrec )
481 #define nextfile (G1.nextfile )
482 #define is_f0_split (G1.is_f0_split )
483 #define t_info (G.t_info )
484 #define t_tclass (G.t_tclass )
485 #define t_string (G.t_string )
486 #define t_lineno (G.t_lineno )
487 #define t_rollback (G.t_rollback )
488 #define intvar (G.intvar )
489 #define fsplitter (G.fsplitter )
490 #define rsplitter (G.rsplitter )
491 #define INIT_G() do { \
492 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1)); \
493 G.next_token__ltclass = TC_OPTERM; \
494 G.evaluate__seed = 1; \
495 } while (0)
496
497
498 /* function prototypes */
499 static void handle_special(var *);
500 static node *parse_expr(uint32_t);
501 static void chain_group(void);
502 static var *evaluate(node *, var *);
503 static rstream *next_input_file(void);
504 static int fmt_num(char *, int, const char *, double, int);
505 static int awk_exit(int) NORETURN;
506
507 /* ---- error handling ---- */
508
509 static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
510 static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
511 static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
512 static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
513 static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
514 static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
515 static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
516 static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
517 static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
518 #if !ENABLE_FEATURE_AWK_LIBM
519 static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
520 #endif
521
522 static void zero_out_var(var * vp)
523 {
524 memset(vp, 0, sizeof(*vp));
525 }
526
527 static void syntax_error(const char *const message) NORETURN;
528 static void syntax_error(const char *const message)
529 {
530 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
531 }
532
533 /* ---- hash stuff ---- */
534
535 static unsigned hashidx(const char *name)
536 {
537 unsigned idx = 0;
538
539 while (*name) idx = *name++ + (idx << 6) - idx;
540 return idx;
541 }
542
543 /* create new hash */
544 static xhash *hash_init(void)
545 {
546 xhash *newhash;
547
548 newhash = xzalloc(sizeof(xhash));
549 newhash->csize = FIRST_PRIME;
550 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
551
552 return newhash;
553 }
554
555 /* find item in hash, return ptr to data, NULL if not found */
556 static void *hash_search(xhash *hash, const char *name)
557 {
558 hash_item *hi;
559
560 hi = hash->items [ hashidx(name) % hash->csize ];
561 while (hi) {
562 if (strcmp(hi->name, name) == 0)
563 return &(hi->data);
564 hi = hi->next;
565 }
566 return NULL;
567 }
568
569 /* grow hash if it becomes too big */
570 static void hash_rebuild(xhash *hash)
571 {
572 unsigned newsize, i, idx;
573 hash_item **newitems, *hi, *thi;
574
575 if (hash->nprime == ARRAY_SIZE(PRIMES))
576 return;
577
578 newsize = PRIMES[hash->nprime++];
579 newitems = xzalloc(newsize * sizeof(hash_item *));
580
581 for (i = 0; i < hash->csize; i++) {
582 hi = hash->items[i];
583 while (hi) {
584 thi = hi;
585 hi = thi->next;
586 idx = hashidx(thi->name) % newsize;
587 thi->next = newitems[idx];
588 newitems[idx] = thi;
589 }
590 }
591
592 free(hash->items);
593 hash->csize = newsize;
594 hash->items = newitems;
595 }
596
597 /* find item in hash, add it if necessary. Return ptr to data */
598 static void *hash_find(xhash *hash, const char *name)
599 {
600 hash_item *hi;
601 unsigned idx;
602 int l;
603
604 hi = hash_search(hash, name);
605 if (!hi) {
606 if (++hash->nel / hash->csize > 10)
607 hash_rebuild(hash);
608
609 l = strlen(name) + 1;
610 hi = xzalloc(sizeof(hash_item) + l);
611 memcpy(hi->name, name, l);
612
613 idx = hashidx(name) % hash->csize;
614 hi->next = hash->items[idx];
615 hash->items[idx] = hi;
616 hash->glen += l;
617 }
618 return &(hi->data);
619 }
620
621 #define findvar(hash, name) ((var*) hash_find((hash), (name)))
622 #define newvar(name) ((var*) hash_find(vhash, (name)))
623 #define newfile(name) ((rstream*)hash_find(fdhash, (name)))
624 #define newfunc(name) ((func*) hash_find(fnhash, (name)))
625
626 static void hash_remove(xhash *hash, const char *name)
627 {
628 hash_item *hi, **phi;
629
630 phi = &(hash->items[hashidx(name) % hash->csize]);
631 while (*phi) {
632 hi = *phi;
633 if (strcmp(hi->name, name) == 0) {
634 hash->glen -= (strlen(name) + 1);
635 hash->nel--;
636 *phi = hi->next;
637 free(hi);
638 break;
639 }
640 phi = &(hi->next);
641 }
642 }
643
644 /* ------ some useful functions ------ */
645
646 static void skip_spaces(char **s)
647 {
648 char *p = *s;
649
650 while (1) {
651 if (*p == '\\' && p[1] == '\n') {
652 p++;
653 t_lineno++;
654 } else if (*p != ' ' && *p != '\t') {
655 break;
656 }
657 p++;
658 }
659 *s = p;
660 }
661
662 static char *nextword(char **s)
663 {
664 char *p = *s;
665
666 while (*(*s)++) /* */;
667
668 return p;
669 }
670
671 static char nextchar(char **s)
672 {
673 char c, *pps;
674
675 c = *((*s)++);
676 pps = *s;
677 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
678 if (c == '\\' && *s == pps) c = *((*s)++);
679 return c;
680 }
681
682 static ALWAYS_INLINE int isalnum_(int c)
683 {
684 return (isalnum(c) || c == '_');
685 }
686
687 static double my_strtod(char **pp)
688 {
689 #if ENABLE_DESKTOP
690 if ((*pp)[0] == '0'
691 && ((((*pp)[1] | 0x20) == 'x') || isdigit((*pp)[1]))
692 ) {
693 return strtoull(*pp, pp, 0);
694 }
695 #endif
696 return strtod(*pp, pp);
697 }
698
699 /* -------- working with variables (set/get/copy/etc) -------- */
700
701 static xhash *iamarray(var *v)
702 {
703 var *a = v;
704
705 while (a->type & VF_CHILD)
706 a = a->x.parent;
707
708 if (!(a->type & VF_ARRAY)) {
709 a->type |= VF_ARRAY;
710 a->x.array = hash_init();
711 }
712 return a->x.array;
713 }
714
715 static void clear_array(xhash *array)
716 {
717 unsigned i;
718 hash_item *hi, *thi;
719
720 for (i = 0; i < array->csize; i++) {
721 hi = array->items[i];
722 while (hi) {
723 thi = hi;
724 hi = hi->next;
725 free(thi->data.v.string);
726 free(thi);
727 }
728 array->items[i] = NULL;
729 }
730 array->glen = array->nel = 0;
731 }
732
733 /* clear a variable */
734 static var *clrvar(var *v)
735 {
736 if (!(v->type & VF_FSTR))
737 free(v->string);
738
739 v->type &= VF_DONTTOUCH;
740 v->type |= VF_DIRTY;
741 v->string = NULL;
742 return v;
743 }
744
745 /* assign string value to variable */
746 static var *setvar_p(var *v, char *value)
747 {
748 clrvar(v);
749 v->string = value;
750 handle_special(v);
751 return v;
752 }
753
754 /* same as setvar_p but make a copy of string */
755 static var *setvar_s(var *v, const char *value)
756 {
757 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
758 }
759
760 /* same as setvar_s but set USER flag */
761 static var *setvar_u(var *v, const char *value)
762 {
763 setvar_s(v, value);
764 v->type |= VF_USER;
765 return v;
766 }
767
768 /* set array element to user string */
769 static void setari_u(var *a, int idx, const char *s)
770 {
771 char sidx[sizeof(int)*3 + 1];
772 var *v;
773
774 sprintf(sidx, "%d", idx);
775 v = findvar(iamarray(a), sidx);
776 setvar_u(v, s);
777 }
778
779 /* assign numeric value to variable */
780 static var *setvar_i(var *v, double value)
781 {
782 clrvar(v);
783 v->type |= VF_NUMBER;
784 v->number = value;
785 handle_special(v);
786 return v;
787 }
788
789 static const char *getvar_s(var *v)
790 {
791 /* if v is numeric and has no cached string, convert it to string */
792 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
793 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
794 v->string = xstrdup(g_buf);
795 v->type |= VF_CACHED;
796 }
797 return (v->string == NULL) ? "" : v->string;
798 }
799
800 static double getvar_i(var *v)
801 {
802 char *s;
803
804 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
805 v->number = 0;
806 s = v->string;
807 if (s && *s) {
808 v->number = my_strtod(&s);
809 if (v->type & VF_USER) {
810 skip_spaces(&s);
811 if (*s != '\0')
812 v->type &= ~VF_USER;
813 }
814 } else {
815 v->type &= ~VF_USER;
816 }
817 v->type |= VF_CACHED;
818 }
819 return v->number;
820 }
821
822 /* Used for operands of bitwise ops */
823 static unsigned long getvar_i_int(var *v)
824 {
825 double d = getvar_i(v);
826
827 /* Casting doubles to longs is undefined for values outside
828 * of target type range. Try to widen it as much as possible */
829 if (d >= 0)
830 return (unsigned long)d;
831 /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */
832 return - (long) (unsigned long) (-d);
833 }
834
835 static var *copyvar(var *dest, const var *src)
836 {
837 if (dest != src) {
838 clrvar(dest);
839 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
840 dest->number = src->number;
841 if (src->string)
842 dest->string = xstrdup(src->string);
843 }
844 handle_special(dest);
845 return dest;
846 }
847
848 static var *incvar(var *v)
849 {
850 return setvar_i(v, getvar_i(v) + 1.);
851 }
852
853 /* return true if v is number or numeric string */
854 static int is_numeric(var *v)
855 {
856 getvar_i(v);
857 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
858 }
859
860 /* return 1 when value of v corresponds to true, 0 otherwise */
861 static int istrue(var *v)
862 {
863 if (is_numeric(v))
864 return (v->number == 0) ? 0 : 1;
865 return (v->string && *(v->string)) ? 1 : 0;
866 }
867
868 /* temporary variables allocator. Last allocated should be first freed */
869 static var *nvalloc(int n)
870 {
871 nvblock *pb = NULL;
872 var *v, *r;
873 int size;
874
875 while (g_cb) {
876 pb = g_cb;
877 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break;
878 g_cb = g_cb->next;
879 }
880
881 if (!g_cb) {
882 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
883 g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var));
884 g_cb->size = size;
885 g_cb->pos = g_cb->nv;
886 g_cb->prev = pb;
887 /*g_cb->next = NULL; - xzalloc did it */
888 if (pb) pb->next = g_cb;
889 }
890
891 v = r = g_cb->pos;
892 g_cb->pos += n;
893
894 while (v < g_cb->pos) {
895 v->type = 0;
896 v->string = NULL;
897 v++;
898 }
899
900 return r;
901 }
902
903 static void nvfree(var *v)
904 {
905 var *p;
906
907 if (v < g_cb->nv || v >= g_cb->pos)
908 syntax_error(EMSG_INTERNAL_ERROR);
909
910 for (p = v; p < g_cb->pos; p++) {
911 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
912 clear_array(iamarray(p));
913 free(p->x.array->items);
914 free(p->x.array);
915 }
916 if (p->type & VF_WALK)
917 free(p->x.walker);
918
919 clrvar(p);
920 }
921
922 g_cb->pos = v;
923 while (g_cb->prev && g_cb->pos == g_cb->nv) {
924 g_cb = g_cb->prev;
925 }
926 }
927
928 /* ------- awk program text parsing ------- */
929
930 /* Parse next token pointed by global pos, place results into global ttt.
931 * If token isn't expected, give away. Return token class
932 */
933 static uint32_t next_token(uint32_t expected)
934 {
935 #define concat_inserted (G.next_token__concat_inserted)
936 #define save_tclass (G.next_token__save_tclass)
937 #define save_info (G.next_token__save_info)
938 /* Initialized to TC_OPTERM: */
939 #define ltclass (G.next_token__ltclass)
940
941 char *p, *pp, *s;
942 const char *tl;
943 uint32_t tc;
944 const uint32_t *ti;
945 int l;
946
947 if (t_rollback) {
948 t_rollback = FALSE;
949
950 } else if (concat_inserted) {
951 concat_inserted = FALSE;
952 t_tclass = save_tclass;
953 t_info = save_info;
954
955 } else {
956 p = g_pos;
957 readnext:
958 skip_spaces(&p);
959 g_lineno = t_lineno;
960 if (*p == '#')
961 while (*p != '\n' && *p != '\0')
962 p++;
963
964 if (*p == '\n')
965 t_lineno++;
966
967 if (*p == '\0') {
968 tc = TC_EOF;
969
970 } else if (*p == '\"') {
971 /* it's a string */
972 t_string = s = ++p;
973 while (*p != '\"') {
974 if (*p == '\0' || *p == '\n')
975 syntax_error(EMSG_UNEXP_EOS);
976 *(s++) = nextchar(&p);
977 }
978 p++;
979 *s = '\0';
980 tc = TC_STRING;
981
982 } else if ((expected & TC_REGEXP) && *p == '/') {
983 /* it's regexp */
984 t_string = s = ++p;
985 while (*p != '/') {
986 if (*p == '\0' || *p == '\n')
987 syntax_error(EMSG_UNEXP_EOS);
988 *s = *p++;
989 if (*s++ == '\\') {
990 pp = p;
991 *(s-1) = bb_process_escape_sequence((const char **)&p);
992 if (*pp == '\\')
993 *s++ = '\\';
994 if (p == pp)
995 *s++ = *p++;
996 }
997 }
998 p++;
999 *s = '\0';
1000 tc = TC_REGEXP;
1001
1002 } else if (*p == '.' || isdigit(*p)) {
1003 /* it's a number */
1004 t_double = my_strtod(&p);
1005 if (*p == '.')
1006 syntax_error(EMSG_UNEXP_TOKEN);
1007 tc = TC_NUMBER;
1008
1009 } else {
1010 /* search for something known */
1011 tl = tokenlist;
1012 tc = 0x00000001;
1013 ti = tokeninfo;
1014 while (*tl) {
1015 l = *(tl++);
1016 if (l == NTCC) {
1017 tc <<= 1;
1018 continue;
1019 }
1020 /* if token class is expected, token
1021 * matches and it's not a longer word,
1022 * then this is what we are looking for
1023 */
1024 if ((tc & (expected | TC_WORD | TC_NEWLINE))
1025 && *tl == *p && strncmp(p, tl, l) == 0
1026 && !((tc & TC_WORD) && isalnum_(p[l]))
1027 ) {
1028 t_info = *ti;
1029 p += l;
1030 break;
1031 }
1032 ti++;
1033 tl += l;
1034 }
1035
1036 if (!*tl) {
1037 /* it's a name (var/array/function),
1038 * otherwise it's something wrong
1039 */
1040 if (!isalnum_(*p))
1041 syntax_error(EMSG_UNEXP_TOKEN);
1042
1043 t_string = --p;
1044 while (isalnum_(*(++p))) {
1045 *(p-1) = *p;
1046 }
1047 *(p-1) = '\0';
1048 tc = TC_VARIABLE;
1049 /* also consume whitespace between functionname and bracket */
1050 if (!(expected & TC_VARIABLE))
1051 skip_spaces(&p);
1052 if (*p == '(') {
1053 tc = TC_FUNCTION;
1054 } else {
1055 if (*p == '[') {
1056 p++;
1057 tc = TC_ARRAY;
1058 }
1059 }
1060 }
1061 }
1062 g_pos = p;
1063
1064 /* skipping newlines in some cases */
1065 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1066 goto readnext;
1067
1068 /* insert concatenation operator when needed */
1069 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
1070 concat_inserted = TRUE;
1071 save_tclass = tc;
1072 save_info = t_info;
1073 tc = TC_BINOP;
1074 t_info = OC_CONCAT | SS | P(35);
1075 }
1076
1077 t_tclass = tc;
1078 }
1079 ltclass = t_tclass;
1080
1081 /* Are we ready for this? */
1082 if (!(ltclass & expected))
1083 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
1084 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
1085
1086 return ltclass;
1087 #undef concat_inserted
1088 #undef save_tclass
1089 #undef save_info
1090 #undef ltclass
1091 }
1092
1093 static void rollback_token(void)
1094 {
1095 t_rollback = TRUE;
1096 }
1097
1098 static node *new_node(uint32_t info)
1099 {
1100 node *n;
1101
1102 n = xzalloc(sizeof(node));
1103 n->info = info;
1104 n->lineno = g_lineno;
1105 return n;
1106 }
1107
1108 static node *mk_re_node(const char *s, node *n, regex_t *re)
1109 {
1110 n->info = OC_REGEXP;
1111 n->l.re = re;
1112 n->r.ire = re + 1;
1113 xregcomp(re, s, REG_EXTENDED);
1114 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
1115
1116 return n;
1117 }
1118
1119 static node *condition(void)
1120 {
1121 next_token(TC_SEQSTART);
1122 return parse_expr(TC_SEQTERM);
1123 }
1124
1125 /* parse expression terminated by given argument, return ptr
1126 * to built subtree. Terminator is eaten by parse_expr */
1127 static node *parse_expr(uint32_t iexp)
1128 {
1129 node sn;
1130 node *cn = &sn;
1131 node *vn, *glptr;
1132 uint32_t tc, xtc;
1133 var *v;
1134
1135 sn.info = PRIMASK;
1136 sn.r.n = glptr = NULL;
1137 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1138
1139 while (!((tc = next_token(xtc)) & iexp)) {
1140 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
1141 /* input redirection (<) attached to glptr node */
1142 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
1143 cn->a.n = glptr;
1144 xtc = TC_OPERAND | TC_UOPPRE;
1145 glptr = NULL;
1146
1147 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1148 /* for binary and postfix-unary operators, jump back over
1149 * previous operators with higher priority */
1150 vn = cn;
1151 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1152 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) )
1153 vn = vn->a.n;
1154 if ((t_info & OPCLSMASK) == OC_TERNARY)
1155 t_info += P(6);
1156 cn = vn->a.n->r.n = new_node(t_info);
1157 cn->a.n = vn->a.n;
1158 if (tc & TC_BINOP) {
1159 cn->l.n = vn;
1160 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1161 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
1162 /* it's a pipe */
1163 next_token(TC_GETLINE);
1164 /* give maximum priority to this pipe */
1165 cn->info &= ~PRIMASK;
1166 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1167 }
1168 } else {
1169 cn->r.n = vn;
1170 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1171 }
1172 vn->a.n = cn;
1173
1174 } else {
1175 /* for operands and prefix-unary operators, attach them
1176 * to last node */
1177 vn = cn;
1178 cn = vn->r.n = new_node(t_info);
1179 cn->a.n = vn;
1180 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1181 if (tc & (TC_OPERAND | TC_REGEXP)) {
1182 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
1183 /* one should be very careful with switch on tclass -
1184 * only simple tclasses should be used! */
1185 switch (tc) {
1186 case TC_VARIABLE:
1187 case TC_ARRAY:
1188 cn->info = OC_VAR;
1189 v = hash_search(ahash, t_string);
1190 if (v != NULL) {
1191 cn->info = OC_FNARG;
1192 cn->l.i = v->x.aidx;
1193 } else {
1194 cn->l.v = newvar(t_string);
1195 }
1196 if (tc & TC_ARRAY) {
1197 cn->info |= xS;
1198 cn->r.n = parse_expr(TC_ARRTERM);
1199 }
1200 break;
1201
1202 case TC_NUMBER:
1203 case TC_STRING:
1204 cn->info = OC_VAR;
1205 v = cn->l.v = xzalloc(sizeof(var));
1206 if (tc & TC_NUMBER)
1207 setvar_i(v, t_double);
1208 else
1209 setvar_s(v, t_string);
1210 break;
1211
1212 case TC_REGEXP:
1213 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
1214 break;
1215
1216 case TC_FUNCTION:
1217 cn->info = OC_FUNC;
1218 cn->r.f = newfunc(t_string);
1219 cn->l.n = condition();
1220 break;
1221
1222 case TC_SEQSTART:
1223 cn = vn->r.n = parse_expr(TC_SEQTERM);
1224 cn->a.n = vn;
1225 break;
1226
1227 case TC_GETLINE:
1228 glptr = cn;
1229 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1230 break;
1231
1232 case TC_BUILTIN:
1233 cn->l.n = condition();
1234 break;
1235 }
1236 }
1237 }
1238 }
1239 return sn.r.n;
1240 }
1241
1242 /* add node to chain. Return ptr to alloc'd node */
1243 static node *chain_node(uint32_t info)
1244 {
1245 node *n;
1246
1247 if (!seq->first)
1248 seq->first = seq->last = new_node(0);
1249
1250 if (seq->programname != g_progname) {
1251 seq->programname = g_progname;
1252 n = chain_node(OC_NEWSOURCE);
1253 n->l.s = xstrdup(g_progname);
1254 }
1255
1256 n = seq->last;
1257 n->info = info;
1258 seq->last = n->a.n = new_node(OC_DONE);
1259
1260 return n;
1261 }
1262
1263 static void chain_expr(uint32_t info)
1264 {
1265 node *n;
1266
1267 n = chain_node(info);
1268 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1269 if (t_tclass & TC_GRPTERM)
1270 rollback_token();
1271 }
1272
1273 static node *chain_loop(node *nn)
1274 {
1275 node *n, *n2, *save_brk, *save_cont;
1276
1277 save_brk = break_ptr;
1278 save_cont = continue_ptr;
1279
1280 n = chain_node(OC_BR | Vx);
1281 continue_ptr = new_node(OC_EXEC);
1282 break_ptr = new_node(OC_EXEC);
1283 chain_group();
1284 n2 = chain_node(OC_EXEC | Vx);
1285 n2->l.n = nn;
1286 n2->a.n = n;
1287 continue_ptr->a.n = n2;
1288 break_ptr->a.n = n->r.n = seq->last;
1289
1290 continue_ptr = save_cont;
1291 break_ptr = save_brk;
1292
1293 return n;
1294 }
1295
1296 /* parse group and attach it to chain */
1297 static void chain_group(void)
1298 {
1299 uint32_t c;
1300 node *n, *n2, *n3;
1301
1302 do {
1303 c = next_token(TC_GRPSEQ);
1304 } while (c & TC_NEWLINE);
1305
1306 if (c & TC_GRPSTART) {
1307 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
1308 if (t_tclass & TC_NEWLINE) continue;
1309 rollback_token();
1310 chain_group();
1311 }
1312 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1313 rollback_token();
1314 chain_expr(OC_EXEC | Vx);
1315 } else { /* TC_STATEMNT */
1316 switch (t_info & OPCLSMASK) {
1317 case ST_IF:
1318 n = chain_node(OC_BR | Vx);
1319 n->l.n = condition();
1320 chain_group();
1321 n2 = chain_node(OC_EXEC);
1322 n->r.n = seq->last;
1323 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
1324 chain_group();
1325 n2->a.n = seq->last;
1326 } else {
1327 rollback_token();
1328 }
1329 break;
1330
1331 case ST_WHILE:
1332 n2 = condition();
1333 n = chain_loop(NULL);
1334 n->l.n = n2;
1335 break;
1336
1337 case ST_DO:
1338 n2 = chain_node(OC_EXEC);
1339 n = chain_loop(NULL);
1340 n2->a.n = n->a.n;
1341 next_token(TC_WHILE);
1342 n->l.n = condition();
1343 break;
1344
1345 case ST_FOR:
1346 next_token(TC_SEQSTART);
1347 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
1348 if (t_tclass & TC_SEQTERM) { /* for-in */
1349 if ((n2->info & OPCLSMASK) != OC_IN)
1350 syntax_error(EMSG_UNEXP_TOKEN);
1351 n = chain_node(OC_WALKINIT | VV);
1352 n->l.n = n2->l.n;
1353 n->r.n = n2->r.n;
1354 n = chain_loop(NULL);
1355 n->info = OC_WALKNEXT | Vx;
1356 n->l.n = n2->l.n;
1357 } else { /* for (;;) */
1358 n = chain_node(OC_EXEC | Vx);
1359 n->l.n = n2;
1360 n2 = parse_expr(TC_SEMICOL);
1361 n3 = parse_expr(TC_SEQTERM);
1362 n = chain_loop(n3);
1363 n->l.n = n2;
1364 if (!n2)
1365 n->info = OC_EXEC;
1366 }
1367 break;
1368
1369 case OC_PRINT:
1370 case OC_PRINTF:
1371 n = chain_node(t_info);
1372 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
1373 if (t_tclass & TC_OUTRDR) {
1374 n->info |= t_info;
1375 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1376 }
1377 if (t_tclass & TC_GRPTERM)
1378 rollback_token();
1379 break;
1380
1381 case OC_BREAK:
1382 n = chain_node(OC_EXEC);
1383 n->a.n = break_ptr;
1384 break;
1385
1386 case OC_CONTINUE:
1387 n = chain_node(OC_EXEC);
1388 n->a.n = continue_ptr;
1389 break;
1390
1391 /* delete, next, nextfile, return, exit */
1392 default:
1393 chain_expr(t_info);
1394 }
1395 }
1396 }
1397
1398 static void parse_program(char *p)
1399 {
1400 uint32_t tclass;
1401 node *cn;
1402 func *f;
1403 var *v;
1404
1405 g_pos = p;
1406 t_lineno = 1;
1407 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
1408 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
1409
1410 if (tclass & TC_OPTERM)
1411 continue;
1412
1413 seq = &mainseq;
1414 if (tclass & TC_BEGIN) {
1415 seq = &beginseq;
1416 chain_group();
1417
1418 } else if (tclass & TC_END) {
1419 seq = &endseq;
1420 chain_group();
1421
1422 } else if (tclass & TC_FUNCDECL) {
1423 next_token(TC_FUNCTION);
1424 g_pos++;
1425 f = newfunc(t_string);
1426 f->body.first = NULL;
1427 f->nargs = 0;
1428 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
1429 v = findvar(ahash, t_string);
1430 v->x.aidx = (f->nargs)++;
1431
1432 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1433 break;
1434 }
1435 seq = &(f->body);
1436 chain_group();
1437 clear_array(ahash);
1438
1439 } else if (tclass & TC_OPSEQ) {
1440 rollback_token();
1441 cn = chain_node(OC_TEST);
1442 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
1443 if (t_tclass & TC_GRPSTART) {
1444 rollback_token();
1445 chain_group();
1446 } else {
1447 chain_node(OC_PRINT);
1448 }
1449 cn->r.n = mainseq.last;
1450
1451 } else /* if (tclass & TC_GRPSTART) */ {
1452 rollback_token();
1453 chain_group();
1454 }
1455 }
1456 }
1457
1458
1459 /* -------- program execution part -------- */
1460
1461 static node *mk_splitter(const char *s, tsplitter *spl)
1462 {
1463 regex_t *re, *ire;
1464 node *n;
1465
1466 re = &spl->re[0];
1467 ire = &spl->re[1];
1468 n = &spl->n;
1469 if ((n->info & OPCLSMASK) == OC_REGEXP) {
1470 regfree(re);
1471 regfree(ire); // TODO: nuke ire, use re+1?
1472 }
1473 if (strlen(s) > 1) {
1474 mk_re_node(s, n, re);
1475 } else {
1476 n->info = (uint32_t) *s;
1477 }
1478
1479 return n;
1480 }
1481
1482 /* use node as a regular expression. Supplied with node ptr and regex_t
1483 * storage space. Return ptr to regex (if result points to preg, it should
1484 * be later regfree'd manually
1485 */
1486 static regex_t *as_regex(node *op, regex_t *preg)
1487 {
1488 var *v;
1489 const char *s;
1490
1491 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1492 return icase ? op->r.ire : op->l.re;
1493 }
1494 v = nvalloc(1);
1495 s = getvar_s(evaluate(op, v));
1496 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1497 nvfree(v);
1498 return preg;
1499 }
1500
1501 /* gradually increasing buffer */
1502 static void qrealloc(char **b, int n, int *size)
1503 {
1504 if (!*b || n >= *size) {
1505 *size = n + (n>>1) + 80;
1506 *b = xrealloc(*b, *size);
1507 }
1508 }
1509
1510 /* resize field storage space */
1511 static void fsrealloc(int size)
1512 {
1513 int i;
1514
1515 if (size >= maxfields) {
1516 i = maxfields;
1517 maxfields = size + 16;
1518 Fields = xrealloc(Fields, maxfields * sizeof(var));
1519 for (; i < maxfields; i++) {
1520 Fields[i].type = VF_SPECIAL;
1521 Fields[i].string = NULL;
1522 }
1523 }
1524
1525 if (size < nfields) {
1526 for (i = size; i < nfields; i++) {
1527 clrvar(Fields + i);
1528 }
1529 }
1530 nfields = size;
1531 }
1532
1533 static int awk_split(const char *s, node *spl, char **slist)
1534 {
1535 int l, n = 0;
1536 char c[4];
1537 char *s1;
1538 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
1539
1540 /* in worst case, each char would be a separate field */
1541 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1542 strcpy(s1, s);
1543
1544 c[0] = c[1] = (char)spl->info;
1545 c[2] = c[3] = '\0';
1546 if (*getvar_s(intvar[RS]) == '\0')
1547 c[2] = '\n';
1548
1549 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1550 if (!*s)
1551 return n; /* "": zero fields */
1552 n++; /* at least one field will be there */
1553 do {
1554 l = strcspn(s, c+2); /* len till next NUL or \n */
1555 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1556 && pmatch[0].rm_so <= l
1557 ) {
1558 l = pmatch[0].rm_so;
1559 if (pmatch[0].rm_eo == 0) {
1560 l++;
1561 pmatch[0].rm_eo++;
1562 }
1563 n++; /* we saw yet another delimiter */
1564 } else {
1565 pmatch[0].rm_eo = l;
1566 if (s[l]) pmatch[0].rm_eo++;
1567 }
1568 memcpy(s1, s, l);
1569 s1[l] = '\0';
1570 nextword(&s1);
1571 s += pmatch[0].rm_eo;
1572 } while (*s);
1573 return n;
1574 }
1575 if (c[0] == '\0') { /* null split */
1576 while (*s) {
1577 *s1++ = *s++;
1578 *s1++ = '\0';
1579 n++;
1580 }
1581 return n;
1582 }
1583 if (c[0] != ' ') { /* single-character split */
1584 if (icase) {
1585 c[0] = toupper(c[0]);
1586 c[1] = tolower(c[1]);
1587 }
1588 if (*s1) n++;
1589 while ((s1 = strpbrk(s1, c))) {
1590 *s1++ = '\0';
1591 n++;
1592 }
1593 return n;
1594 }
1595 /* space split */
1596 while (*s) {
1597 s = skip_whitespace(s);
1598 if (!*s) break;
1599 n++;
1600 while (*s && !isspace(*s))
1601 *s1++ = *s++;
1602 *s1++ = '\0';
1603 }
1604 return n;
1605 }
1606
1607 static void split_f0(void)
1608 {
1609 /* static char *fstrings; */
1610 #define fstrings (G.split_f0__fstrings)
1611
1612 int i, n;
1613 char *s;
1614
1615 if (is_f0_split)
1616 return;
1617
1618 is_f0_split = TRUE;
1619 free(fstrings);
1620 fsrealloc(0);
1621 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
1622 fsrealloc(n);
1623 s = fstrings;
1624 for (i = 0; i < n; i++) {
1625 Fields[i].string = nextword(&s);
1626 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1627 }
1628
1629 /* set NF manually to avoid side effects */
1630 clrvar(intvar[NF]);
1631 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1632 intvar[NF]->number = nfields;
1633 #undef fstrings
1634 }
1635
1636 /* perform additional actions when some internal variables changed */
1637 static void handle_special(var *v)
1638 {
1639 int n;
1640 char *b;
1641 const char *sep, *s;
1642 int sl, l, len, i, bsize;
1643
1644 if (!(v->type & VF_SPECIAL))
1645 return;
1646
1647 if (v == intvar[NF]) {
1648 n = (int)getvar_i(v);
1649 fsrealloc(n);
1650
1651 /* recalculate $0 */
1652 sep = getvar_s(intvar[OFS]);
1653 sl = strlen(sep);
1654 b = NULL;
1655 len = 0;
1656 for (i = 0; i < n; i++) {
1657 s = getvar_s(&Fields[i]);
1658 l = strlen(s);
1659 if (b) {
1660 memcpy(b+len, sep, sl);
1661 len += sl;
1662 }
1663 qrealloc(&b, len+l+sl, &bsize);
1664 memcpy(b+len, s, l);
1665 len += l;
1666 }
1667 if (b)
1668 b[len] = '\0';
1669 setvar_p(intvar[F0], b);
1670 is_f0_split = TRUE;
1671
1672 } else if (v == intvar[F0]) {
1673 is_f0_split = FALSE;
1674
1675 } else if (v == intvar[FS]) {
1676 mk_splitter(getvar_s(v), &fsplitter);
1677
1678 } else if (v == intvar[RS]) {
1679 mk_splitter(getvar_s(v), &rsplitter);
1680
1681 } else if (v == intvar[IGNORECASE]) {
1682 icase = istrue(v);
1683
1684 } else { /* $n */
1685 n = getvar_i(intvar[NF]);
1686 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
1687 /* right here v is invalid. Just to note... */
1688 }
1689 }
1690
1691 /* step through func/builtin/etc arguments */
1692 static node *nextarg(node **pn)
1693 {
1694 node *n;
1695
1696 n = *pn;
1697 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1698 *pn = n->r.n;
1699 n = n->l.n;
1700 } else {
1701 *pn = NULL;
1702 }
1703 return n;
1704 }
1705
1706 static void hashwalk_init(var *v, xhash *array)
1707 {
1708 char **w;
1709 hash_item *hi;
1710 unsigned i;
1711
1712 if (v->type & VF_WALK)
1713 free(v->x.walker);
1714
1715 v->type |= VF_WALK;
1716 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
1717 w[0] = w[1] = (char *)(w + 2);
1718 for (i = 0; i < array->csize; i++) {
1719 hi = array->items[i];
1720 while (hi) {
1721 strcpy(*w, hi->name);
1722 nextword(w);
1723 hi = hi->next;
1724 }
1725 }
1726 }
1727
1728 static int hashwalk_next(var *v)
1729 {
1730 char **w;
1731
1732 w = v->x.walker;
1733 if (w[1] == w[0])
1734 return FALSE;
1735
1736 setvar_s(v, nextword(w+1));
1737 return TRUE;
1738 }
1739
1740 /* evaluate node, return 1 when result is true, 0 otherwise */
1741 static int ptest(node *pattern)
1742 {
1743 /* ptest__v is "static": to save stack space? */
1744 return istrue(evaluate(pattern, &G.ptest__v));
1745 }
1746
1747 /* read next record from stream rsm into a variable v */
1748 static int awk_getline(rstream *rsm, var *v)
1749 {
1750 char *b;
1751 regmatch_t pmatch[2];
1752 int a, p, pp=0, size;
1753 int fd, so, eo, r, rp;
1754 char c, *m, *s;
1755
1756 /* we're using our own buffer since we need access to accumulating
1757 * characters
1758 */
1759 fd = fileno(rsm->F);
1760 m = rsm->buffer;
1761 a = rsm->adv;
1762 p = rsm->pos;
1763 size = rsm->size;
1764 c = (char) rsplitter.n.info;
1765 rp = 0;
1766
1767 if (!m) qrealloc(&m, 256, &size);
1768 do {
1769 b = m + a;
1770 so = eo = p;
1771 r = 1;
1772 if (p > 0) {
1773 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1774 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
1775 b, 1, pmatch, 0) == 0) {
1776 so = pmatch[0].rm_so;
1777 eo = pmatch[0].rm_eo;
1778 if (b[eo] != '\0')
1779 break;
1780 }
1781 } else if (c != '\0') {
1782 s = strchr(b+pp, c);
1783 if (!s) s = memchr(b+pp, '\0', p - pp);
1784 if (s) {
1785 so = eo = s-b;
1786 eo++;
1787 break;
1788 }
1789 } else {
1790 while (b[rp] == '\n')
1791 rp++;
1792 s = strstr(b+rp, "\n\n");
1793 if (s) {
1794 so = eo = s-b;
1795 while (b[eo] == '\n') eo++;
1796 if (b[eo] != '\0')
1797 break;
1798 }
1799 }
1800 }
1801
1802 if (a > 0) {
1803 memmove(m, (const void *)(m+a), p+1);
1804 b = m;
1805 a = 0;
1806 }
1807
1808 qrealloc(&m, a+p+128, &size);
1809 b = m + a;
1810 pp = p;
1811 p += safe_read(fd, b+p, size-p-1);
1812 if (p < pp) {
1813 p = 0;
1814 r = 0;
1815 setvar_i(intvar[ERRNO], errno);
1816 }
1817 b[p] = '\0';
1818
1819 } while (p > pp);
1820
1821 if (p == 0) {
1822 r--;
1823 } else {
1824 c = b[so]; b[so] = '\0';
1825 setvar_s(v, b+rp);
1826 v->type |= VF_USER;
1827 b[so] = c;
1828 c = b[eo]; b[eo] = '\0';
1829 setvar_s(intvar[RT], b+so);
1830 b[eo] = c;
1831 }
1832
1833 rsm->buffer = m;
1834 rsm->adv = a + eo;
1835 rsm->pos = p - eo;
1836 rsm->size = size;
1837
1838 return r;
1839 }
1840
1841 static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
1842 {
1843 int r = 0;
1844 char c;
1845 const char *s = format;
1846
1847 if (int_as_int && n == (int)n) {
1848 r = snprintf(b, size, "%d", (int)n);
1849 } else {
1850 do { c = *s; } while (c && *++s);
1851 if (strchr("diouxX", c)) {
1852 r = snprintf(b, size, format, (int)n);
1853 } else if (strchr("eEfgG", c)) {
1854 r = snprintf(b, size, format, n);
1855 } else {
1856 syntax_error(EMSG_INV_FMT);
1857 }
1858 }
1859 return r;
1860 }
1861
1862
1863 /* formatted output into an allocated buffer, return ptr to buffer */
1864 static char *awk_printf(node *n)
1865 {
1866 char *b = NULL;
1867 char *fmt, *s, *f;
1868 const char *s1;
1869 int i, j, incr, bsize;
1870 char c, c1;
1871 var *v, *arg;
1872
1873 v = nvalloc(1);
1874 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
1875
1876 i = 0;
1877 while (*f) {
1878 s = f;
1879 while (*f && (*f != '%' || *(++f) == '%'))
1880 f++;
1881 while (*f && !isalpha(*f)) {
1882 if (*f == '*')
1883 syntax_error("%*x formats are not supported");
1884 f++;
1885 }
1886
1887 incr = (f - s) + MAXVARFMT;
1888 qrealloc(&b, incr + i, &bsize);
1889 c = *f;
1890 if (c != '\0') f++;
1891 c1 = *f;
1892 *f = '\0';
1893 arg = evaluate(nextarg(&n), v);
1894
1895 j = i;
1896 if (c == 'c' || !c) {
1897 i += sprintf(b+i, s, is_numeric(arg) ?
1898 (char)getvar_i(arg) : *getvar_s(arg));
1899 } else if (c == 's') {
1900 s1 = getvar_s(arg);
1901 qrealloc(&b, incr+i+strlen(s1), &bsize);
1902 i += sprintf(b+i, s, s1);
1903 } else {
1904 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1905 }
1906 *f = c1;
1907
1908 /* if there was an error while sprintf, return value is negative */
1909 if (i < j) i = j;
1910 }
1911
1912 b = xrealloc(b, i + 1);
1913 free(fmt);
1914 nvfree(v);
1915 b[i] = '\0';
1916 return b;
1917 }
1918
1919 /* common substitution routine
1920 * replace (nm) substring of (src) that match (n) with (repl), store
1921 * result into (dest), return number of substitutions. If nm=0, replace
1922 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1923 * subexpression matching (\1-\9)
1924 */
1925 static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
1926 {
1927 char *ds = NULL;
1928 const char *s;
1929 const char *sp;
1930 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1931 regmatch_t pmatch[10];
1932 regex_t sreg, *re;
1933
1934 re = as_regex(rn, &sreg);
1935 if (!src) src = intvar[F0];
1936 if (!dest) dest = intvar[F0];
1937
1938 i = di = 0;
1939 sp = getvar_s(src);
1940 rl = strlen(repl);
1941 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
1942 so = pmatch[0].rm_so;
1943 eo = pmatch[0].rm_eo;
1944
1945 qrealloc(&ds, di + eo + rl, &dssize);
1946 memcpy(ds + di, sp, eo);
1947 di += eo;
1948 if (++i >= nm) {
1949 /* replace */
1950 di -= (eo - so);
1951 nbs = 0;
1952 for (s = repl; *s; s++) {
1953 ds[di++] = c = *s;
1954 if (c == '\\') {
1955 nbs++;
1956 continue;
1957 }
1958 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1959 di -= ((nbs + 3) >> 1);
1960 j = 0;
1961 if (c != '&') {
1962 j = c - '0';
1963 nbs++;
1964 }
1965 if (nbs % 2) {
1966 ds[di++] = c;
1967 } else {
1968 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1969 qrealloc(&ds, di + rl + n, &dssize);
1970 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1971 di += n;
1972 }
1973 }
1974 nbs = 0;
1975 }
1976 }
1977
1978 sp += eo;
1979 if (i == nm) break;
1980 if (eo == so) {
1981 ds[di] = *sp++;
1982 if (!ds[di++]) break;
1983 }
1984 }
1985
1986 qrealloc(&ds, di + strlen(sp), &dssize);
1987 strcpy(ds + di, sp);
1988 setvar_p(dest, ds);
1989 if (re == &sreg) regfree(re);
1990 return i;
1991 }
1992
1993 static var *exec_builtin(node *op, var *res)
1994 {
1995 #define tspl (G.exec_builtin__tspl)
1996
1997 int (*to_xxx)(int);
1998 var *tv;
1999 node *an[4];
2000 var *av[4];
2001 const char *as[4];
2002 regmatch_t pmatch[2];
2003 regex_t sreg, *re;
2004 node *spl;
2005 uint32_t isr, info;
2006 int nargs;
2007 time_t tt;
2008 char *s, *s1;
2009 int i, l, ll, n;
2010
2011 tv = nvalloc(4);
2012 isr = info = op->info;
2013 op = op->l.n;
2014
2015 av[2] = av[3] = NULL;
2016 for (i = 0; i < 4 && op; i++) {
2017 an[i] = nextarg(&op);
2018 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
2019 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
2020 isr >>= 1;
2021 }
2022
2023 nargs = i;
2024 if ((uint32_t)nargs < (info >> 30))
2025 syntax_error(EMSG_TOO_FEW_ARGS);
2026
2027 switch (info & OPNMASK) {
2028
2029 case B_a2:
2030 #if ENABLE_FEATURE_AWK_LIBM
2031 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
2032 #else
2033 syntax_error(EMSG_NO_MATH);
2034 #endif
2035 break;
2036
2037 case B_sp:
2038 if (nargs > 2) {
2039 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2040 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2041 } else {
2042 spl = &fsplitter.n;
2043 }
2044
2045 n = awk_split(as[0], spl, &s);
2046 s1 = s;
2047 clear_array(iamarray(av[1]));
2048 for (i = 1; i <= n; i++)
2049 setari_u(av[1], i, nextword(&s1));
2050 free(s);
2051 setvar_i(res, n);
2052 break;
2053
2054 case B_ss:
2055 l = strlen(as[0]);
2056 i = getvar_i(av[1]) - 1;
2057 if (i > l) i = l;
2058 if (i < 0) i = 0;
2059 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
2060 if (n < 0) n = 0;
2061 s = xstrndup(as[0]+i, n);
2062 setvar_p(res, s);
2063 break;
2064
2065 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2066 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
2067 case B_an:
2068 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
2069 break;
2070
2071 case B_co:
2072 setvar_i(res, ~getvar_i_int(av[0]));
2073 break;
2074
2075 case B_ls:
2076 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
2077 break;
2078
2079 case B_or:
2080 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
2081 break;
2082
2083 case B_rs:
2084 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
2085 break;
2086
2087 case B_xo:
2088 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
2089 break;
2090
2091 case B_lo:
2092 to_xxx = tolower;
2093 goto lo_cont;
2094
2095 case B_up:
2096 to_xxx = toupper;
2097 lo_cont:
2098 s1 = s = xstrdup(as[0]);
2099 while (*s1) {
2100 *s1 = (*to_xxx)(*s1);
2101 s1++;
2102 }
2103 setvar_p(res, s);
2104 break;
2105
2106 case B_ix:
2107 n = 0;
2108 ll = strlen(as[1]);
2109 l = strlen(as[0]) - ll;
2110 if (ll > 0 && l >= 0) {
2111 if (!icase) {
2112 s = strstr(as[0], as[1]);
2113 if (s) n = (s - as[0]) + 1;
2114 } else {
2115 /* this piece of code is terribly slow and
2116 * really should be rewritten
2117 */
2118 for (i=0; i<=l; i++) {
2119 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2120 n = i+1;
2121 break;
2122 }
2123 }
2124 }
2125 }
2126 setvar_i(res, n);
2127 break;
2128
2129 case B_ti:
2130 if (nargs > 1)
2131 tt = getvar_i(av[1]);
2132 else
2133 time(&tt);
2134 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
2135 i = strftime(g_buf, MAXVARFMT,
2136 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2137 localtime(&tt));
2138 g_buf[i] = '\0';
2139 setvar_s(res, g_buf);
2140 break;
2141
2142 case B_ma:
2143 re = as_regex(an[1], &sreg);
2144 n = regexec(re, as[0], 1, pmatch, 0);
2145 if (n == 0) {
2146 pmatch[0].rm_so++;
2147 pmatch[0].rm_eo++;
2148 } else {
2149 pmatch[0].rm_so = 0;
2150 pmatch[0].rm_eo = -1;
2151 }
2152 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2153 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2154 setvar_i(res, pmatch[0].rm_so);
2155 if (re == &sreg) regfree(re);
2156 break;
2157
2158 case B_ge:
2159 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2160 break;
2161
2162 case B_gs:
2163 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2164 break;
2165
2166 case B_su:
2167 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2168 break;
2169 }
2170
2171 nvfree(tv);
2172 return res;
2173 #undef tspl
2174 }
2175
2176 /*
2177 * Evaluate node - the heart of the program. Supplied with subtree
2178 * and place where to store result. returns ptr to result.
2179 */
2180 #define XC(n) ((n) >> 8)
2181
2182 static var *evaluate(node *op, var *res)
2183 {
2184 /* This procedure is recursive so we should count every byte */
2185 #define fnargs (G.evaluate__fnargs)
2186 /* seed is initialized to 1 */
2187 #define seed (G.evaluate__seed)
2188 #define sreg (G.evaluate__sreg)
2189
2190 node *op1;
2191 var *v1;
2192 union {
2193 var *v;
2194 const char *s;
2195 double d;
2196 int i;
2197 } L, R;
2198 uint32_t opinfo;
2199 int opn;
2200 union {
2201 char *s;
2202 rstream *rsm;
2203 FILE *F;
2204 var *v;
2205 regex_t *re;
2206 uint32_t info;
2207 } X;
2208
2209 if (!op)
2210 return setvar_s(res, NULL);
2211
2212 v1 = nvalloc(2);
2213
2214 while (op) {
2215 opinfo = op->info;
2216 opn = (opinfo & OPNMASK);
2217 g_lineno = op->lineno;
2218
2219 /* execute inevitable things */
2220 op1 = op->l.n;
2221 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2222 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2223 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2224 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2225 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2226
2227 switch (XC(opinfo & OPCLSMASK)) {
2228
2229 /* -- iterative node type -- */
2230
2231 /* test pattern */
2232 case XC( OC_TEST ):
2233 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2234 /* it's range pattern */
2235 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2236 op->info |= OF_CHECKED;
2237 if (ptest(op1->r.n))
2238 op->info &= ~OF_CHECKED;
2239
2240 op = op->a.n;
2241 } else {
2242 op = op->r.n;
2243 }
2244 } else {
2245 op = (ptest(op1)) ? op->a.n : op->r.n;
2246 }
2247 break;
2248
2249 /* just evaluate an expression, also used as unconditional jump */
2250 case XC( OC_EXEC ):
2251 break;
2252
2253 /* branch, used in if-else and various loops */
2254 case XC( OC_BR ):
2255 op = istrue(L.v) ? op->a.n : op->r.n;
2256 break;
2257
2258 /* initialize for-in loop */
2259 case XC( OC_WALKINIT ):
2260 hashwalk_init(L.v, iamarray(R.v));
2261 break;
2262
2263 /* get next array item */
2264 case XC( OC_WALKNEXT ):
2265 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2266 break;
2267
2268 case XC( OC_PRINT ):
2269 case XC( OC_PRINTF ):
2270 X.F = stdout;
2271 if (op->r.n) {
2272 X.rsm = newfile(R.s);
2273 if (!X.rsm->F) {
2274 if (opn == '|') {
2275 X.rsm->F = popen(R.s, "w");
2276 if (X.rsm->F == NULL)
2277 bb_perror_msg_and_die("popen");
2278 X.rsm->is_pipe = 1;
2279 } else {
2280 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
2281 }
2282 }
2283 X.F = X.rsm->F;
2284 }
2285
2286 if ((opinfo & OPCLSMASK) == OC_PRINT) {
2287 if (!op1) {
2288 fputs(getvar_s(intvar[F0]), X.F);
2289 } else {
2290 while (op1) {
2291 L.v = evaluate(nextarg(&op1), v1);
2292 if (L.v->type & VF_NUMBER) {
2293 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
2294 getvar_i(L.v), TRUE);
2295 fputs(g_buf, X.F);
2296 } else {
2297 fputs(getvar_s(L.v), X.F);
2298 }
2299
2300 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
2301 }
2302 }
2303 fputs(getvar_s(intvar[ORS]), X.F);
2304
2305 } else { /* OC_PRINTF */
2306 L.s = awk_printf(op1);
2307 fputs(L.s, X.F);
2308 free((char*)L.s);
2309 }
2310 fflush(X.F);
2311 break;
2312
2313 case XC( OC_DELETE ):
2314 X.info = op1->info & OPCLSMASK;
2315 if (X.info == OC_VAR) {
2316 R.v = op1->l.v;
2317 } else if (X.info == OC_FNARG) {
2318 R.v = &fnargs[op1->l.i];
2319 } else {
2320 syntax_error(EMSG_NOT_ARRAY);
2321 }
2322
2323 if (op1->r.n) {
2324 clrvar(L.v);
2325 L.s = getvar_s(evaluate(op1->r.n, v1));
2326 hash_remove(iamarray(R.v), L.s);
2327 } else {
2328 clear_array(iamarray(R.v));
2329 }
2330 break;
2331
2332 case XC( OC_NEWSOURCE ):
2333 g_progname = op->l.s;
2334 break;
2335
2336 case XC( OC_RETURN ):
2337 copyvar(res, L.v);
2338 break;
2339
2340 case XC( OC_NEXTFILE ):
2341 nextfile = TRUE;
2342 case XC( OC_NEXT ):
2343 nextrec = TRUE;
2344 case XC( OC_DONE ):
2345 clrvar(res);
2346 break;
2347
2348 case XC( OC_EXIT ):
2349 awk_exit(L.d);
2350
2351 /* -- recursive node type -- */
2352
2353 case XC( OC_VAR ):
2354 L.v = op->l.v;
2355 if (L.v == intvar[NF])
2356 split_f0();
2357 goto v_cont;
2358
2359 case XC( OC_FNARG ):
2360 L.v = &fnargs[op->l.i];
2361 v_cont:
2362 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
2363 break;
2364
2365 case XC( OC_IN ):
2366 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2367 break;
2368
2369 case XC( OC_REGEXP ):
2370 op1 = op;
2371 L.s = getvar_s(intvar[F0]);
2372 goto re_cont;
2373
2374 case XC( OC_MATCH ):
2375 op1 = op->r.n;
2376 re_cont:
2377 X.re = as_regex(op1, &sreg);
2378 R.i = regexec(X.re, L.s, 0, NULL, 0);
2379 if (X.re == &sreg) regfree(X.re);
2380 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2381 break;
2382
2383 case XC( OC_MOVE ):
2384 /* if source is a temporary string, jusk relink it to dest */
2385 if (R.v == v1+1 && R.v->string) {
2386 res = setvar_p(L.v, R.v->string);
2387 R.v->string = NULL;
2388 } else {
2389 res = copyvar(L.v, R.v);
2390 }
2391 break;
2392
2393 case XC( OC_TERNARY ):
2394 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
2395 syntax_error(EMSG_POSSIBLE_ERROR);
2396 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2397 break;
2398
2399 case XC( OC_FUNC ):
2400 if (!op->r.f->body.first)
2401 syntax_error(EMSG_UNDEF_FUNC);
2402
2403 X.v = R.v = nvalloc(op->r.f->nargs+1);
2404 while (op1) {
2405 L.v = evaluate(nextarg(&op1), v1);
2406 copyvar(R.v, L.v);
2407 R.v->type |= VF_CHILD;
2408 R.v->x.parent = L.v;
2409 if (++R.v - X.v >= op->r.f->nargs)
2410 break;
2411 }
2412
2413 R.v = fnargs;
2414 fnargs = X.v;
2415
2416 L.s = g_progname;
2417 res = evaluate(op->r.f->body.first, res);
2418 g_progname = L.s;
2419
2420 nvfree(fnargs);
2421 fnargs = R.v;
2422 break;
2423
2424 case XC( OC_GETLINE ):
2425 case XC( OC_PGETLINE ):
2426 if (op1) {
2427 X.rsm = newfile(L.s);
2428 if (!X.rsm->F) {
2429 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2430 X.rsm->F = popen(L.s, "r");
2431 X.rsm->is_pipe = TRUE;
2432 } else {
2433 X.rsm->F = fopen_for_read(L.s); /* not xfopen! */
2434 }
2435 }
2436 } else {
2437 if (!iF) iF = next_input_file();
2438 X.rsm = iF;
2439 }
2440
2441 if (!X.rsm->F) {
2442 setvar_i(intvar[ERRNO], errno);
2443 setvar_i(res, -1);
2444 break;
2445 }
2446
2447 if (!op->r.n)
2448 R.v = intvar[F0];
2449
2450 L.i = awk_getline(X.rsm, R.v);
2451 if (L.i > 0) {
2452 if (!op1) {
2453 incvar(intvar[FNR]);
2454 incvar(intvar[NR]);
2455 }
2456 }
2457 setvar_i(res, L.i);
2458 break;
2459
2460 /* simple builtins */
2461 case XC( OC_FBLTIN ):
2462 switch (opn) {
2463
2464 case F_in:
2465 R.d = (int)L.d;
2466 break;
2467
2468 case F_rn:
2469 R.d = (double)rand() / (double)RAND_MAX;
2470 break;
2471 #if ENABLE_FEATURE_AWK_LIBM
2472 case F_co:
2473 R.d = cos(L.d);
2474 break;
2475
2476 case F_ex:
2477 R.d = exp(L.d);
2478 break;
2479
2480 case F_lg:
2481 R.d = log(L.d);
2482 break;
2483
2484 case F_si:
2485 R.d = sin(L.d);
2486 break;
2487
2488 case F_sq:
2489 R.d = sqrt(L.d);
2490 break;
2491 #else
2492 case F_co:
2493 case F_ex:
2494 case F_lg:
2495 case F_si:
2496 case F_sq:
2497 syntax_error(EMSG_NO_MATH);
2498 break;
2499 #endif
2500 case F_sr:
2501 R.d = (double)seed;
2502 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
2503 srand(seed);
2504 break;
2505
2506 case F_ti:
2507 R.d = time(NULL);
2508 break;
2509
2510 case F_le:
2511 if (!op1)
2512 L.s = getvar_s(intvar[F0]);
2513 R.d = strlen(L.s);
2514 break;
2515
2516 case F_sy:
2517 fflush(NULL);
2518 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2519 ? (system(L.s) >> 8) : 0;
2520 break;
2521
2522 case F_ff:
2523 if (!op1)
2524 fflush(stdout);
2525 else {
2526 if (L.s && *L.s) {
2527 X.rsm = newfile(L.s);
2528 fflush(X.rsm->F);
2529 } else {
2530 fflush(NULL);
2531 }
2532 }
2533 break;
2534
2535 case F_cl:
2536 X.rsm = (rstream *)hash_search(fdhash, L.s);
2537 if (X.rsm) {
2538 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
2539 free(X.rsm->buffer);
2540 hash_remove(fdhash, L.s);
2541 }
2542 if (R.i != 0)
2543 setvar_i(intvar[ERRNO], errno);
2544 R.d = (double)R.i;
2545 break;
2546 }
2547 setvar_i(res, R.d);
2548 break;
2549
2550 case XC( OC_BUILTIN ):
2551 res = exec_builtin(op, res);
2552 break;
2553
2554 case XC( OC_SPRINTF ):
2555 setvar_p(res, awk_printf(op1));
2556 break;
2557
2558 case XC( OC_UNARY ):
2559 X.v = R.v;
2560 L.d = R.d = getvar_i(R.v);
2561 switch (opn) {
2562 case 'P':
2563 L.d = ++R.d;
2564 goto r_op_change;
2565 case 'p':
2566 R.d++;
2567 goto r_op_change;
2568 case 'M':
2569 L.d = --R.d;
2570 goto r_op_change;
2571 case 'm':
2572 R.d--;
2573 goto r_op_change;
2574 case '!':
2575 L.d = istrue(X.v) ? 0 : 1;
2576 break;
2577 case '-':
2578 L.d = -R.d;
2579 break;
2580 r_op_change:
2581 setvar_i(X.v, R.d);
2582 }
2583 setvar_i(res, L.d);
2584 break;
2585
2586 case XC( OC_FIELD ):
2587 R.i = (int)getvar_i(R.v);
2588 if (R.i == 0) {
2589 res = intvar[F0];
2590 } else {
2591 split_f0();
2592 if (R.i > nfields)
2593 fsrealloc(R.i);
2594 res = &Fields[R.i - 1];
2595 }
2596 break;
2597
2598 /* concatenation (" ") and index joining (",") */
2599 case XC( OC_CONCAT ):
2600 case XC( OC_COMMA ):
2601 opn = strlen(L.s) + strlen(R.s) + 2;
2602 X.s = xmalloc(opn);
2603 strcpy(X.s, L.s);
2604 if ((opinfo & OPCLSMASK) == OC_COMMA) {
2605 L.s = getvar_s(intvar[SUBSEP]);
2606 X.s = xrealloc(X.s, opn + strlen(L.s));
2607 strcat(X.s, L.s);
2608 }
2609 strcat(X.s, R.s);
2610 setvar_p(res, X.s);
2611 break;
2612
2613 case XC( OC_LAND ):
2614 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2615 break;
2616
2617 case XC( OC_LOR ):
2618 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2619 break;
2620
2621 case XC( OC_BINARY ):
2622 case XC( OC_REPLACE ):
2623 R.d = getvar_i(R.v);
2624 switch (opn) {
2625 case '+':
2626 L.d += R.d;
2627 break;
2628 case '-':
2629 L.d -= R.d;
2630 break;
2631 case '*':
2632 L.d *= R.d;
2633 break;
2634 case '/':
2635 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
2636 L.d /= R.d;
2637 break;
2638 case '&':
2639 #if ENABLE_FEATURE_AWK_LIBM
2640 L.d = pow(L.d, R.d);
2641 #else
2642 syntax_error(EMSG_NO_MATH);
2643 #endif
2644 break;
2645 case '%':
2646 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
2647 L.d -= (int)(L.d / R.d) * R.d;
2648 break;
2649 }
2650 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
2651 break;
2652
2653 case XC( OC_COMPARE ):
2654 if (is_numeric(L.v) && is_numeric(R.v)) {
2655 L.d = getvar_i(L.v) - getvar_i(R.v);
2656 } else {
2657 L.s = getvar_s(L.v);
2658 R.s = getvar_s(R.v);
2659 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2660 }
2661 switch (opn & 0xfe) {
2662 case 0:
2663 R.i = (L.d > 0);
2664 break;
2665 case 2:
2666 R.i = (L.d >= 0);
2667 break;
2668 case 4:
2669 R.i = (L.d == 0);
2670 break;
2671 }
2672 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2673 break;
2674
2675 default:
2676 syntax_error(EMSG_POSSIBLE_ERROR);
2677 }
2678 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2679 op = op->a.n;
2680 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2681 break;
2682 if (nextrec)
2683 break;
2684 }
2685 nvfree(v1);
2686 return res;
2687 #undef fnargs
2688 #undef seed
2689 #undef sreg
2690 }
2691
2692
2693 /* -------- main & co. -------- */
2694
2695 static int awk_exit(int r)
2696 {
2697 var tv;
2698 unsigned i;
2699 hash_item *hi;
2700
2701 zero_out_var(&tv);
2702
2703 if (!exiting) {
2704 exiting = TRUE;
2705 nextrec = FALSE;
2706 evaluate(endseq.first, &tv);
2707 }
2708
2709 /* waiting for children */
2710 for (i = 0; i < fdhash->csize; i++) {
2711 hi = fdhash->items[i];
2712 while (hi) {
2713 if (hi->data.rs.F && hi->data.rs.is_pipe)
2714 pclose(hi->data.rs.F);
2715 hi = hi->next;
2716 }
2717 }
2718
2719 exit(r);
2720 }
2721
2722 /* if expr looks like "var=value", perform assignment and return 1,
2723 * otherwise return 0 */
2724 static int is_assignment(const char *expr)
2725 {
2726 char *exprc, *s, *s0, *s1;
2727
2728 exprc = xstrdup(expr);
2729 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2730 free(exprc);
2731 return FALSE;
2732 }
2733
2734 *(s++) = '\0';
2735 s0 = s1 = s;
2736 while (*s)
2737 *(s1++) = nextchar(&s);
2738
2739 *s1 = '\0';
2740 setvar_u(newvar(exprc), s0);
2741 free(exprc);
2742 return TRUE;
2743 }
2744
2745 /* switch to next input file */
2746 static rstream *next_input_file(void)
2747 {
2748 #define rsm (G.next_input_file__rsm)
2749 #define files_happen (G.next_input_file__files_happen)
2750
2751 FILE *F = NULL;
2752 const char *fname, *ind;
2753
2754 if (rsm.F) fclose(rsm.F);
2755 rsm.F = NULL;
2756 rsm.pos = rsm.adv = 0;
2757
2758 do {
2759 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
2760 if (files_happen)
2761 return NULL;
2762 fname = "-";
2763 F = stdin;
2764 } else {
2765 ind = getvar_s(incvar(intvar[ARGIND]));
2766 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
2767 if (fname && *fname && !is_assignment(fname))
2768 F = xfopen_stdin(fname);
2769 }
2770 } while (!F);
2771
2772 files_happen = TRUE;
2773 setvar_s(intvar[FILENAME], fname);
2774 rsm.F = F;
2775 return &rsm;
2776 #undef rsm
2777 #undef files_happen
2778 }
2779
2780 int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2781 int awk_main(int argc, char **argv)
2782 {
2783 unsigned opt;
2784 char *opt_F, *opt_W;
2785 llist_t *list_v = NULL;
2786 llist_t *list_f = NULL;
2787 int i, j;
2788 var *v;
2789 var tv;
2790 char **envp;
2791 char *vnames = (char *)vNames; /* cheat */
2792 char *vvalues = (char *)vValues;
2793
2794 INIT_G();
2795
2796 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
2797 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2798 if (ENABLE_LOCALE_SUPPORT)
2799 setlocale(LC_NUMERIC, "C");
2800
2801 zero_out_var(&tv);
2802
2803 /* allocate global buffer */
2804 g_buf = xmalloc(MAXVARFMT + 1);
2805
2806 vhash = hash_init();
2807 ahash = hash_init();
2808 fdhash = hash_init();
2809 fnhash = hash_init();
2810
2811 /* initialize variables */
2812 for (i = 0; *vnames; i++) {
2813 intvar[i] = v = newvar(nextword(&vnames));
2814 if (*vvalues != '\377')
2815 setvar_s(v, nextword(&vvalues));
2816 else
2817 setvar_i(v, 0);
2818
2819 if (*vnames == '*') {
2820 v->type |= VF_SPECIAL;
2821 vnames++;
2822 }
2823 }
2824
2825 handle_special(intvar[FS]);
2826 handle_special(intvar[RS]);
2827
2828 newfile("/dev/stdin")->F = stdin;
2829 newfile("/dev/stdout")->F = stdout;
2830 newfile("/dev/stderr")->F = stderr;
2831
2832 /* Huh, people report that sometimes environ is NULL. Oh well. */
2833 if (environ) for (envp = environ; *envp; envp++) {
2834 /* environ is writable, thus we don't strdup it needlessly */
2835 char *s = *envp;
2836 char *s1 = strchr(s, '=');
2837 if (s1) {
2838 *s1 = '\0';
2839 /* Both findvar and setvar_u take const char*
2840 * as 2nd arg -> environment is not trashed */
2841 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
2842 *s1 = '=';
2843 }
2844 }
2845 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
2846 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
2847 argv += optind;
2848 argc -= optind;
2849 if (opt & 0x1)
2850 setvar_s(intvar[FS], opt_F); // -F
2851 while (list_v) { /* -v */
2852 if (!is_assignment(llist_pop(&list_v)))
2853 bb_show_usage();
2854 }
2855 if (list_f) { /* -f */
2856 do {
2857 char *s = NULL;
2858 FILE *from_file;
2859
2860 g_progname = llist_pop(&list_f);
2861 from_file = xfopen_stdin(g_progname);
2862 /* one byte is reserved for some trick in next_token */
2863 for (i = j = 1; j > 0; i += j) {
2864 s = xrealloc(s, i + 4096);
2865 j = fread(s + i, 1, 4094, from_file);
2866 }
2867 s[i] = '\0';
2868 fclose(from_file);
2869 parse_program(s + 1);
2870 free(s);
2871 } while (list_f);
2872 } else { // no -f: take program from 1st parameter
2873 if (!argc)
2874 bb_show_usage();
2875 g_progname = "cmd. line";
2876 parse_program(*argv++);
2877 argc--;
2878 }
2879 if (opt & 0x8) // -W
2880 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
2881
2882 /* fill in ARGV array */
2883 setvar_i(intvar[ARGC], argc + 1);
2884 setari_u(intvar[ARGV], 0, "awk");
2885 i = 0;
2886 while (*argv)
2887 setari_u(intvar[ARGV], ++i, *argv++);
2888
2889 evaluate(beginseq.first, &tv);
2890 if (!mainseq.first && !endseq.first)
2891 awk_exit(EXIT_SUCCESS);
2892
2893 /* input file could already be opened in BEGIN block */
2894 if (!iF) iF = next_input_file();
2895
2896 /* passing through input files */
2897 while (iF) {
2898 nextfile = FALSE;
2899 setvar_i(intvar[FNR], 0);
2900
2901 while ((i = awk_getline(iF, intvar[F0])) > 0) {
2902 nextrec = FALSE;
2903 incvar(intvar[NR]);
2904 incvar(intvar[FNR]);
2905 evaluate(mainseq.first, &tv);
2906
2907 if (nextfile)
2908 break;
2909 }
2910
2911 if (i < 0)
2912 syntax_error(strerror(errno));
2913
2914 iF = next_input_file();
2915 }
2916
2917 awk_exit(EXIT_SUCCESS);
2918 /*return 0;*/
2919 }