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