style fixes. No code changes
[platform/upstream/busybox.git] / editors / awk.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * awk implementation for busybox
4  *
5  * Copyright (C) 2002 by Dmitry Zakharov <dmit@crp.bank.gov.ua>
6  *
7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8  */
9
10 #include "busybox.h"
11 #include "xregex.h"
12 #include <math.h>
13
14 /* This is a NOEXEC applet. Be very careful! */
15
16
17 #define MAXVARFMT       240
18 #define MINNVBLOCK      64
19
20 /* variable flags */
21 #define VF_NUMBER       0x0001  /* 1 = primary type is number */
22 #define VF_ARRAY        0x0002  /* 1 = it's an array */
23
24 #define VF_CACHED       0x0100  /* 1 = num/str value has cached str/num eq */
25 #define VF_USER         0x0200  /* 1 = user input (may be numeric string) */
26 #define VF_SPECIAL      0x0400  /* 1 = requires extra handling when changed */
27 #define VF_WALK         0x0800  /* 1 = variable has alloc'd x.walker list */
28 #define VF_FSTR         0x1000  /* 1 = var::string points to fstring buffer */
29 #define VF_CHILD        0x2000  /* 1 = function arg; x.parent points to source */
30 #define VF_DIRTY        0x4000  /* 1 = variable was set explicitly */
31
32 /* these flags are static, don't change them when value is changed */
33 #define VF_DONTTOUCH    (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
34
35 /* Variable */
36 typedef struct var_s {
37         unsigned short type;            /* flags */
38         double number;
39         char *string;
40         union {
41                 int aidx;               /* func arg idx (for compilation stage) */
42                 struct xhash_s *array;  /* array ptr */
43                 struct var_s *parent;   /* for func args, ptr to actual parameter */
44                 char **walker;          /* list of array elements (for..in) */
45         } x;
46 } var;
47
48 /* Node chain (pattern-action chain, BEGIN, END, function bodies) */
49 typedef struct chain_s {
50         struct node_s *first;
51         struct node_s *last;
52         const char *programname;
53 } chain;
54
55 /* Function */
56 typedef struct func_s {
57         unsigned short nargs;
58         struct chain_s body;
59 } func;
60
61 /* I/O stream */
62 typedef struct rstream_s {
63         FILE *F;
64         char *buffer;
65         int adv;
66         int size;
67         int pos;
68         unsigned short is_pipe;
69 } rstream;
70
71 typedef struct hash_item_s {
72         union {
73                 struct var_s v;                 /* variable/array hash */
74                 struct rstream_s rs;    /* redirect streams hash */
75                 struct func_s f;                /* functions hash */
76         } data;
77         struct hash_item_s *next;       /* next in chain */
78         char name[1];                           /* really it's longer */
79 } hash_item;
80
81 typedef struct xhash_s {
82         unsigned nel;                                   /* num of elements */
83         unsigned csize;                                 /* current hash size */
84         unsigned nprime;                                /* next hash size in PRIMES[] */
85         unsigned glen;                                  /* summary length of item names */
86         struct hash_item_s **items;
87 } xhash;
88
89 /* Tree node */
90 typedef struct node_s {
91         uint32_t info;
92         unsigned 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                         f++;
1761
1762                 incr = (f - s) + MAXVARFMT;
1763                 qrealloc(&b, incr + i, &bsize);
1764                 c = *f;
1765                 if (c != '\0') f++;
1766                 c1 = *f;
1767                 *f = '\0';
1768                 arg = evaluate(nextarg(&n), v);
1769
1770                 j = i;
1771                 if (c == 'c' || !c) {
1772                         i += sprintf(b+i, s, is_numeric(arg) ?
1773                                         (char)getvar_i(arg) : *getvar_s(arg));
1774
1775                 } else if (c == 's') {
1776                         s1 = getvar_s(arg);
1777                         qrealloc(&b, incr+i+strlen(s1), &bsize);
1778                         i += sprintf(b+i, s, s1);
1779
1780                 } else {
1781                         i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1782                 }
1783                 *f = c1;
1784
1785                 /* if there was an error while sprintf, return value is negative */
1786                 if (i < j) i = j;
1787         }
1788
1789         b = xrealloc(b, i + 1);
1790         free(fmt);
1791         nvfree(v);
1792         b[i] = '\0';
1793         return b;
1794 }
1795
1796 /* common substitution routine
1797  * replace (nm) substring of (src) that match (n) with (repl), store
1798  * result into (dest), return number of substitutions. If nm=0, replace
1799  * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1800  * subexpression matching (\1-\9)
1801  */
1802 static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
1803 {
1804         char *ds = NULL;
1805         const char *s;
1806         const char *sp;
1807         int c, i, j, di, rl, so, eo, nbs, n, dssize;
1808         regmatch_t pmatch[10];
1809         regex_t sreg, *re;
1810
1811         re = as_regex(rn, &sreg);
1812         if (! src) src = V[F0];
1813         if (! dest) dest = V[F0];
1814
1815         i = di = 0;
1816         sp = getvar_s(src);
1817         rl = strlen(repl);
1818         while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0:REG_NOTBOL) == 0) {
1819                 so = pmatch[0].rm_so;
1820                 eo = pmatch[0].rm_eo;
1821
1822                 qrealloc(&ds, di + eo + rl, &dssize);
1823                 memcpy(ds + di, sp, eo);
1824                 di += eo;
1825                 if (++i >= nm) {
1826                         /* replace */
1827                         di -= (eo - so);
1828                         nbs = 0;
1829                         for (s = repl; *s; s++) {
1830                                 ds[di++] = c = *s;
1831                                 if (c == '\\') {
1832                                         nbs++;
1833                                         continue;
1834                                 }
1835                                 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1836                                         di -= ((nbs + 3) >> 1);
1837                                         j = 0;
1838                                         if (c != '&') {
1839                                                 j = c - '0';
1840                                                 nbs++;
1841                                         }
1842                                         if (nbs % 2) {
1843                                                 ds[di++] = c;
1844                                         } else {
1845                                                 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1846                                                 qrealloc(&ds, di + rl + n, &dssize);
1847                                                 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1848                                                 di += n;
1849                                         }
1850                                 }
1851                                 nbs = 0;
1852                         }
1853                 }
1854
1855                 sp += eo;
1856                 if (i == nm) break;
1857                 if (eo == so) {
1858                         if (! (ds[di++] = *sp++)) break;
1859                 }
1860         }
1861
1862         qrealloc(&ds, di + strlen(sp), &dssize);
1863         strcpy(ds + di, sp);
1864         setvar_p(dest, ds);
1865         if (re == &sreg) regfree(re);
1866         return i;
1867 }
1868
1869 static var *exec_builtin(node *op, var *res)
1870 {
1871         int (*to_xxx)(int);
1872         var *tv;
1873         node *an[4];
1874         var  *av[4];
1875         const char *as[4];
1876         regmatch_t pmatch[2];
1877         regex_t sreg, *re;
1878         static tsplitter tspl;
1879         node *spl;
1880         uint32_t isr, info;
1881         int nargs;
1882         time_t tt;
1883         char *s, *s1;
1884         int i, l, ll, n;
1885
1886         tv = nvalloc(4);
1887         isr = info = op->info;
1888         op = op->l.n;
1889
1890         av[2] = av[3] = NULL;
1891         for (i=0 ; i<4 && op ; i++) {
1892                 an[i] = nextarg(&op);
1893                 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
1894                 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
1895                 isr >>= 1;
1896         }
1897
1898         nargs = i;
1899         if (nargs < (info >> 30))
1900                 runtime_error(EMSG_TOO_FEW_ARGS);
1901
1902         switch (info & OPNMASK) {
1903
1904         case B_a2:
1905 #if ENABLE_FEATURE_AWK_MATH
1906                 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
1907 #else
1908                 runtime_error(EMSG_NO_MATH);
1909 #endif
1910                 break;
1911
1912         case B_sp:
1913                 if (nargs > 2) {
1914                         spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
1915                                 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
1916                 } else {
1917                         spl = &fsplitter.n;
1918                 }
1919
1920                 n = awk_split(as[0], spl, &s);
1921                 s1 = s;
1922                 clear_array(iamarray(av[1]));
1923                 for (i=1; i<=n; i++)
1924                         setari_u(av[1], i, nextword(&s1));
1925                 free(s);
1926                 setvar_i(res, n);
1927                 break;
1928
1929         case B_ss:
1930                 l = strlen(as[0]);
1931                 i = getvar_i(av[1]) - 1;
1932                 if (i>l) i=l; if (i<0) i=0;
1933                 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
1934                 if (n<0) n=0;
1935                 s = xmalloc(n+1);
1936                 strncpy(s, as[0]+i, n);
1937                 s[n] = '\0';
1938                 setvar_p(res, s);
1939                 break;
1940
1941         case B_an:
1942                 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
1943                 break;
1944
1945         case B_co:
1946                 setvar_i(res, ~(long)getvar_i(av[0]));
1947                 break;
1948
1949         case B_ls:
1950                 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
1951                 break;
1952
1953         case B_or:
1954                 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
1955                 break;
1956
1957         case B_rs:
1958                 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
1959                 break;
1960
1961         case B_xo:
1962                 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
1963                 break;
1964
1965         case B_lo:
1966                 to_xxx = tolower;
1967                 goto lo_cont;
1968
1969         case B_up:
1970                 to_xxx = toupper;
1971  lo_cont:
1972                 s1 = s = xstrdup(as[0]);
1973                 while (*s1) {
1974                         *s1 = (*to_xxx)(*s1);
1975                         s1++;
1976                 }
1977                 setvar_p(res, s);
1978                 break;
1979
1980         case B_ix:
1981                 n = 0;
1982                 ll = strlen(as[1]);
1983                 l = strlen(as[0]) - ll;
1984                 if (ll > 0 && l >= 0) {
1985                         if (! icase) {
1986                                 s = strstr(as[0], as[1]);
1987                                 if (s) n = (s - as[0]) + 1;
1988                         } else {
1989                                 /* this piece of code is terribly slow and
1990                                  * really should be rewritten
1991                                  */
1992                                 for (i=0; i<=l; i++) {
1993                                         if (strncasecmp(as[0]+i, as[1], ll) == 0) {
1994                                                 n = i+1;
1995                                                 break;
1996                                         }
1997                                 }
1998                         }
1999                 }
2000                 setvar_i(res, n);
2001                 break;
2002
2003         case B_ti:
2004                 if (nargs > 1)
2005                         tt = getvar_i(av[1]);
2006                 else
2007                         time(&tt);
2008                 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
2009                 i = strftime(buf, MAXVARFMT,
2010                         ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2011                         localtime(&tt));
2012                 buf[i] = '\0';
2013                 setvar_s(res, buf);
2014                 break;
2015
2016         case B_ma:
2017                 re = as_regex(an[1], &sreg);
2018                 n = regexec(re, as[0], 1, pmatch, 0);
2019                 if (n == 0) {
2020                         pmatch[0].rm_so++;
2021                         pmatch[0].rm_eo++;
2022                 } else {
2023                         pmatch[0].rm_so = 0;
2024                         pmatch[0].rm_eo = -1;
2025                 }
2026                 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2027                 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2028                 setvar_i(res, pmatch[0].rm_so);
2029                 if (re == &sreg) regfree(re);
2030                 break;
2031
2032         case B_ge:
2033                 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2034                 break;
2035
2036         case B_gs:
2037                 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2038                 break;
2039
2040         case B_su:
2041                 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2042                 break;
2043         }
2044
2045         nvfree(tv);
2046         return res;
2047 }
2048
2049 /*
2050  * Evaluate node - the heart of the program. Supplied with subtree
2051  * and place where to store result. returns ptr to result.
2052  */
2053 #define XC(n) ((n) >> 8)
2054
2055 static var *evaluate(node *op, var *res)
2056 {
2057         /* This procedure is recursive so we should count every byte */
2058         static var *fnargs = NULL;
2059         static unsigned seed = 1;
2060         static regex_t sreg;
2061
2062         node *op1;
2063         var *v1;
2064         union {
2065                 var *v;
2066                 const char *s;
2067                 double d;
2068                 int i;
2069         } L, R;
2070         uint32_t opinfo;
2071         short opn;
2072         union {
2073                 char *s;
2074                 rstream *rsm;
2075                 FILE *F;
2076                 var *v;
2077                 regex_t *re;
2078                 uint32_t info;
2079         } X;
2080
2081         if (!op)
2082                 return setvar_s(res, NULL);
2083
2084         v1 = nvalloc(2);
2085
2086         while (op) {
2087
2088                 opinfo = op->info;
2089                 opn = (short)(opinfo & OPNMASK);
2090                 lineno = op->lineno;
2091
2092                 /* execute inevitable things */
2093                 op1 = op->l.n;
2094                 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2095                 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2096                 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2097                 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2098                 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2099
2100                 switch (XC(opinfo & OPCLSMASK)) {
2101
2102                   /* -- iterative node type -- */
2103
2104                   /* test pattern */
2105                 case XC( OC_TEST ):
2106                         if ((op1->info & OPCLSMASK) == OC_COMMA) {
2107                                 /* it's range pattern */
2108                                 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2109                                         op->info |= OF_CHECKED;
2110                                         if (ptest(op1->r.n))
2111                                                 op->info &= ~OF_CHECKED;
2112
2113                                         op = op->a.n;
2114                                 } else {
2115                                         op = op->r.n;
2116                                 }
2117                         } else {
2118                                 op = (ptest(op1)) ? op->a.n : op->r.n;
2119                         }
2120                         break;
2121
2122                   /* just evaluate an expression, also used as unconditional jump */
2123                 case XC( OC_EXEC ):
2124                         break;
2125
2126                   /* branch, used in if-else and various loops */
2127                 case XC( OC_BR ):
2128                         op = istrue(L.v) ? op->a.n : op->r.n;
2129                         break;
2130
2131                   /* initialize for-in loop */
2132                 case XC( OC_WALKINIT ):
2133                         hashwalk_init(L.v, iamarray(R.v));
2134                         break;
2135
2136                   /* get next array item */
2137                 case XC( OC_WALKNEXT ):
2138                         op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2139                         break;
2140
2141                 case XC( OC_PRINT ):
2142                 case XC( OC_PRINTF ):
2143                         X.F = stdout;
2144                         if (op->r.n) {
2145                                 X.rsm = newfile(R.s);
2146                                 if (! X.rsm->F) {
2147                                         if (opn == '|') {
2148                                                 X.rsm->F = popen(R.s, "w");
2149                                                 if (X.rsm->F == NULL)
2150                                                         bb_perror_msg_and_die("popen");
2151                                                 X.rsm->is_pipe = 1;
2152                                         } else {
2153                                                 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
2154                                         }
2155                                 }
2156                                 X.F = X.rsm->F;
2157                         }
2158
2159                         if ((opinfo & OPCLSMASK) == OC_PRINT) {
2160                                 if (! op1) {
2161                                         fputs(getvar_s(V[F0]), X.F);
2162                                 } else {
2163                                         while (op1) {
2164                                                 L.v = evaluate(nextarg(&op1), v1);
2165                                                 if (L.v->type & VF_NUMBER) {
2166                                                         fmt_num(buf, MAXVARFMT, getvar_s(V[OFMT]),
2167                                                                         getvar_i(L.v), TRUE);
2168                                                         fputs(buf, X.F);
2169                                                 } else {
2170                                                         fputs(getvar_s(L.v), X.F);
2171                                                 }
2172
2173                                                 if (op1) fputs(getvar_s(V[OFS]), X.F);
2174                                         }
2175                                 }
2176                                 fputs(getvar_s(V[ORS]), X.F);
2177
2178                         } else {        /* OC_PRINTF */
2179                                 L.s = awk_printf(op1);
2180                                 fputs(L.s, X.F);
2181                                 free((char*)L.s);
2182                         }
2183                         fflush(X.F);
2184                         break;
2185
2186                 case XC( OC_DELETE ):
2187                         X.info = op1->info & OPCLSMASK;
2188                         if (X.info == OC_VAR) {
2189                                 R.v = op1->l.v;
2190                         } else if (X.info == OC_FNARG) {
2191                                 R.v = &fnargs[op1->l.i];
2192                         } else {
2193                                 runtime_error(EMSG_NOT_ARRAY);
2194                         }
2195
2196                         if (op1->r.n) {
2197                                 clrvar(L.v);
2198                                 L.s = getvar_s(evaluate(op1->r.n, v1));
2199                                 hash_remove(iamarray(R.v), L.s);
2200                         } else {
2201                                 clear_array(iamarray(R.v));
2202                         }
2203                         break;
2204
2205                 case XC( OC_NEWSOURCE ):
2206                         programname = op->l.s;
2207                         break;
2208
2209                 case XC( OC_RETURN ):
2210                         copyvar(res, L.v);
2211                         break;
2212
2213                 case XC( OC_NEXTFILE ):
2214                         nextfile = TRUE;
2215                 case XC( OC_NEXT ):
2216                         nextrec = TRUE;
2217                 case XC( OC_DONE ):
2218                         clrvar(res);
2219                         break;
2220
2221                 case XC( OC_EXIT ):
2222                         awk_exit(L.d);
2223
2224                   /* -- recursive node type -- */
2225
2226                 case XC( OC_VAR ):
2227                         L.v = op->l.v;
2228                         if (L.v == V[NF])
2229                                 split_f0();
2230                         goto v_cont;
2231
2232                 case XC( OC_FNARG ):
2233                         L.v = &fnargs[op->l.i];
2234  v_cont:
2235                         res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
2236                         break;
2237
2238                 case XC( OC_IN ):
2239                         setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2240                         break;
2241
2242                 case XC( OC_REGEXP ):
2243                         op1 = op;
2244                         L.s = getvar_s(V[F0]);
2245                         goto re_cont;
2246
2247                 case XC( OC_MATCH ):
2248                         op1 = op->r.n;
2249  re_cont:
2250                         X.re = as_regex(op1, &sreg);
2251                         R.i = regexec(X.re, L.s, 0, NULL, 0);
2252                         if (X.re == &sreg) regfree(X.re);
2253                         setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2254                         break;
2255
2256                 case XC( OC_MOVE ):
2257                         /* if source is a temporary string, jusk relink it to dest */
2258                         if (R.v == v1+1 && R.v->string) {
2259                                 res = setvar_p(L.v, R.v->string);
2260                                 R.v->string = NULL;
2261                         } else {
2262                                 res = copyvar(L.v, R.v);
2263                         }
2264                         break;
2265
2266                 case XC( OC_TERNARY ):
2267                         if ((op->r.n->info & OPCLSMASK) != OC_COLON)
2268                                 runtime_error(EMSG_POSSIBLE_ERROR);
2269                         res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2270                         break;
2271
2272                 case XC( OC_FUNC ):
2273                         if (! op->r.f->body.first)
2274                                 runtime_error(EMSG_UNDEF_FUNC);
2275
2276                         X.v = R.v = nvalloc(op->r.f->nargs+1);
2277                         while (op1) {
2278                                 L.v = evaluate(nextarg(&op1), v1);
2279                                 copyvar(R.v, L.v);
2280                                 R.v->type |= VF_CHILD;
2281                                 R.v->x.parent = L.v;
2282                                 if (++R.v - X.v >= op->r.f->nargs)
2283                                         break;
2284                         }
2285
2286                         R.v = fnargs;
2287                         fnargs = X.v;
2288
2289                         L.s = programname;
2290                         res = evaluate(op->r.f->body.first, res);
2291                         programname = L.s;
2292
2293                         nvfree(fnargs);
2294                         fnargs = R.v;
2295                         break;
2296
2297                 case XC( OC_GETLINE ):
2298                 case XC( OC_PGETLINE ):
2299                         if (op1) {
2300                                 X.rsm = newfile(L.s);
2301                                 if (! X.rsm->F) {
2302                                         if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2303                                                 X.rsm->F = popen(L.s, "r");
2304                                                 X.rsm->is_pipe = TRUE;
2305                                         } else {
2306                                                 X.rsm->F = fopen(L.s, "r");             /* not xfopen! */
2307                                         }
2308                                 }
2309                         } else {
2310                                 if (! iF) iF = next_input_file();
2311                                 X.rsm = iF;
2312                         }
2313
2314                         if (! X.rsm->F) {
2315                                 setvar_i(V[ERRNO], errno);
2316                                 setvar_i(res, -1);
2317                                 break;
2318                         }
2319
2320                         if (! op->r.n)
2321                                 R.v = V[F0];
2322
2323                         L.i = awk_getline(X.rsm, R.v);
2324                         if (L.i > 0) {
2325                                 if (! op1) {
2326                                         incvar(V[FNR]);
2327                                         incvar(V[NR]);
2328                                 }
2329                         }
2330                         setvar_i(res, L.i);
2331                         break;
2332
2333                   /* simple builtins */
2334                 case XC( OC_FBLTIN ):
2335                         switch (opn) {
2336
2337                         case F_in:
2338                                 R.d = (int)L.d;
2339                                 break;
2340
2341                         case F_rn:
2342                                 R.d = (double)rand() / (double)RAND_MAX;
2343                                 break;
2344
2345 #if ENABLE_FEATURE_AWK_MATH
2346                         case F_co:
2347                                 R.d = cos(L.d);
2348                                 break;
2349
2350                         case F_ex:
2351                                 R.d = exp(L.d);
2352                                 break;
2353
2354                         case F_lg:
2355                                 R.d = log(L.d);
2356                                 break;
2357
2358                         case F_si:
2359                                 R.d = sin(L.d);
2360                                 break;
2361
2362                         case F_sq:
2363                                 R.d = sqrt(L.d);
2364                                 break;
2365 #else
2366                         case F_co:
2367                         case F_ex:
2368                         case F_lg:
2369                         case F_si:
2370                         case F_sq:
2371                                 runtime_error(EMSG_NO_MATH);
2372                                 break;
2373 #endif
2374
2375                         case F_sr:
2376                                 R.d = (double)seed;
2377                                 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
2378                                 srand(seed);
2379                                 break;
2380
2381                         case F_ti:
2382                                 R.d = time(NULL);
2383                                 break;
2384
2385                         case F_le:
2386                                 if (! op1)
2387                                         L.s = getvar_s(V[F0]);
2388                                 R.d = strlen(L.s);
2389                                 break;
2390
2391                         case F_sy:
2392                                 fflush(NULL);
2393                                 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2394                                                 ? (system(L.s) >> 8) : 0;
2395                                 break;
2396
2397                         case F_ff:
2398                                 if (! op1)
2399                                         fflush(stdout);
2400                                 else {
2401                                         if (L.s && *L.s) {
2402                                                 X.rsm = newfile(L.s);
2403                                                 fflush(X.rsm->F);
2404                                         } else {
2405                                                 fflush(NULL);
2406                                         }
2407                                 }
2408                                 break;
2409
2410                         case F_cl:
2411                                 X.rsm = (rstream *)hash_search(fdhash, L.s);
2412                                 if (X.rsm) {
2413                                         R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
2414                                         free(X.rsm->buffer);
2415                                         hash_remove(fdhash, L.s);
2416                                 }
2417                                 if (R.i != 0)
2418                                         setvar_i(V[ERRNO], errno);
2419                                 R.d = (double)R.i;
2420                                 break;
2421                         }
2422                         setvar_i(res, R.d);
2423                         break;
2424
2425                 case XC( OC_BUILTIN ):
2426                         res = exec_builtin(op, res);
2427                         break;
2428
2429                 case XC( OC_SPRINTF ):
2430                         setvar_p(res, awk_printf(op1));
2431                         break;
2432
2433                 case XC( OC_UNARY ):
2434                         X.v = R.v;
2435                         L.d = R.d = getvar_i(R.v);
2436                         switch (opn) {
2437                         case 'P':
2438                                 L.d = ++R.d;
2439                                 goto r_op_change;
2440                         case 'p':
2441                                 R.d++;
2442                                 goto r_op_change;
2443                         case 'M':
2444                                 L.d = --R.d;
2445                                 goto r_op_change;
2446                         case 'm':
2447                                 R.d--;
2448                                 goto r_op_change;
2449                         case '!':
2450                                 L.d = istrue(X.v) ? 0 : 1;
2451                                 break;
2452                         case '-':
2453                                 L.d = -R.d;
2454                                 break;
2455  r_op_change:
2456                                 setvar_i(X.v, R.d);
2457                         }
2458                         setvar_i(res, L.d);
2459                         break;
2460
2461                 case XC( OC_FIELD ):
2462                         R.i = (int)getvar_i(R.v);
2463                         if (R.i == 0) {
2464                                 res = V[F0];
2465                         } else {
2466                                 split_f0();
2467                                 if (R.i > nfields)
2468                                         fsrealloc(R.i);
2469
2470                                 res = &Fields[R.i-1];
2471                         }
2472                         break;
2473
2474                   /* concatenation (" ") and index joining (",") */
2475                 case XC( OC_CONCAT ):
2476                 case XC( OC_COMMA ):
2477                         opn = strlen(L.s) + strlen(R.s) + 2;
2478                         X.s = xmalloc(opn);
2479                         strcpy(X.s, L.s);
2480                         if ((opinfo & OPCLSMASK) == OC_COMMA) {
2481                                 L.s = getvar_s(V[SUBSEP]);
2482                                 X.s = xrealloc(X.s, opn + strlen(L.s));
2483                                 strcat(X.s, L.s);
2484                         }
2485                         strcat(X.s, R.s);
2486                         setvar_p(res, X.s);
2487                         break;
2488
2489                 case XC( OC_LAND ):
2490                         setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2491                         break;
2492
2493                 case XC( OC_LOR ):
2494                         setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2495                         break;
2496
2497                 case XC( OC_BINARY ):
2498                 case XC( OC_REPLACE ):
2499                         R.d = getvar_i(R.v);
2500                         switch (opn) {
2501                         case '+':
2502                                 L.d += R.d;
2503                                 break;
2504                         case '-':
2505                                 L.d -= R.d;
2506                                 break;
2507                         case '*':
2508                                 L.d *= R.d;
2509                                 break;
2510                         case '/':
2511                                 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2512                                 L.d /= R.d;
2513                                 break;
2514                         case '&':
2515 #if ENABLE_FEATURE_AWK_MATH
2516                                 L.d = pow(L.d, R.d);
2517 #else
2518                                 runtime_error(EMSG_NO_MATH);
2519 #endif
2520                                 break;
2521                         case '%':
2522                                 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2523                                 L.d -= (int)(L.d / R.d) * R.d;
2524                                 break;
2525                         }
2526                         res = setvar_i(((opinfo&OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
2527                         break;
2528
2529                 case XC( OC_COMPARE ):
2530                         if (is_numeric(L.v) && is_numeric(R.v)) {
2531                                 L.d = getvar_i(L.v) - getvar_i(R.v);
2532                         } else {
2533                                 L.s = getvar_s(L.v);
2534                                 R.s = getvar_s(R.v);
2535                                 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2536                         }
2537                         switch (opn & 0xfe) {
2538                         case 0:
2539                                 R.i = (L.d > 0);
2540                                 break;
2541                         case 2:
2542                                 R.i = (L.d >= 0);
2543                                 break;
2544                         case 4:
2545                                 R.i = (L.d == 0);
2546                                 break;
2547                         }
2548                         setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2549                         break;
2550
2551                 default:
2552                         runtime_error(EMSG_POSSIBLE_ERROR);
2553                 }
2554                 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2555                         op = op->a.n;
2556                 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2557                         break;
2558                 if (nextrec)
2559                         break;
2560         }
2561         nvfree(v1);
2562         return res;
2563 }
2564
2565
2566 /* -------- main & co. -------- */
2567
2568 static int awk_exit(int r)
2569 {
2570         var tv;
2571         unsigned i;
2572         hash_item *hi;
2573
2574         zero_out_var(&tv);
2575
2576         if (!exiting) {
2577                 exiting = TRUE;
2578                 nextrec = FALSE;
2579                 evaluate(endseq.first, &tv);
2580         }
2581
2582         /* waiting for children */
2583         for (i = 0; i < fdhash->csize; i++) {
2584                 hi = fdhash->items[i];
2585                 while (hi) {
2586                         if (hi->data.rs.F && hi->data.rs.is_pipe)
2587                                 pclose(hi->data.rs.F);
2588                         hi = hi->next;
2589                 }
2590         }
2591
2592         exit(r);
2593 }
2594
2595 /* if expr looks like "var=value", perform assignment and return 1,
2596  * otherwise return 0 */
2597 static int is_assignment(const char *expr)
2598 {
2599         char *exprc, *s, *s0, *s1;
2600
2601         exprc = xstrdup(expr);
2602         if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2603                 free(exprc);
2604                 return FALSE;
2605         }
2606
2607         *(s++) = '\0';
2608         s0 = s1 = s;
2609         while (*s)
2610                 *(s1++) = nextchar(&s);
2611
2612         *s1 = '\0';
2613         setvar_u(newvar(exprc), s0);
2614         free(exprc);
2615         return TRUE;
2616 }
2617
2618 /* switch to next input file */
2619 static rstream *next_input_file(void)
2620 {
2621         static rstream rsm;
2622         FILE *F = NULL;
2623         const char *fname, *ind;
2624         static int files_happen = FALSE;
2625
2626         if (rsm.F) fclose(rsm.F);
2627         rsm.F = NULL;
2628         rsm.pos = rsm.adv = 0;
2629
2630         do {
2631                 if (getvar_i(V[ARGIND])+1 >= getvar_i(V[ARGC])) {
2632                         if (files_happen)
2633                                 return NULL;
2634                         fname = "-";
2635                         F = stdin;
2636                 } else {
2637                         ind = getvar_s(incvar(V[ARGIND]));
2638                         fname = getvar_s(findvar(iamarray(V[ARGV]), ind));
2639                         if (fname && *fname && !is_assignment(fname))
2640                                 F = afopen(fname, "r");
2641                 }
2642         } while (!F);
2643
2644         files_happen = TRUE;
2645         setvar_s(V[FILENAME], fname);
2646         rsm.F = F;
2647         return &rsm;
2648 }
2649
2650 int awk_main(int argc, char **argv);
2651 int awk_main(int argc, char **argv)
2652 {
2653         unsigned opt;
2654         char *opt_F, *opt_W;
2655         llist_t *opt_v = NULL;
2656         int i, j, flen;
2657         var *v;
2658         var tv;
2659         char **envp;
2660         char *vnames = (char *)vNames; /* cheat */
2661         char *vvalues = (char *)vValues;
2662
2663         /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
2664          * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2665         if (ENABLE_LOCALE_SUPPORT)
2666                 setlocale(LC_NUMERIC, "C");
2667
2668         zero_out_var(&tv);
2669
2670         /* allocate global buffer */
2671         buf = xmalloc(MAXVARFMT + 1);
2672
2673         vhash = hash_init();
2674         ahash = hash_init();
2675         fdhash = hash_init();
2676         fnhash = hash_init();
2677
2678         /* initialize variables */
2679         for (i = 0; *vnames; i++) {
2680                 V[i] = v = newvar(nextword(&vnames));
2681                 if (*vvalues != '\377')
2682                         setvar_s(v, nextword(&vvalues));
2683                 else
2684                         setvar_i(v, 0);
2685
2686                 if (*vnames == '*') {
2687                         v->type |= VF_SPECIAL;
2688                         vnames++;
2689                 }
2690         }
2691
2692         handle_special(V[FS]);
2693         handle_special(V[RS]);
2694
2695         newfile("/dev/stdin")->F = stdin;
2696         newfile("/dev/stdout")->F = stdout;
2697         newfile("/dev/stderr")->F = stderr;
2698
2699         for (envp = environ; *envp; envp++) {
2700                 char *s = xstrdup(*envp);
2701                 char *s1 = strchr(s, '=');
2702                 if (s1) {
2703                         *s1++ = '\0';
2704                         setvar_u(findvar(iamarray(V[ENVIRON]), s), s1);
2705                 }
2706                 free(s);
2707         }
2708         opt_complementary = "v::";
2709         opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &programname, &opt_W);
2710         argv += optind;
2711         argc -= optind;
2712         if (opt & 0x1) setvar_s(V[FS], opt_F); // -F
2713         while (opt_v) { /* -v */
2714                 if (!is_assignment(llist_pop(&opt_v)))
2715                         bb_show_usage();
2716         }
2717         if (opt & 0x4) { // -f
2718                 char *s = s; /* die, gcc, die */
2719                 FILE *from_file = afopen(programname, "r");
2720                 /* one byte is reserved for some trick in next_token */
2721                 if (fseek(from_file, 0, SEEK_END) == 0) {
2722                         flen = ftell(from_file);
2723                         s = xmalloc(flen + 4);
2724                         fseek(from_file, 0, SEEK_SET);
2725                         i = 1 + fread(s + 1, 1, flen, from_file);
2726                 } else {
2727                         for (i = j = 1; j > 0; i += j) {
2728                                 s = xrealloc(s, i + 4096);
2729                                 j = fread(s + i, 1, 4094, from_file);
2730                         }
2731                 }
2732                 s[i] = '\0';
2733                 fclose(from_file);
2734                 parse_program(s + 1);
2735                 free(s);
2736         } else { // no -f: take program from 1st parameter
2737                 if (!argc)
2738                         bb_show_usage();
2739                 programname = "cmd. line";
2740                 parse_program(*argv++);
2741                 argc--;
2742         }
2743         if (opt & 0x8) // -W
2744                 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
2745
2746         /* fill in ARGV array */
2747         setvar_i(V[ARGC], argc + 1);
2748         setari_u(V[ARGV], 0, "awk");
2749         i = 0;
2750         while (*argv)
2751                 setari_u(V[ARGV], ++i, *argv++);
2752
2753         evaluate(beginseq.first, &tv);
2754         if (!mainseq.first && !endseq.first)
2755                 awk_exit(EXIT_SUCCESS);
2756
2757         /* input file could already be opened in BEGIN block */
2758         if (!iF) iF = next_input_file();
2759
2760         /* passing through input files */
2761         while (iF) {
2762                 nextfile = FALSE;
2763                 setvar_i(V[FNR], 0);
2764
2765                 while ((i = awk_getline(iF, V[F0])) > 0) {
2766                         nextrec = FALSE;
2767                         incvar(V[NR]);
2768                         incvar(V[FNR]);
2769                         evaluate(mainseq.first, &tv);
2770
2771                         if (nextfile)
2772                                 break;
2773                 }
2774
2775                 if (i < 0)
2776                         runtime_error(strerror(errno));
2777
2778                 iF = next_input_file();
2779         }
2780
2781         awk_exit(EXIT_SUCCESS);
2782         /*return 0;*/
2783 }