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