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