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