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