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