several *.c files:
[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 "busybox.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=0, 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=0, 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=0,  OFMT,       FS,         OFS,
369         ORS,        RS,         RT,         FILENAME,
370         SUBSEP,     ARGIND,     ARGC,       ARGV,
371         ERRNO,      FNR,
372         NR,         NF,         IGNORECASE,
373         ENVIRON,    F0,         _intvarcount_
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(unsigned) };
394
395 /* globals */
396
397 static var * V[_intvarcount_];
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
425 /* function prototypes */
426 static void handle_special(var *);
427 static node *parse_expr(uint32_t);
428 static void chain_group(void);
429 static var *evaluate(node *, var *);
430 static rstream *next_input_file(void);
431 static int fmt_num(char *, int, const char *, double, int);
432 static int awk_exit(int) ATTRIBUTE_NORETURN;
433
434 /* ---- error handling ---- */
435
436 static const char EMSG_INTERNAL_ERROR[] = "Internal error";
437 static const char EMSG_UNEXP_EOS[] = "Unexpected end of string";
438 static const char EMSG_UNEXP_TOKEN[] = "Unexpected token";
439 static const char EMSG_DIV_BY_ZERO[] = "Division by zero";
440 static const char EMSG_INV_FMT[] = "Invalid format specifier";
441 static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin";
442 static const char EMSG_NOT_ARRAY[] = "Not an array";
443 static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error";
444 static const char EMSG_UNDEF_FUNC[] = "Call to undefined function";
445 #if !ENABLE_FEATURE_AWK_MATH
446 static const char EMSG_NO_MATH[] = "Math support is not compiled in";
447 #endif
448
449 static void zero_out_var(var * vp)
450 {
451         memset(vp, 0, sizeof(*vp));
452 }
453
454 static void syntax_error(const char * const message) ATTRIBUTE_NORETURN;
455 static void syntax_error(const char * const message)
456 {
457         bb_error_msg_and_die("%s:%i: %s", programname, lineno, message);
458 }
459
460 #define runtime_error(x) syntax_error(x)
461
462
463 /* ---- hash stuff ---- */
464
465 static unsigned hashidx(const char *name)
466 {
467         unsigned idx = 0;
468
469         while (*name) idx = *name++ + (idx << 6) - idx;
470         return idx;
471 }
472
473 /* create new hash */
474 static xhash *hash_init(void)
475 {
476         xhash *newhash;
477
478         newhash = xzalloc(sizeof(xhash));
479         newhash->csize = FIRST_PRIME;
480         newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
481
482         return newhash;
483 }
484
485 /* find item in hash, return ptr to data, NULL if not found */
486 static void *hash_search(xhash *hash, const char *name)
487 {
488         hash_item *hi;
489
490         hi = hash->items [ hashidx(name) % hash->csize ];
491         while (hi) {
492                 if (strcmp(hi->name, name) == 0)
493                         return &(hi->data);
494                 hi = hi->next;
495         }
496         return NULL;
497 }
498
499 /* grow hash if it becomes too big */
500 static void hash_rebuild(xhash *hash)
501 {
502         unsigned newsize, i, idx;
503         hash_item **newitems, *hi, *thi;
504
505         if (hash->nprime == NPRIMES)
506                 return;
507
508         newsize = PRIMES[hash->nprime++];
509         newitems = xzalloc(newsize * sizeof(hash_item *));
510
511         for (i=0; i<hash->csize; i++) {
512                 hi = hash->items[i];
513                 while (hi) {
514                         thi = hi;
515                         hi = thi->next;
516                         idx = hashidx(thi->name) % newsize;
517                         thi->next = newitems[idx];
518                         newitems[idx] = thi;
519                 }
520         }
521
522         free(hash->items);
523         hash->csize = newsize;
524         hash->items = newitems;
525 }
526
527 /* find item in hash, add it if necessary. Return ptr to data */
528 static void *hash_find(xhash *hash, const char *name)
529 {
530         hash_item *hi;
531         unsigned idx;
532         int l;
533
534         hi = hash_search(hash, name);
535         if (! hi) {
536                 if (++hash->nel / hash->csize > 10)
537                         hash_rebuild(hash);
538
539                 l = strlen(name) + 1;
540                 hi = xzalloc(sizeof(hash_item) + l);
541                 memcpy(hi->name, name, l);
542
543                 idx = hashidx(name) % hash->csize;
544                 hi->next = hash->items[idx];
545                 hash->items[idx] = hi;
546                 hash->glen += l;
547         }
548         return &(hi->data);
549 }
550
551 #define findvar(hash, name) ((var*)    hash_find((hash) , (name)))
552 #define newvar(name)        ((var*)    hash_find(vhash , (name)))
553 #define newfile(name)       ((rstream*)hash_find(fdhash ,(name)))
554 #define newfunc(name)       ((func*)   hash_find(fnhash , (name)))
555
556 static void hash_remove(xhash *hash, const char *name)
557 {
558         hash_item *hi, **phi;
559
560         phi = &(hash->items[ hashidx(name) % hash->csize ]);
561         while (*phi) {
562                 hi = *phi;
563                 if (strcmp(hi->name, name) == 0) {
564                         hash->glen -= (strlen(name) + 1);
565                         hash->nel--;
566                         *phi = hi->next;
567                         free(hi);
568                         break;
569                 }
570                 phi = &(hi->next);
571         }
572 }
573
574 /* ------ some useful functions ------ */
575
576 static void skip_spaces(char **s)
577 {
578         char *p = *s;
579
580         while (1) {
581                 if (*p == '\\' && p[1] == '\n') {
582                         p++;
583                         ttt.lineno++;
584                 } else if (*p != ' ' && *p != '\t') {
585                         break;
586                 }
587                 p++;
588         }
589         *s = p;
590 }
591
592 static char *nextword(char **s)
593 {
594         char *p = *s;
595
596         while (*(*s)++) /* */;
597
598         return p;
599 }
600
601 static char nextchar(char **s)
602 {
603         char c, *pps;
604
605         c = *((*s)++);
606         pps = *s;
607         if (c == '\\') c = bb_process_escape_sequence((const char**)s);
608         if (c == '\\' && *s == pps) c = *((*s)++);
609         return c;
610 }
611
612 static int ATTRIBUTE_ALWAYS_INLINE isalnum_(int c)
613 {
614         return (isalnum(c) || c == '_');
615 }
616
617 static FILE *afopen(const char *path, const char *mode)
618 {
619         return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode);
620 }
621
622 /* -------- working with variables (set/get/copy/etc) -------- */
623
624 static xhash *iamarray(var *v)
625 {
626         var *a = v;
627
628         while (a->type & VF_CHILD)
629                 a = a->x.parent;
630
631         if (!(a->type & VF_ARRAY)) {
632                 a->type |= VF_ARRAY;
633                 a->x.array = hash_init();
634         }
635         return a->x.array;
636 }
637
638 static void clear_array(xhash *array)
639 {
640         unsigned i;
641         hash_item *hi, *thi;
642
643         for (i = 0; i < array->csize; i++) {
644                 hi = array->items[i];
645                 while (hi) {
646                         thi = hi;
647                         hi = hi->next;
648                         free(thi->data.v.string);
649                         free(thi);
650                 }
651                 array->items[i] = NULL;
652         }
653         array->glen = array->nel = 0;
654 }
655
656 /* clear a variable */
657 static var *clrvar(var *v)
658 {
659         if (!(v->type & VF_FSTR))
660                 free(v->string);
661
662         v->type &= VF_DONTTOUCH;
663         v->type |= VF_DIRTY;
664         v->string = NULL;
665         return v;
666 }
667
668 /* assign string value to variable */
669 static var *setvar_p(var *v, char *value)
670 {
671         clrvar(v);
672         v->string = value;
673         handle_special(v);
674
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         var *v;
696         static char sidx[12];
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(V[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') p++;
872
873                 if (*p == '\n')
874                         ttt.lineno++;
875
876                 if (*p == '\0') {
877                         tc = TC_EOF;
878
879                 } else if (*p == '\"') {
880                         /* it's a string */
881                         ttt.string = s = ++p;
882                         while (*p != '\"') {
883                                 if (*p == '\0' || *p == '\n')
884                                         syntax_error(EMSG_UNEXP_EOS);
885                                 *(s++) = nextchar(&p);
886                         }
887                         p++;
888                         *s = '\0';
889                         tc = TC_STRING;
890
891                 } else if ((expected & TC_REGEXP) && *p == '/') {
892                         /* it's regexp */
893                         ttt.string = s = ++p;
894                         while (*p != '/') {
895                                 if (*p == '\0' || *p == '\n')
896                                         syntax_error(EMSG_UNEXP_EOS);
897                                 if ((*s++ = *p++) == '\\') {
898                                         pp = p;
899                                         *(s-1) = bb_process_escape_sequence((const char **)&p);
900                                         if (*pp == '\\') *s++ = '\\';
901                                         if (p == pp) *s++ = *p++;
902                                 }
903                         }
904                         p++;
905                         *s = '\0';
906                         tc = TC_REGEXP;
907
908                 } else if (*p == '.' || isdigit(*p)) {
909                         /* it's a number */
910                         ttt.number = strtod(p, &p);
911                         if (*p == '.')
912                                 syntax_error(EMSG_UNEXP_TOKEN);
913                         tc = TC_NUMBER;
914
915                 } else {
916                         /* search for something known */
917                         tl = tokenlist;
918                         tc = 0x00000001;
919                         ti = tokeninfo;
920                         while (*tl) {
921                                 l = *(tl++);
922                                 if (l == NTCC) {
923                                         tc <<= 1;
924                                         continue;
925                                 }
926                                 /* if token class is expected, token
927                                  * matches and it's not a longer word,
928                                  * then this is what we are looking for
929                                  */
930                                 if ((tc & (expected | TC_WORD | TC_NEWLINE)) &&
931                                 *tl == *p && strncmp(p, tl, l) == 0 &&
932                                 !((tc & TC_WORD) && isalnum_(*(p + l)))) {
933                                         ttt.info = *ti;
934                                         p += l;
935                                         break;
936                                 }
937                                 ti++;
938                                 tl += l;
939                         }
940
941                         if (!*tl) {
942                                 /* it's a name (var/array/function),
943                                  * otherwise it's something wrong
944                                  */
945                                 if (!isalnum_(*p))
946                                         syntax_error(EMSG_UNEXP_TOKEN);
947
948                                 ttt.string = --p;
949                                 while (isalnum_(*(++p))) {
950                                         *(p-1) = *p;
951                                 }
952                                 *(p-1) = '\0';
953                                 tc = TC_VARIABLE;
954                                 /* also consume whitespace between functionname and bracket */
955                                 if (!(expected & TC_VARIABLE)) skip_spaces(&p);
956                                 if (*p == '(') {
957                                         tc = TC_FUNCTION;
958                                 } else {
959                                         if (*p == '[') {
960                                                 p++;
961                                                 tc = TC_ARRAY;
962                                         }
963                                 }
964                         }
965                 }
966                 pos = p;
967
968                 /* skipping newlines in some cases */
969                 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
970                         goto readnext;
971
972                 /* insert concatenation operator when needed */
973                 if ((ltclass&TC_CONCAT1) && (tc&TC_CONCAT2) && (expected&TC_BINOP)) {
974                         concat_inserted = TRUE;
975                         save_tclass = tc;
976                         save_info = ttt.info;
977                         tc = TC_BINOP;
978                         ttt.info = OC_CONCAT | SS | P(35);
979                 }
980
981                 ttt.tclass = tc;
982         }
983         ltclass = ttt.tclass;
984
985         /* Are we ready for this? */
986         if (! (ltclass & expected))
987                 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
988                                                                 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
989
990         return ltclass;
991 }
992
993 static void rollback_token(void)
994 {
995         ttt.rollback = TRUE;
996 }
997
998 static node *new_node(uint32_t info)
999 {
1000         node *n;
1001
1002         n = xzalloc(sizeof(node));
1003         n->info = info;
1004         n->lineno = lineno;
1005         return n;
1006 }
1007
1008 static node *mk_re_node(const char *s, node *n, regex_t *re)
1009 {
1010         n->info = OC_REGEXP;
1011         n->l.re = re;
1012         n->r.ire = re + 1;
1013         xregcomp(re, s, REG_EXTENDED);
1014         xregcomp(re+1, s, REG_EXTENDED | REG_ICASE);
1015
1016         return n;
1017 }
1018
1019 static node *condition(void)
1020 {
1021         next_token(TC_SEQSTART);
1022         return parse_expr(TC_SEQTERM);
1023 }
1024
1025 /* parse expression terminated by given argument, return ptr
1026  * to built subtree. Terminator is eaten by parse_expr */
1027 static node *parse_expr(uint32_t iexp)
1028 {
1029         node sn;
1030         node *cn = &sn;
1031         node *vn, *glptr;
1032         uint32_t tc, xtc;
1033         var *v;
1034
1035         sn.info = PRIMASK;
1036         sn.r.n = glptr = NULL;
1037         xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1038
1039         while (!((tc = next_token(xtc)) & iexp)) {
1040                 if (glptr && (ttt.info == (OC_COMPARE|VV|P(39)|2))) {
1041                         /* input redirection (<) attached to glptr node */
1042                         cn = glptr->l.n = new_node(OC_CONCAT|SS|P(37));
1043                         cn->a.n = glptr;
1044                         xtc = TC_OPERAND | TC_UOPPRE;
1045                         glptr = NULL;
1046
1047                 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1048                         /* for binary and postfix-unary operators, jump back over
1049                          * previous operators with higher priority */
1050                         vn = cn;
1051                         while ( ((ttt.info & PRIMASK) > (vn->a.n->info & PRIMASK2)) ||
1052                           ((ttt.info == vn->info) && ((ttt.info & OPCLSMASK) == OC_COLON)) )
1053                                 vn = vn->a.n;
1054                         if ((ttt.info & OPCLSMASK) == OC_TERNARY)
1055                                 ttt.info += P(6);
1056                         cn = vn->a.n->r.n = new_node(ttt.info);
1057                         cn->a.n = vn->a.n;
1058                         if (tc & TC_BINOP) {
1059                                 cn->l.n = vn;
1060                                 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1061                                 if ((ttt.info & OPCLSMASK) == OC_PGETLINE) {
1062                                         /* it's a pipe */
1063                                         next_token(TC_GETLINE);
1064                                         /* give maximum priority to this pipe */
1065                                         cn->info &= ~PRIMASK;
1066                                         xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1067                                 }
1068                         } else {
1069                                 cn->r.n = vn;
1070                                 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1071                         }
1072                         vn->a.n = cn;
1073
1074                 } else {
1075                         /* for operands and prefix-unary operators, attach them
1076                          * to last node */
1077                         vn = cn;
1078                         cn = vn->r.n = new_node(ttt.info);
1079                         cn->a.n = vn;
1080                         xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1081                         if (tc & (TC_OPERAND | TC_REGEXP)) {
1082                                 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
1083                                 /* one should be very careful with switch on tclass -
1084                                  * only simple tclasses should be used! */
1085                                 switch (tc) {
1086                                 case TC_VARIABLE:
1087                                 case TC_ARRAY:
1088                                         cn->info = OC_VAR;
1089                                         if ((v = hash_search(ahash, ttt.string)) != NULL) {
1090                                                 cn->info = OC_FNARG;
1091                                                 cn->l.i = v->x.aidx;
1092                                         } else {
1093                                                 cn->l.v = newvar(ttt.string);
1094                                         }
1095                                         if (tc & TC_ARRAY) {
1096                                                 cn->info |= xS;
1097                                                 cn->r.n = parse_expr(TC_ARRTERM);
1098                                         }
1099                                         break;
1100
1101                                 case TC_NUMBER:
1102                                 case TC_STRING:
1103                                         cn->info = OC_VAR;
1104                                         v = cn->l.v = xzalloc(sizeof(var));
1105                                         if (tc & TC_NUMBER)
1106                                                 setvar_i(v, ttt.number);
1107                                         else
1108                                                 setvar_s(v, ttt.string);
1109                                         break;
1110
1111                                 case TC_REGEXP:
1112                                         mk_re_node(ttt.string, cn, xzalloc(sizeof(regex_t)*2));
1113                                         break;
1114
1115                                 case TC_FUNCTION:
1116                                         cn->info = OC_FUNC;
1117                                         cn->r.f = newfunc(ttt.string);
1118                                         cn->l.n = condition();
1119                                         break;
1120
1121                                 case TC_SEQSTART:
1122                                         cn = vn->r.n = parse_expr(TC_SEQTERM);
1123                                         cn->a.n = vn;
1124                                         break;
1125
1126                                 case TC_GETLINE:
1127                                         glptr = cn;
1128                                         xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1129                                         break;
1130
1131                                 case TC_BUILTIN:
1132                                         cn->l.n = condition();
1133                                         break;
1134                                 }
1135                         }
1136                 }
1137         }
1138         return sn.r.n;
1139 }
1140
1141 /* add node to chain. Return ptr to alloc'd node */
1142 static node *chain_node(uint32_t info)
1143 {
1144         node *n;
1145
1146         if (!seq->first)
1147                 seq->first = seq->last = new_node(0);
1148
1149         if (seq->programname != programname) {
1150                 seq->programname = programname;
1151                 n = chain_node(OC_NEWSOURCE);
1152                 n->l.s = xstrdup(programname);
1153         }
1154
1155         n = seq->last;
1156         n->info = info;
1157         seq->last = n->a.n = new_node(OC_DONE);
1158
1159         return n;
1160 }
1161
1162 static void chain_expr(uint32_t info)
1163 {
1164         node *n;
1165
1166         n = chain_node(info);
1167         n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1168         if (ttt.tclass & TC_GRPTERM)
1169                 rollback_token();
1170 }
1171
1172 static node *chain_loop(node *nn)
1173 {
1174         node *n, *n2, *save_brk, *save_cont;
1175
1176         save_brk = break_ptr;
1177         save_cont = continue_ptr;
1178
1179         n = chain_node(OC_BR | Vx);
1180         continue_ptr = new_node(OC_EXEC);
1181         break_ptr = new_node(OC_EXEC);
1182         chain_group();
1183         n2 = chain_node(OC_EXEC | Vx);
1184         n2->l.n = nn;
1185         n2->a.n = n;
1186         continue_ptr->a.n = n2;
1187         break_ptr->a.n = n->r.n = seq->last;
1188
1189         continue_ptr = save_cont;
1190         break_ptr = save_brk;
1191
1192         return n;
1193 }
1194
1195 /* parse group and attach it to chain */
1196 static void chain_group(void)
1197 {
1198         uint32_t c;
1199         node *n, *n2, *n3;
1200
1201         do {
1202                 c = next_token(TC_GRPSEQ);
1203         } while (c & TC_NEWLINE);
1204
1205         if (c & TC_GRPSTART) {
1206                 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
1207                         if (ttt.tclass & TC_NEWLINE) continue;
1208                         rollback_token();
1209                         chain_group();
1210                 }
1211         } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1212                 rollback_token();
1213                 chain_expr(OC_EXEC | Vx);
1214         } else {                                                /* TC_STATEMNT */
1215                 switch (ttt.info & OPCLSMASK) {
1216                         case ST_IF:
1217                                 n = chain_node(OC_BR | Vx);
1218                                 n->l.n = condition();
1219                                 chain_group();
1220                                 n2 = chain_node(OC_EXEC);
1221                                 n->r.n = seq->last;
1222                                 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE)==TC_ELSE) {
1223                                         chain_group();
1224                                         n2->a.n = seq->last;
1225                                 } else {
1226                                         rollback_token();
1227                                 }
1228                                 break;
1229
1230                         case ST_WHILE:
1231                                 n2 = condition();
1232                                 n = chain_loop(NULL);
1233                                 n->l.n = n2;
1234                                 break;
1235
1236                         case ST_DO:
1237                                 n2 = chain_node(OC_EXEC);
1238                                 n = chain_loop(NULL);
1239                                 n2->a.n = n->a.n;
1240                                 next_token(TC_WHILE);
1241                                 n->l.n = condition();
1242                                 break;
1243
1244                         case ST_FOR:
1245                                 next_token(TC_SEQSTART);
1246                                 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
1247                                 if (ttt.tclass & TC_SEQTERM) {  /* for-in */
1248                                         if ((n2->info & OPCLSMASK) != OC_IN)
1249                                                 syntax_error(EMSG_UNEXP_TOKEN);
1250                                         n = chain_node(OC_WALKINIT | VV);
1251                                         n->l.n = n2->l.n;
1252                                         n->r.n = n2->r.n;
1253                                         n = chain_loop(NULL);
1254                                         n->info = OC_WALKNEXT | Vx;
1255                                         n->l.n = n2->l.n;
1256                                 } else {                        /* for (;;) */
1257                                         n = chain_node(OC_EXEC | Vx);
1258                                         n->l.n = n2;
1259                                         n2 = parse_expr(TC_SEMICOL);
1260                                         n3 = parse_expr(TC_SEQTERM);
1261                                         n = chain_loop(n3);
1262                                         n->l.n = n2;
1263                                         if (! n2)
1264                                                 n->info = OC_EXEC;
1265                                 }
1266                                 break;
1267
1268                         case OC_PRINT:
1269                         case OC_PRINTF:
1270                                 n = chain_node(ttt.info);
1271                                 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
1272                                 if (ttt.tclass & TC_OUTRDR) {
1273                                         n->info |= ttt.info;
1274                                         n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1275                                 }
1276                                 if (ttt.tclass & TC_GRPTERM)
1277                                         rollback_token();
1278                                 break;
1279
1280                         case OC_BREAK:
1281                                 n = chain_node(OC_EXEC);
1282                                 n->a.n = break_ptr;
1283                                 break;
1284
1285                         case OC_CONTINUE:
1286                                 n = chain_node(OC_EXEC);
1287                                 n->a.n = continue_ptr;
1288                                 break;
1289
1290                         /* delete, next, nextfile, return, exit */
1291                         default:
1292                                 chain_expr(ttt.info);
1293                 }
1294         }
1295 }
1296
1297 static void parse_program(char *p)
1298 {
1299         uint32_t tclass;
1300         node *cn;
1301         func *f;
1302         var *v;
1303
1304         pos = p;
1305         ttt.lineno = 1;
1306         while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
1307                                 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
1308
1309                 if (tclass & TC_OPTERM)
1310                         continue;
1311
1312                 seq = &mainseq;
1313                 if (tclass & TC_BEGIN) {
1314                         seq = &beginseq;
1315                         chain_group();
1316
1317                 } else if (tclass & TC_END) {
1318                         seq = &endseq;
1319                         chain_group();
1320
1321                 } else if (tclass & TC_FUNCDECL) {
1322                         next_token(TC_FUNCTION);
1323                         pos++;
1324                         f = newfunc(ttt.string);
1325                         f->body.first = NULL;
1326                         f->nargs = 0;
1327                         while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
1328                                 v = findvar(ahash, ttt.string);
1329                                 v->x.aidx = (f->nargs)++;
1330
1331                                 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1332                                         break;
1333                         }
1334                         seq = &(f->body);
1335                         chain_group();
1336                         clear_array(ahash);
1337
1338                 } else if (tclass & TC_OPSEQ) {
1339                         rollback_token();
1340                         cn = chain_node(OC_TEST);
1341                         cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
1342                         if (ttt.tclass & TC_GRPSTART) {
1343                                 rollback_token();
1344                                 chain_group();
1345                         } else {
1346                                 chain_node(OC_PRINT);
1347                         }
1348                         cn->r.n = mainseq.last;
1349
1350                 } else /* if (tclass & TC_GRPSTART) */ {
1351                         rollback_token();
1352                         chain_group();
1353                 }
1354         }
1355 }
1356
1357
1358 /* -------- program execution part -------- */
1359
1360 static node *mk_splitter(const char *s, tsplitter *spl)
1361 {
1362         regex_t *re, *ire;
1363         node *n;
1364
1365         re = &spl->re[0];
1366         ire = &spl->re[1];
1367         n = &spl->n;
1368         if ((n->info & OPCLSMASK) == OC_REGEXP) {
1369                 regfree(re);
1370                 regfree(ire);
1371         }
1372         if (strlen(s) > 1) {
1373                 mk_re_node(s, n, re);
1374         } else {
1375                 n->info = (uint32_t) *s;
1376         }
1377
1378         return n;
1379 }
1380
1381 /* use node as a regular expression. Supplied with node ptr and regex_t
1382  * storage space. Return ptr to regex (if result points to preg, it should
1383  * be later regfree'd manually
1384  */
1385 static regex_t *as_regex(node *op, regex_t *preg)
1386 {
1387         var *v;
1388         const char *s;
1389
1390         if ((op->info & OPCLSMASK) == OC_REGEXP) {
1391                 return icase ? op->r.ire : op->l.re;
1392         } else {
1393                 v = nvalloc(1);
1394                 s = getvar_s(evaluate(op, v));
1395                 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1396                 nvfree(v);
1397                 return preg;
1398         }
1399 }
1400
1401 /* gradually increasing buffer */
1402 static void qrealloc(char **b, int n, int *size)
1403 {
1404         if (!*b || n >= *size)
1405                 *b = xrealloc(*b, *size = n + (n>>1) + 80);
1406 }
1407
1408 /* resize field storage space */
1409 static void fsrealloc(int size)
1410 {
1411         static int maxfields; /* = 0;*/
1412         int i;
1413
1414         if (size >= maxfields) {
1415                 i = maxfields;
1416                 maxfields = size + 16;
1417                 Fields = xrealloc(Fields, maxfields * sizeof(var));
1418                 for (; i < maxfields; i++) {
1419                         Fields[i].type = VF_SPECIAL;
1420                         Fields[i].string = NULL;
1421                 }
1422         }
1423
1424         if (size < nfields) {
1425                 for (i = size; i < nfields; i++) {
1426                         clrvar(Fields + i);
1427                 }
1428         }
1429         nfields = size;
1430 }
1431
1432 static int awk_split(const char *s, node *spl, char **slist)
1433 {
1434         int l, n = 0;
1435         char c[4];
1436         char *s1;
1437         regmatch_t pmatch[2];
1438
1439         /* in worst case, each char would be a separate field */
1440         *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1441         strcpy(s1, s);
1442
1443         c[0] = c[1] = (char)spl->info;
1444         c[2] = c[3] = '\0';
1445         if (*getvar_s(V[RS]) == '\0') c[2] = '\n';
1446
1447         if ((spl->info & OPCLSMASK) == OC_REGEXP) {             /* regex split */
1448                 while (*s) {
1449                         l = strcspn(s, c+2);
1450                         if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1451                          && pmatch[0].rm_so <= l
1452                         ) {
1453                                 l = pmatch[0].rm_so;
1454                                 if (pmatch[0].rm_eo == 0) { l++; pmatch[0].rm_eo++; }
1455                         } else {
1456                                 pmatch[0].rm_eo = l;
1457                                 if (s[l]) pmatch[0].rm_eo++;
1458                         }
1459
1460                         memcpy(s1, s, l);
1461                         s1[l] = '\0';
1462                         nextword(&s1);
1463                         s += pmatch[0].rm_eo;
1464                         n++;
1465                 }
1466         } else if (c[0] == '\0') {              /* null split */
1467                 while (*s) {
1468                         *s1++ = *s++;
1469                         *s1++ = '\0';
1470                         n++;
1471                 }
1472         } else if (c[0] != ' ') {               /* single-character split */
1473                 if (icase) {
1474                         c[0] = toupper(c[0]);
1475                         c[1] = tolower(c[1]);
1476                 }
1477                 if (*s1) n++;
1478                 while ((s1 = strpbrk(s1, c))) {
1479                         *s1++ = '\0';
1480                         n++;
1481                 }
1482         } else {                                /* space split */
1483                 while (*s) {
1484                         s = skip_whitespace(s);
1485                         if (!*s) break;
1486                         n++;
1487                         while (*s && !isspace(*s))
1488                                 *s1++ = *s++;
1489                         *s1++ = '\0';
1490                 }
1491         }
1492         return n;
1493 }
1494
1495 static void split_f0(void)
1496 {
1497         static char *fstrings = NULL;
1498         int i, n;
1499         char *s;
1500
1501         if (is_f0_split)
1502                 return;
1503
1504         is_f0_split = TRUE;
1505         free(fstrings);
1506         fsrealloc(0);
1507         n = awk_split(getvar_s(V[F0]), &fsplitter.n, &fstrings);
1508         fsrealloc(n);
1509         s = fstrings;
1510         for (i = 0; i < n; i++) {
1511                 Fields[i].string = nextword(&s);
1512                 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1513         }
1514
1515         /* set NF manually to avoid side effects */
1516         clrvar(V[NF]);
1517         V[NF]->type = VF_NUMBER | VF_SPECIAL;
1518         V[NF]->number = nfields;
1519 }
1520
1521 /* perform additional actions when some internal variables changed */
1522 static void handle_special(var *v)
1523 {
1524         int n;
1525         char *b;
1526         const char *sep, *s;
1527         int sl, l, len, i, bsize;
1528
1529         if (!(v->type & VF_SPECIAL))
1530                 return;
1531
1532         if (v == V[NF]) {
1533                 n = (int)getvar_i(v);
1534                 fsrealloc(n);
1535
1536                 /* recalculate $0 */
1537                 sep = getvar_s(V[OFS]);
1538                 sl = strlen(sep);
1539                 b = NULL;
1540                 len = 0;
1541                 for (i=0; i<n; i++) {
1542                         s = getvar_s(&Fields[i]);
1543                         l = strlen(s);
1544                         if (b) {
1545                                 memcpy(b+len, sep, sl);
1546                                 len += sl;
1547                         }
1548                         qrealloc(&b, len+l+sl, &bsize);
1549                         memcpy(b+len, s, l);
1550                         len += l;
1551                 }
1552                 if (b)
1553                         b[len] = '\0';
1554                 setvar_p(V[F0], b);
1555                 is_f0_split = TRUE;
1556
1557         } else if (v == V[F0]) {
1558                 is_f0_split = FALSE;
1559
1560         } else if (v == V[FS]) {
1561                 mk_splitter(getvar_s(v), &fsplitter);
1562
1563         } else if (v == V[RS]) {
1564                 mk_splitter(getvar_s(v), &rsplitter);
1565
1566         } else if (v == V[IGNORECASE]) {
1567                 icase = istrue(v);
1568
1569         } else {                                /* $n */
1570                 n = getvar_i(V[NF]);
1571                 setvar_i(V[NF], n > v-Fields ? n : v-Fields+1);
1572                 /* right here v is invalid. Just to note... */
1573         }
1574 }
1575
1576 /* step through func/builtin/etc arguments */
1577 static node *nextarg(node **pn)
1578 {
1579         node *n;
1580
1581         n = *pn;
1582         if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1583                 *pn = n->r.n;
1584                 n = n->l.n;
1585         } else {
1586                 *pn = NULL;
1587         }
1588         return n;
1589 }
1590
1591 static void hashwalk_init(var *v, xhash *array)
1592 {
1593         char **w;
1594         hash_item *hi;
1595         int i;
1596
1597         if (v->type & VF_WALK)
1598                 free(v->x.walker);
1599
1600         v->type |= VF_WALK;
1601         w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
1602         *w = *(w+1) = (char *)(w + 2);
1603         for (i=0; i<array->csize; i++) {
1604                 hi = array->items[i];
1605                 while (hi) {
1606                         strcpy(*w, hi->name);
1607                         nextword(w);
1608                         hi = hi->next;
1609                 }
1610         }
1611 }
1612
1613 static int hashwalk_next(var *v)
1614 {
1615         char **w;
1616
1617         w = v->x.walker;
1618         if (*(w+1) == *w)
1619                 return FALSE;
1620
1621         setvar_s(v, nextword(w+1));
1622         return TRUE;
1623 }
1624
1625 /* evaluate node, return 1 when result is true, 0 otherwise */
1626 static int ptest(node *pattern)
1627 {
1628         static var v; /* static: to save stack space? */
1629
1630         return istrue(evaluate(pattern, &v));
1631 }
1632
1633 /* read next record from stream rsm into a variable v */
1634 static int awk_getline(rstream *rsm, var *v)
1635 {
1636         char *b;
1637         regmatch_t pmatch[2];
1638         int a, p, pp=0, size;
1639         int fd, so, eo, r, rp;
1640         char c, *m, *s;
1641
1642         /* we're using our own buffer since we need access to accumulating
1643          * characters
1644          */
1645         fd = fileno(rsm->F);
1646         m = rsm->buffer;
1647         a = rsm->adv;
1648         p = rsm->pos;
1649         size = rsm->size;
1650         c = (char) rsplitter.n.info;
1651         rp = 0;
1652
1653         if (! m) qrealloc(&m, 256, &size);
1654         do {
1655                 b = m + a;
1656                 so = eo = p;
1657                 r = 1;
1658                 if (p > 0) {
1659                         if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1660                                 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
1661                                                                                                 b, 1, pmatch, 0) == 0) {
1662                                         so = pmatch[0].rm_so;
1663                                         eo = pmatch[0].rm_eo;
1664                                         if (b[eo] != '\0')
1665                                                 break;
1666                                 }
1667                         } else if (c != '\0') {
1668                                 s = strchr(b+pp, c);
1669                                 if (! s) s = memchr(b+pp, '\0', p - pp);
1670                                 if (s) {
1671                                         so = eo = s-b;
1672                                         eo++;
1673                                         break;
1674                                 }
1675                         } else {
1676                                 while (b[rp] == '\n')
1677                                         rp++;
1678                                 s = strstr(b+rp, "\n\n");
1679                                 if (s) {
1680                                         so = eo = s-b;
1681                                         while (b[eo] == '\n') eo++;
1682                                         if (b[eo] != '\0')
1683                                                 break;
1684                                 }
1685                         }
1686                 }
1687
1688                 if (a > 0) {
1689                         memmove(m, (const void *)(m+a), p+1);
1690                         b = m;
1691                         a = 0;
1692                 }
1693
1694                 qrealloc(&m, a+p+128, &size);
1695                 b = m + a;
1696                 pp = p;
1697                 p += safe_read(fd, b+p, size-p-1);
1698                 if (p < pp) {
1699                         p = 0;
1700                         r = 0;
1701                         setvar_i(V[ERRNO], errno);
1702                 }
1703                 b[p] = '\0';
1704
1705         } while (p > pp);
1706
1707         if (p == 0) {
1708                 r--;
1709         } else {
1710                 c = b[so]; b[so] = '\0';
1711                 setvar_s(v, b+rp);
1712                 v->type |= VF_USER;
1713                 b[so] = c;
1714                 c = b[eo]; b[eo] = '\0';
1715                 setvar_s(V[RT], b+so);
1716                 b[eo] = c;
1717         }
1718
1719         rsm->buffer = m;
1720         rsm->adv = a + eo;
1721         rsm->pos = p - eo;
1722         rsm->size = size;
1723
1724         return r;
1725 }
1726
1727 static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
1728 {
1729         int r = 0;
1730         char c;
1731         const char *s = format;
1732
1733         if (int_as_int && n == (int)n) {
1734                 r = snprintf(b, size, "%d", (int)n);
1735         } else {
1736                 do { c = *s; } while (c && *++s);
1737                 if (strchr("diouxX", c)) {
1738                         r = snprintf(b, size, format, (int)n);
1739                 } else if (strchr("eEfgG", c)) {
1740                         r = snprintf(b, size, format, n);
1741                 } else {
1742                         runtime_error(EMSG_INV_FMT);
1743                 }
1744         }
1745         return r;
1746 }
1747
1748
1749 /* formatted output into an allocated buffer, return ptr to buffer */
1750 static char *awk_printf(node *n)
1751 {
1752         char *b = NULL;
1753         char *fmt, *s, *f;
1754         const char *s1;
1755         int i, j, incr, bsize;
1756         char c, c1;
1757         var *v, *arg;
1758
1759         v = nvalloc(1);
1760         fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
1761
1762         i = 0;
1763         while (*f) {
1764                 s = f;
1765                 while (*f && (*f != '%' || *(++f) == '%'))
1766                         f++;
1767                 while (*f && !isalpha(*f)) {
1768                         if (*f == '*')
1769                                 syntax_error("%*x formats are not supported");
1770                         f++;
1771                 }
1772
1773                 incr = (f - s) + MAXVARFMT;
1774                 qrealloc(&b, incr + i, &bsize);
1775                 c = *f;
1776                 if (c != '\0') f++;
1777                 c1 = *f;
1778                 *f = '\0';
1779                 arg = evaluate(nextarg(&n), v);
1780
1781                 j = i;
1782                 if (c == 'c' || !c) {
1783                         i += sprintf(b+i, s, is_numeric(arg) ?
1784                                         (char)getvar_i(arg) : *getvar_s(arg));
1785
1786                 } else if (c == 's') {
1787                         s1 = getvar_s(arg);
1788                         qrealloc(&b, incr+i+strlen(s1), &bsize);
1789                         i += sprintf(b+i, s, s1);
1790
1791                 } else {
1792                         i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1793                 }
1794                 *f = c1;
1795
1796                 /* if there was an error while sprintf, return value is negative */
1797                 if (i < j) i = j;
1798         }
1799
1800         b = xrealloc(b, i + 1);
1801         free(fmt);
1802         nvfree(v);
1803         b[i] = '\0';
1804         return b;
1805 }
1806
1807 /* common substitution routine
1808  * replace (nm) substring of (src) that match (n) with (repl), store
1809  * result into (dest), return number of substitutions. If nm=0, replace
1810  * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1811  * subexpression matching (\1-\9)
1812  */
1813 static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
1814 {
1815         char *ds = NULL;
1816         const char *s;
1817         const char *sp;
1818         int c, i, j, di, rl, so, eo, nbs, n, dssize;
1819         regmatch_t pmatch[10];
1820         regex_t sreg, *re;
1821
1822         re = as_regex(rn, &sreg);
1823         if (! src) src = V[F0];
1824         if (! dest) dest = V[F0];
1825
1826         i = di = 0;
1827         sp = getvar_s(src);
1828         rl = strlen(repl);
1829         while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0:REG_NOTBOL) == 0) {
1830                 so = pmatch[0].rm_so;
1831                 eo = pmatch[0].rm_eo;
1832
1833                 qrealloc(&ds, di + eo + rl, &dssize);
1834                 memcpy(ds + di, sp, eo);
1835                 di += eo;
1836                 if (++i >= nm) {
1837                         /* replace */
1838                         di -= (eo - so);
1839                         nbs = 0;
1840                         for (s = repl; *s; s++) {
1841                                 ds[di++] = c = *s;
1842                                 if (c == '\\') {
1843                                         nbs++;
1844                                         continue;
1845                                 }
1846                                 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1847                                         di -= ((nbs + 3) >> 1);
1848                                         j = 0;
1849                                         if (c != '&') {
1850                                                 j = c - '0';
1851                                                 nbs++;
1852                                         }
1853                                         if (nbs % 2) {
1854                                                 ds[di++] = c;
1855                                         } else {
1856                                                 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1857                                                 qrealloc(&ds, di + rl + n, &dssize);
1858                                                 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1859                                                 di += n;
1860                                         }
1861                                 }
1862                                 nbs = 0;
1863                         }
1864                 }
1865
1866                 sp += eo;
1867                 if (i == nm) break;
1868                 if (eo == so) {
1869                         if (! (ds[di++] = *sp++)) break;
1870                 }
1871         }
1872
1873         qrealloc(&ds, di + strlen(sp), &dssize);
1874         strcpy(ds + di, sp);
1875         setvar_p(dest, ds);
1876         if (re == &sreg) regfree(re);
1877         return i;
1878 }
1879
1880 static var *exec_builtin(node *op, var *res)
1881 {
1882         int (*to_xxx)(int);
1883         var *tv;
1884         node *an[4];
1885         var  *av[4];
1886         const char *as[4];
1887         regmatch_t pmatch[2];
1888         regex_t sreg, *re;
1889         static tsplitter tspl;
1890         node *spl;
1891         uint32_t isr, info;
1892         int nargs;
1893         time_t tt;
1894         char *s, *s1;
1895         int i, l, ll, n;
1896
1897         tv = nvalloc(4);
1898         isr = info = op->info;
1899         op = op->l.n;
1900
1901         av[2] = av[3] = NULL;
1902         for (i=0 ; i<4 && op ; i++) {
1903                 an[i] = nextarg(&op);
1904                 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
1905                 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
1906                 isr >>= 1;
1907         }
1908
1909         nargs = i;
1910         if (nargs < (info >> 30))
1911                 runtime_error(EMSG_TOO_FEW_ARGS);
1912
1913         switch (info & OPNMASK) {
1914
1915         case B_a2:
1916 #if ENABLE_FEATURE_AWK_MATH
1917                 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
1918 #else
1919                 runtime_error(EMSG_NO_MATH);
1920 #endif
1921                 break;
1922
1923         case B_sp:
1924                 if (nargs > 2) {
1925                         spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
1926                                 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
1927                 } else {
1928                         spl = &fsplitter.n;
1929                 }
1930
1931                 n = awk_split(as[0], spl, &s);
1932                 s1 = s;
1933                 clear_array(iamarray(av[1]));
1934                 for (i=1; i<=n; i++)
1935                         setari_u(av[1], i, nextword(&s1));
1936                 free(s);
1937                 setvar_i(res, n);
1938                 break;
1939
1940         case B_ss:
1941                 l = strlen(as[0]);
1942                 i = getvar_i(av[1]) - 1;
1943                 if (i>l) i=l; if (i<0) i=0;
1944                 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
1945                 if (n<0) n=0;
1946                 s = xmalloc(n+1);
1947                 strncpy(s, as[0]+i, n);
1948                 s[n] = '\0';
1949                 setvar_p(res, s);
1950                 break;
1951
1952         case B_an:
1953                 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
1954                 break;
1955
1956         case B_co:
1957                 setvar_i(res, ~(long)getvar_i(av[0]));
1958                 break;
1959
1960         case B_ls:
1961                 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
1962                 break;
1963
1964         case B_or:
1965                 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
1966                 break;
1967
1968         case B_rs:
1969                 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
1970                 break;
1971
1972         case B_xo:
1973                 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
1974                 break;
1975
1976         case B_lo:
1977                 to_xxx = tolower;
1978                 goto lo_cont;
1979
1980         case B_up:
1981                 to_xxx = toupper;
1982  lo_cont:
1983                 s1 = s = xstrdup(as[0]);
1984                 while (*s1) {
1985                         *s1 = (*to_xxx)(*s1);
1986                         s1++;
1987                 }
1988                 setvar_p(res, s);
1989                 break;
1990
1991         case B_ix:
1992                 n = 0;
1993                 ll = strlen(as[1]);
1994                 l = strlen(as[0]) - ll;
1995                 if (ll > 0 && l >= 0) {
1996                         if (! icase) {
1997                                 s = strstr(as[0], as[1]);
1998                                 if (s) n = (s - as[0]) + 1;
1999                         } else {
2000                                 /* this piece of code is terribly slow and
2001                                  * really should be rewritten
2002                                  */
2003                                 for (i=0; i<=l; i++) {
2004                                         if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2005                                                 n = i+1;
2006                                                 break;
2007                                         }
2008                                 }
2009                         }
2010                 }
2011                 setvar_i(res, n);
2012                 break;
2013
2014         case B_ti:
2015                 if (nargs > 1)
2016                         tt = getvar_i(av[1]);
2017                 else
2018                         time(&tt);
2019                 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
2020                 i = strftime(buf, MAXVARFMT,
2021                         ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2022                         localtime(&tt));
2023                 buf[i] = '\0';
2024                 setvar_s(res, buf);
2025                 break;
2026
2027         case B_ma:
2028                 re = as_regex(an[1], &sreg);
2029                 n = regexec(re, as[0], 1, pmatch, 0);
2030                 if (n == 0) {
2031                         pmatch[0].rm_so++;
2032                         pmatch[0].rm_eo++;
2033                 } else {
2034                         pmatch[0].rm_so = 0;
2035                         pmatch[0].rm_eo = -1;
2036                 }
2037                 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2038                 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2039                 setvar_i(res, pmatch[0].rm_so);
2040                 if (re == &sreg) regfree(re);
2041                 break;
2042
2043         case B_ge:
2044                 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2045                 break;
2046
2047         case B_gs:
2048                 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2049                 break;
2050
2051         case B_su:
2052                 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2053                 break;
2054         }
2055
2056         nvfree(tv);
2057         return res;
2058 }
2059
2060 /*
2061  * Evaluate node - the heart of the program. Supplied with subtree
2062  * and place where to store result. returns ptr to result.
2063  */
2064 #define XC(n) ((n) >> 8)
2065
2066 static var *evaluate(node *op, var *res)
2067 {
2068         /* This procedure is recursive so we should count every byte */
2069         static var *fnargs = NULL;
2070         static unsigned seed = 1;
2071         static regex_t sreg;
2072
2073         node *op1;
2074         var *v1;
2075         union {
2076                 var *v;
2077                 const char *s;
2078                 double d;
2079                 int i;
2080         } L, R;
2081         uint32_t opinfo;
2082         short opn;
2083         union {
2084                 char *s;
2085                 rstream *rsm;
2086                 FILE *F;
2087                 var *v;
2088                 regex_t *re;
2089                 uint32_t info;
2090         } X;
2091
2092         if (!op)
2093                 return setvar_s(res, NULL);
2094
2095         v1 = nvalloc(2);
2096
2097         while (op) {
2098                 opinfo = op->info;
2099                 opn = (short)(opinfo & OPNMASK);
2100                 lineno = op->lineno;
2101
2102                 /* execute inevitable things */
2103                 op1 = op->l.n;
2104                 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2105                 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2106                 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2107                 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2108                 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2109
2110                 switch (XC(opinfo & OPCLSMASK)) {
2111
2112                 /* -- iterative node type -- */
2113
2114                 /* test pattern */
2115                 case XC( OC_TEST ):
2116                         if ((op1->info & OPCLSMASK) == OC_COMMA) {
2117                                 /* it's range pattern */
2118                                 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2119                                         op->info |= OF_CHECKED;
2120                                         if (ptest(op1->r.n))
2121                                                 op->info &= ~OF_CHECKED;
2122
2123                                         op = op->a.n;
2124                                 } else {
2125                                         op = op->r.n;
2126                                 }
2127                         } else {
2128                                 op = (ptest(op1)) ? op->a.n : op->r.n;
2129                         }
2130                         break;
2131
2132                 /* just evaluate an expression, also used as unconditional jump */
2133                 case XC( OC_EXEC ):
2134                         break;
2135
2136                 /* branch, used in if-else and various loops */
2137                 case XC( OC_BR ):
2138                         op = istrue(L.v) ? op->a.n : op->r.n;
2139                         break;
2140
2141                 /* initialize for-in loop */
2142                 case XC( OC_WALKINIT ):
2143                         hashwalk_init(L.v, iamarray(R.v));
2144                         break;
2145
2146                 /* get next array item */
2147                 case XC( OC_WALKNEXT ):
2148                         op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2149                         break;
2150
2151                 case XC( OC_PRINT ):
2152                 case XC( OC_PRINTF ):
2153                         X.F = stdout;
2154                         if (op->r.n) {
2155                                 X.rsm = newfile(R.s);
2156                                 if (! X.rsm->F) {
2157                                         if (opn == '|') {
2158                                                 X.rsm->F = popen(R.s, "w");
2159                                                 if (X.rsm->F == NULL)
2160                                                         bb_perror_msg_and_die("popen");
2161                                                 X.rsm->is_pipe = 1;
2162                                         } else {
2163                                                 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
2164                                         }
2165                                 }
2166                                 X.F = X.rsm->F;
2167                         }
2168
2169                         if ((opinfo & OPCLSMASK) == OC_PRINT) {
2170                                 if (! op1) {
2171                                         fputs(getvar_s(V[F0]), X.F);
2172                                 } else {
2173                                         while (op1) {
2174                                                 L.v = evaluate(nextarg(&op1), v1);
2175                                                 if (L.v->type & VF_NUMBER) {
2176                                                         fmt_num(buf, MAXVARFMT, getvar_s(V[OFMT]),
2177                                                                         getvar_i(L.v), TRUE);
2178                                                         fputs(buf, X.F);
2179                                                 } else {
2180                                                         fputs(getvar_s(L.v), X.F);
2181                                                 }
2182
2183                                                 if (op1) fputs(getvar_s(V[OFS]), X.F);
2184                                         }
2185                                 }
2186                                 fputs(getvar_s(V[ORS]), X.F);
2187
2188                         } else {        /* OC_PRINTF */
2189                                 L.s = awk_printf(op1);
2190                                 fputs(L.s, X.F);
2191                                 free((char*)L.s);
2192                         }
2193                         fflush(X.F);
2194                         break;
2195
2196                 case XC( OC_DELETE ):
2197                         X.info = op1->info & OPCLSMASK;
2198                         if (X.info == OC_VAR) {
2199                                 R.v = op1->l.v;
2200                         } else if (X.info == OC_FNARG) {
2201                                 R.v = &fnargs[op1->l.i];
2202                         } else {
2203                                 runtime_error(EMSG_NOT_ARRAY);
2204                         }
2205
2206                         if (op1->r.n) {
2207                                 clrvar(L.v);
2208                                 L.s = getvar_s(evaluate(op1->r.n, v1));
2209                                 hash_remove(iamarray(R.v), L.s);
2210                         } else {
2211                                 clear_array(iamarray(R.v));
2212                         }
2213                         break;
2214
2215                 case XC( OC_NEWSOURCE ):
2216                         programname = op->l.s;
2217                         break;
2218
2219                 case XC( OC_RETURN ):
2220                         copyvar(res, L.v);
2221                         break;
2222
2223                 case XC( OC_NEXTFILE ):
2224                         nextfile = TRUE;
2225                 case XC( OC_NEXT ):
2226                         nextrec = TRUE;
2227                 case XC( OC_DONE ):
2228                         clrvar(res);
2229                         break;
2230
2231                 case XC( OC_EXIT ):
2232                         awk_exit(L.d);
2233
2234                 /* -- recursive node type -- */
2235
2236                 case XC( OC_VAR ):
2237                         L.v = op->l.v;
2238                         if (L.v == V[NF])
2239                                 split_f0();
2240                         goto v_cont;
2241
2242                 case XC( OC_FNARG ):
2243                         L.v = &fnargs[op->l.i];
2244  v_cont:
2245                         res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
2246                         break;
2247
2248                 case XC( OC_IN ):
2249                         setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2250                         break;
2251
2252                 case XC( OC_REGEXP ):
2253                         op1 = op;
2254                         L.s = getvar_s(V[F0]);
2255                         goto re_cont;
2256
2257                 case XC( OC_MATCH ):
2258                         op1 = op->r.n;
2259  re_cont:
2260                         X.re = as_regex(op1, &sreg);
2261                         R.i = regexec(X.re, L.s, 0, NULL, 0);
2262                         if (X.re == &sreg) regfree(X.re);
2263                         setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2264                         break;
2265
2266                 case XC( OC_MOVE ):
2267                         /* if source is a temporary string, jusk relink it to dest */
2268                         if (R.v == v1+1 && R.v->string) {
2269                                 res = setvar_p(L.v, R.v->string);
2270                                 R.v->string = NULL;
2271                         } else {
2272                                 res = copyvar(L.v, R.v);
2273                         }
2274                         break;
2275
2276                 case XC( OC_TERNARY ):
2277                         if ((op->r.n->info & OPCLSMASK) != OC_COLON)
2278                                 runtime_error(EMSG_POSSIBLE_ERROR);
2279                         res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2280                         break;
2281
2282                 case XC( OC_FUNC ):
2283                         if (! op->r.f->body.first)
2284                                 runtime_error(EMSG_UNDEF_FUNC);
2285
2286                         X.v = R.v = nvalloc(op->r.f->nargs+1);
2287                         while (op1) {
2288                                 L.v = evaluate(nextarg(&op1), v1);
2289                                 copyvar(R.v, L.v);
2290                                 R.v->type |= VF_CHILD;
2291                                 R.v->x.parent = L.v;
2292                                 if (++R.v - X.v >= op->r.f->nargs)
2293                                         break;
2294                         }
2295
2296                         R.v = fnargs;
2297                         fnargs = X.v;
2298
2299                         L.s = programname;
2300                         res = evaluate(op->r.f->body.first, res);
2301                         programname = L.s;
2302
2303                         nvfree(fnargs);
2304                         fnargs = R.v;
2305                         break;
2306
2307                 case XC( OC_GETLINE ):
2308                 case XC( OC_PGETLINE ):
2309                         if (op1) {
2310                                 X.rsm = newfile(L.s);
2311                                 if (! X.rsm->F) {
2312                                         if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2313                                                 X.rsm->F = popen(L.s, "r");
2314                                                 X.rsm->is_pipe = TRUE;
2315                                         } else {
2316                                                 X.rsm->F = fopen(L.s, "r");             /* not xfopen! */
2317                                         }
2318                                 }
2319                         } else {
2320                                 if (! iF) iF = next_input_file();
2321                                 X.rsm = iF;
2322                         }
2323
2324                         if (! X.rsm->F) {
2325                                 setvar_i(V[ERRNO], errno);
2326                                 setvar_i(res, -1);
2327                                 break;
2328                         }
2329
2330                         if (! op->r.n)
2331                                 R.v = V[F0];
2332
2333                         L.i = awk_getline(X.rsm, R.v);
2334                         if (L.i > 0) {
2335                                 if (! op1) {
2336                                         incvar(V[FNR]);
2337                                         incvar(V[NR]);
2338                                 }
2339                         }
2340                         setvar_i(res, L.i);
2341                         break;
2342
2343                 /* simple builtins */
2344                 case XC( OC_FBLTIN ):
2345                         switch (opn) {
2346
2347                         case F_in:
2348                                 R.d = (int)L.d;
2349                                 break;
2350
2351                         case F_rn:
2352                                 R.d = (double)rand() / (double)RAND_MAX;
2353                                 break;
2354 #if ENABLE_FEATURE_AWK_MATH
2355                         case F_co:
2356                                 R.d = cos(L.d);
2357                                 break;
2358
2359                         case F_ex:
2360                                 R.d = exp(L.d);
2361                                 break;
2362
2363                         case F_lg:
2364                                 R.d = log(L.d);
2365                                 break;
2366
2367                         case F_si:
2368                                 R.d = sin(L.d);
2369                                 break;
2370
2371                         case F_sq:
2372                                 R.d = sqrt(L.d);
2373                                 break;
2374 #else
2375                         case F_co:
2376                         case F_ex:
2377                         case F_lg:
2378                         case F_si:
2379                         case F_sq:
2380                                 runtime_error(EMSG_NO_MATH);
2381                                 break;
2382 #endif
2383                         case F_sr:
2384                                 R.d = (double)seed;
2385                                 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
2386                                 srand(seed);
2387                                 break;
2388
2389                         case F_ti:
2390                                 R.d = time(NULL);
2391                                 break;
2392
2393                         case F_le:
2394                                 if (! op1)
2395                                         L.s = getvar_s(V[F0]);
2396                                 R.d = strlen(L.s);
2397                                 break;
2398
2399                         case F_sy:
2400                                 fflush(NULL);
2401                                 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2402                                                 ? (system(L.s) >> 8) : 0;
2403                                 break;
2404
2405                         case F_ff:
2406                                 if (! op1)
2407                                         fflush(stdout);
2408                                 else {
2409                                         if (L.s && *L.s) {
2410                                                 X.rsm = newfile(L.s);
2411                                                 fflush(X.rsm->F);
2412                                         } else {
2413                                                 fflush(NULL);
2414                                         }
2415                                 }
2416                                 break;
2417
2418                         case F_cl:
2419                                 X.rsm = (rstream *)hash_search(fdhash, L.s);
2420                                 if (X.rsm) {
2421                                         R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
2422                                         free(X.rsm->buffer);
2423                                         hash_remove(fdhash, L.s);
2424                                 }
2425                                 if (R.i != 0)
2426                                         setvar_i(V[ERRNO], errno);
2427                                 R.d = (double)R.i;
2428                                 break;
2429                         }
2430                         setvar_i(res, R.d);
2431                         break;
2432
2433                 case XC( OC_BUILTIN ):
2434                         res = exec_builtin(op, res);
2435                         break;
2436
2437                 case XC( OC_SPRINTF ):
2438                         setvar_p(res, awk_printf(op1));
2439                         break;
2440
2441                 case XC( OC_UNARY ):
2442                         X.v = R.v;
2443                         L.d = R.d = getvar_i(R.v);
2444                         switch (opn) {
2445                         case 'P':
2446                                 L.d = ++R.d;
2447                                 goto r_op_change;
2448                         case 'p':
2449                                 R.d++;
2450                                 goto r_op_change;
2451                         case 'M':
2452                                 L.d = --R.d;
2453                                 goto r_op_change;
2454                         case 'm':
2455                                 R.d--;
2456                                 goto r_op_change;
2457                         case '!':
2458                                 L.d = istrue(X.v) ? 0 : 1;
2459                                 break;
2460                         case '-':
2461                                 L.d = -R.d;
2462                                 break;
2463  r_op_change:
2464                                 setvar_i(X.v, R.d);
2465                         }
2466                         setvar_i(res, L.d);
2467                         break;
2468
2469                 case XC( OC_FIELD ):
2470                         R.i = (int)getvar_i(R.v);
2471                         if (R.i == 0) {
2472                                 res = V[F0];
2473                         } else {
2474                                 split_f0();
2475                                 if (R.i > nfields)
2476                                         fsrealloc(R.i);
2477
2478                                 res = &Fields[R.i-1];
2479                         }
2480                         break;
2481
2482                 /* concatenation (" ") and index joining (",") */
2483                 case XC( OC_CONCAT ):
2484                 case XC( OC_COMMA ):
2485                         opn = strlen(L.s) + strlen(R.s) + 2;
2486                         X.s = xmalloc(opn);
2487                         strcpy(X.s, L.s);
2488                         if ((opinfo & OPCLSMASK) == OC_COMMA) {
2489                                 L.s = getvar_s(V[SUBSEP]);
2490                                 X.s = xrealloc(X.s, opn + strlen(L.s));
2491                                 strcat(X.s, L.s);
2492                         }
2493                         strcat(X.s, R.s);
2494                         setvar_p(res, X.s);
2495                         break;
2496
2497                 case XC( OC_LAND ):
2498                         setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2499                         break;
2500
2501                 case XC( OC_LOR ):
2502                         setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2503                         break;
2504
2505                 case XC( OC_BINARY ):
2506                 case XC( OC_REPLACE ):
2507                         R.d = getvar_i(R.v);
2508                         switch (opn) {
2509                         case '+':
2510                                 L.d += R.d;
2511                                 break;
2512                         case '-':
2513                                 L.d -= R.d;
2514                                 break;
2515                         case '*':
2516                                 L.d *= R.d;
2517                                 break;
2518                         case '/':
2519                                 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2520                                 L.d /= R.d;
2521                                 break;
2522                         case '&':
2523 #if ENABLE_FEATURE_AWK_MATH
2524                                 L.d = pow(L.d, R.d);
2525 #else
2526                                 runtime_error(EMSG_NO_MATH);
2527 #endif
2528                                 break;
2529                         case '%':
2530                                 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2531                                 L.d -= (int)(L.d / R.d) * R.d;
2532                                 break;
2533                         }
2534                         res = setvar_i(((opinfo&OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
2535                         break;
2536
2537                 case XC( OC_COMPARE ):
2538                         if (is_numeric(L.v) && is_numeric(R.v)) {
2539                                 L.d = getvar_i(L.v) - getvar_i(R.v);
2540                         } else {
2541                                 L.s = getvar_s(L.v);
2542                                 R.s = getvar_s(R.v);
2543                                 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2544                         }
2545                         switch (opn & 0xfe) {
2546                         case 0:
2547                                 R.i = (L.d > 0);
2548                                 break;
2549                         case 2:
2550                                 R.i = (L.d >= 0);
2551                                 break;
2552                         case 4:
2553                                 R.i = (L.d == 0);
2554                                 break;
2555                         }
2556                         setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2557                         break;
2558
2559                 default:
2560                         runtime_error(EMSG_POSSIBLE_ERROR);
2561                 }
2562                 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2563                         op = op->a.n;
2564                 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2565                         break;
2566                 if (nextrec)
2567                         break;
2568         }
2569         nvfree(v1);
2570         return res;
2571 }
2572
2573
2574 /* -------- main & co. -------- */
2575
2576 static int awk_exit(int r)
2577 {
2578         var tv;
2579         unsigned i;
2580         hash_item *hi;
2581
2582         zero_out_var(&tv);
2583
2584         if (!exiting) {
2585                 exiting = TRUE;
2586                 nextrec = FALSE;
2587                 evaluate(endseq.first, &tv);
2588         }
2589
2590         /* waiting for children */
2591         for (i = 0; i < fdhash->csize; i++) {
2592                 hi = fdhash->items[i];
2593                 while (hi) {
2594                         if (hi->data.rs.F && hi->data.rs.is_pipe)
2595                                 pclose(hi->data.rs.F);
2596                         hi = hi->next;
2597                 }
2598         }
2599
2600         exit(r);
2601 }
2602
2603 /* if expr looks like "var=value", perform assignment and return 1,
2604  * otherwise return 0 */
2605 static int is_assignment(const char *expr)
2606 {
2607         char *exprc, *s, *s0, *s1;
2608
2609         exprc = xstrdup(expr);
2610         if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2611                 free(exprc);
2612                 return FALSE;
2613         }
2614
2615         *(s++) = '\0';
2616         s0 = s1 = s;
2617         while (*s)
2618                 *(s1++) = nextchar(&s);
2619
2620         *s1 = '\0';
2621         setvar_u(newvar(exprc), s0);
2622         free(exprc);
2623         return TRUE;
2624 }
2625
2626 /* switch to next input file */
2627 static rstream *next_input_file(void)
2628 {
2629         static rstream rsm;
2630         FILE *F = NULL;
2631         const char *fname, *ind;
2632         static int files_happen = FALSE;
2633
2634         if (rsm.F) fclose(rsm.F);
2635         rsm.F = NULL;
2636         rsm.pos = rsm.adv = 0;
2637
2638         do {
2639                 if (getvar_i(V[ARGIND])+1 >= getvar_i(V[ARGC])) {
2640                         if (files_happen)
2641                                 return NULL;
2642                         fname = "-";
2643                         F = stdin;
2644                 } else {
2645                         ind = getvar_s(incvar(V[ARGIND]));
2646                         fname = getvar_s(findvar(iamarray(V[ARGV]), ind));
2647                         if (fname && *fname && !is_assignment(fname))
2648                                 F = afopen(fname, "r");
2649                 }
2650         } while (!F);
2651
2652         files_happen = TRUE;
2653         setvar_s(V[FILENAME], fname);
2654         rsm.F = F;
2655         return &rsm;
2656 }
2657
2658 int awk_main(int argc, char **argv);
2659 int awk_main(int argc, char **argv)
2660 {
2661         unsigned opt;
2662         char *opt_F, *opt_W;
2663         llist_t *opt_v = NULL;
2664         int i, j, flen;
2665         var *v;
2666         var tv;
2667         char **envp;
2668         char *vnames = (char *)vNames; /* cheat */
2669         char *vvalues = (char *)vValues;
2670
2671         /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
2672          * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2673         if (ENABLE_LOCALE_SUPPORT)
2674                 setlocale(LC_NUMERIC, "C");
2675
2676         zero_out_var(&tv);
2677
2678         /* allocate global buffer */
2679         buf = xmalloc(MAXVARFMT + 1);
2680
2681         vhash = hash_init();
2682         ahash = hash_init();
2683         fdhash = hash_init();
2684         fnhash = hash_init();
2685
2686         /* initialize variables */
2687         for (i = 0; *vnames; i++) {
2688                 V[i] = v = newvar(nextword(&vnames));
2689                 if (*vvalues != '\377')
2690                         setvar_s(v, nextword(&vvalues));
2691                 else
2692                         setvar_i(v, 0);
2693
2694                 if (*vnames == '*') {
2695                         v->type |= VF_SPECIAL;
2696                         vnames++;
2697                 }
2698         }
2699
2700         handle_special(V[FS]);
2701         handle_special(V[RS]);
2702
2703         newfile("/dev/stdin")->F = stdin;
2704         newfile("/dev/stdout")->F = stdout;
2705         newfile("/dev/stderr")->F = stderr;
2706
2707         /* Huh, people report that sometimes environ is NULL. Oh well. */
2708         if (environ) for (envp = environ; *envp; envp++) {
2709                 char *s = xstrdup(*envp);
2710                 char *s1 = strchr(s, '=');
2711                 if (s1) {
2712                         *s1++ = '\0';
2713                         setvar_u(findvar(iamarray(V[ENVIRON]), s), s1);
2714                 }
2715                 free(s);
2716         }
2717         opt_complementary = "v::";
2718         opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &programname, &opt_W);
2719         argv += optind;
2720         argc -= optind;
2721         if (opt & 0x1) setvar_s(V[FS], opt_F); // -F
2722         while (opt_v) { /* -v */
2723                 if (!is_assignment(llist_pop(&opt_v)))
2724                         bb_show_usage();
2725         }
2726         if (opt & 0x4) { // -f
2727                 char *s = s; /* die, gcc, die */
2728                 FILE *from_file = afopen(programname, "r");
2729                 /* one byte is reserved for some trick in next_token */
2730                 if (fseek(from_file, 0, SEEK_END) == 0) {
2731                         flen = ftell(from_file);
2732                         s = xmalloc(flen + 4);
2733                         fseek(from_file, 0, SEEK_SET);
2734                         i = 1 + fread(s + 1, 1, flen, from_file);
2735                 } else {
2736                         for (i = j = 1; j > 0; i += j) {
2737                                 s = xrealloc(s, i + 4096);
2738                                 j = fread(s + i, 1, 4094, from_file);
2739                         }
2740                 }
2741                 s[i] = '\0';
2742                 fclose(from_file);
2743                 parse_program(s + 1);
2744                 free(s);
2745         } else { // no -f: take program from 1st parameter
2746                 if (!argc)
2747                         bb_show_usage();
2748                 programname = "cmd. line";
2749                 parse_program(*argv++);
2750                 argc--;
2751         }
2752         if (opt & 0x8) // -W
2753                 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
2754
2755         /* fill in ARGV array */
2756         setvar_i(V[ARGC], argc + 1);
2757         setari_u(V[ARGV], 0, "awk");
2758         i = 0;
2759         while (*argv)
2760                 setari_u(V[ARGV], ++i, *argv++);
2761
2762         evaluate(beginseq.first, &tv);
2763         if (!mainseq.first && !endseq.first)
2764                 awk_exit(EXIT_SUCCESS);
2765
2766         /* input file could already be opened in BEGIN block */
2767         if (!iF) iF = next_input_file();
2768
2769         /* passing through input files */
2770         while (iF) {
2771                 nextfile = FALSE;
2772                 setvar_i(V[FNR], 0);
2773
2774                 while ((i = awk_getline(iF, V[F0])) > 0) {
2775                         nextrec = FALSE;
2776                         incvar(V[NR]);
2777                         incvar(V[FNR]);
2778                         evaluate(mainseq.first, &tv);
2779
2780                         if (nextfile)
2781                                 break;
2782                 }
2783
2784                 if (i < 0)
2785                         runtime_error(strerror(errno));
2786
2787                 iF = next_input_file();
2788         }
2789
2790         awk_exit(EXIT_SUCCESS);
2791         /*return 0;*/
2792 }