blob: f487163af731e3b26d0cb7fca3601ff94200bd93 [file] [log] [blame]
Glenn L McGrath545106f2002-11-11 06:21:00 +00001/* 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 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Glenn L McGrath545106f2002-11-11 06:21:00 +00008 */
9
Sven-Göran Berghf200f732013-11-12 14:18:25 +010010//config:config AWK
11//config: bool "awk"
12//config: default y
13//config: help
14//config: Awk is used as a pattern scanning and processing language. This is
15//config: the BusyBox implementation of that programming language.
16//config:
17//config:config FEATURE_AWK_LIBM
18//config: bool "Enable math functions (requires libm)"
19//config: default y
20//config: depends on AWK
21//config: help
22//config: Enable math functions of the Awk programming language.
23//config: NOTE: This will require libm to be present for linking.
24//config:
25//config:config FEATURE_AWK_GNU_EXTENSIONS
26//config: bool "Enable a few GNU extensions"
27//config: default y
28//config: depends on AWK
29//config: help
30//config: Enable a few features from gawk:
31//config: * command line option -e AWK_PROGRAM
32//config: * simultaneous use of -f and -e on the command line.
33//config: This enables the use of awk library files.
34//config: Ex: awk -f mylib.awk -e '{print myfunction($1);}' ...
35
36//applet:IF_AWK(APPLET_NOEXEC(awk, awk, BB_DIR_USR_BIN, BB_SUID_DROP, awk))
37
38//kbuild:lib-$(CONFIG_AWK) += awk.o
39
Pere Orga6a3e01d2011-04-01 22:56:30 +020040//usage:#define awk_trivial_usage
41//usage: "[OPTIONS] [AWK_PROGRAM] [FILE]..."
42//usage:#define awk_full_usage "\n\n"
Denys Vlasenko66426762011-06-05 03:58:28 +020043//usage: " -v VAR=VAL Set variable"
Pere Orga6a3e01d2011-04-01 22:56:30 +020044//usage: "\n -F SEP Use SEP as field separator"
45//usage: "\n -f FILE Read program from FILE"
Sven-Göran Berghf200f732013-11-12 14:18:25 +010046//usage: IF_FEATURE_AWK_GNU_EXTENSIONS(
47//usage: "\n -e AWK_PROGRAM"
48//usage: )
Pere Orga6a3e01d2011-04-01 22:56:30 +020049
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000050#include "libbb.h"
Rob Landleyd921b2e2006-08-03 15:41:12 +000051#include "xregex.h"
52#include <math.h>
Glenn L McGrath545106f2002-11-11 06:21:00 +000053
Denis Vlasenko99912ca2007-04-10 15:43:37 +000054/* This is a NOEXEC applet. Be very careful! */
55
Glenn L McGrath545106f2002-11-11 06:21:00 +000056
Denys Vlasenkoda62b092010-03-11 12:13:18 +010057/* If you comment out one of these below, it will be #defined later
58 * to perform debug printfs to stderr: */
59#define debug_printf_walker(...) do {} while (0)
Denys Vlasenkod527e0c2010-10-05 13:22:11 +020060#define debug_printf_eval(...) do {} while (0)
Denys Vlasenko7b46d112011-09-11 00:30:56 +020061#define debug_printf_parse(...) do {} while (0)
Denys Vlasenkoda62b092010-03-11 12:13:18 +010062
63#ifndef debug_printf_walker
64# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__))
65#endif
Denys Vlasenkod527e0c2010-10-05 13:22:11 +020066#ifndef debug_printf_eval
67# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__))
68#endif
Denys Vlasenko7b46d112011-09-11 00:30:56 +020069#ifndef debug_printf_parse
70# define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__))
71#endif
Denys Vlasenkoda62b092010-03-11 12:13:18 +010072
73
Sven-Göran Berghf200f732013-11-12 14:18:25 +010074#define OPTSTR_AWK \
75 "F:v:f:" \
76 IF_FEATURE_AWK_GNU_EXTENSIONS("e:") \
77 "W:"
78#define OPTCOMPLSTR_AWK \
79 "v::f::" \
80 IF_FEATURE_AWK_GNU_EXTENSIONS("e::")
81enum {
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};
Denys Vlasenkoda62b092010-03-11 12:13:18 +010093
Denis Vlasenko629563b2007-02-24 17:05:52 +000094#define MAXVARFMT 240
95#define MINNVBLOCK 64
Glenn L McGrath545106f2002-11-11 06:21:00 +000096
97/* variable flags */
Denis Vlasenko629563b2007-02-24 17:05:52 +000098#define VF_NUMBER 0x0001 /* 1 = primary type is number */
99#define VF_ARRAY 0x0002 /* 1 = it's an array */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000100
Denis Vlasenko629563b2007-02-24 17:05:52 +0000101#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 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000108
109/* these flags are static, don't change them when value is changed */
Denis Vlasenko629563b2007-02-24 17:05:52 +0000110#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000111
Denys Vlasenkoda62b092010-03-11 12:13:18 +0100112typedef struct walker_list {
113 char *end;
114 char *cur;
115 struct walker_list *prev;
116 char wbuf[1];
117} walker_list;
118
Glenn L McGrath545106f2002-11-11 06:21:00 +0000119/* Variable */
120typedef struct var_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000121 unsigned type; /* flags */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000122 double number;
123 char *string;
124 union {
Denis Vlasenko629563b2007-02-24 17:05:52 +0000125 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 */
Denys Vlasenkoda62b092010-03-11 12:13:18 +0100128 walker_list *walker; /* list of array elements (for..in) */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000129 } x;
130} var;
131
132/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
133typedef struct chain_s {
134 struct node_s *first;
135 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000136 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000137} chain;
138
139/* Function */
140typedef struct func_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000141 unsigned nargs;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000142 struct chain_s body;
143} func;
144
145/* I/O stream */
146typedef struct rstream_s {
147 FILE *F;
148 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +0000149 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000150 int size;
151 int pos;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000152 smallint is_pipe;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000153} rstream;
154
155typedef struct hash_item_s {
156 union {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000157 struct var_s v; /* variable/array hash */
158 struct rstream_s rs; /* redirect streams hash */
159 struct func_s f; /* functions hash */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000160 } data;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000161 struct hash_item_s *next; /* next in chain */
162 char name[1]; /* really it's longer */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000163} hash_item;
164
165typedef struct xhash_s {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000166 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 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000170 struct hash_item_s **items;
171} xhash;
172
173/* Tree node */
174typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000175 uint32_t info;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000176 unsigned lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000177 union {
178 struct node_s *n;
179 var *v;
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100180 int aidx;
181 char *new_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000182 regex_t *re;
183 } l;
184 union {
185 struct node_s *n;
186 regex_t *ire;
187 func *f;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000188 } r;
189 union {
190 struct node_s *n;
191 } a;
192} node;
193
194/* Block of temporary variables */
195typedef struct nvblock_s {
196 int size;
197 var *pos;
198 struct nvblock_s *prev;
199 struct nvblock_s *next;
Denys Vlasenkod069e532009-09-09 23:12:10 +0200200 var nv[];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000201} nvblock;
202
203typedef 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() */
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100210#define TC_SEQSTART 1 /* ( */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000211#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#define TC_GETLINE (1 << 20)
231#define TC_FUNCDECL (1 << 21) /* `function' `func' */
232#define TC_BEGIN (1 << 22)
233#define TC_END (1 << 23)
234#define TC_EOF (1 << 24)
235#define TC_VARIABLE (1 << 25)
236#define TC_ARRAY (1 << 26)
237#define TC_FUNCTION (1 << 27)
238#define TC_STRING (1 << 28)
239#define TC_NUMBER (1 << 29)
240
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000241#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000242
243/* combined token classes */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000244#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
Denys Vlasenko1390a012013-07-20 21:23:01 +0200245//#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000246#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
247 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000248
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000249#define TC_STATEMNT (TC_STATX | TC_WHILE)
250#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000251
252/* word tokens, cannot mean something else if not expected */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000253#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
254 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000255
256/* discard newlines after these */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000257#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
258 | TC_BINOP | TC_OPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000259
260/* what can expression begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000261#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000262/* what can group begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000263#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000264
265/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
266/* operator is inserted between them */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000267#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
268 | TC_STRING | TC_NUMBER | TC_UOPPOST)
269#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000270
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000271#define OF_RES1 0x010000
272#define OF_RES2 0x020000
273#define OF_STR1 0x040000
274#define OF_STR2 0x080000
275#define OF_NUM1 0x100000
276#define OF_CHECKED 0x200000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000277
278/* combined operator flags */
279#define xx 0
280#define xV OF_RES2
281#define xS (OF_RES2 | OF_STR2)
282#define Vx OF_RES1
283#define VV (OF_RES1 | OF_RES2)
284#define Nx (OF_RES1 | OF_NUM1)
285#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
286#define Sx (OF_RES1 | OF_STR1)
287#define SV (OF_RES1 | OF_STR1 | OF_RES2)
288#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
289
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000290#define OPCLSMASK 0xFF00
291#define OPNMASK 0x007F
Glenn L McGrath545106f2002-11-11 06:21:00 +0000292
293/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
294 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
295 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
296 */
Denys Vlasenko202a1b92011-09-10 04:51:09 +0200297#undef P
298#undef PRIMASK
299#undef PRIMASK2
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000300#define P(x) (x << 24)
301#define PRIMASK 0x7F000000
302#define PRIMASK2 0x7E000000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000303
304/* Operation classes */
305
306#define SHIFT_TIL_THIS 0x0600
307#define RECUR_FROM_THIS 0x1000
308
309enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000310 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
311 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000312
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000313 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
314 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
315 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000316
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000317 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
318 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
319 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
320 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
321 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
322 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
323 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
324 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
325 OC_DONE = 0x2800,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000326
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000327 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
328 ST_WHILE = 0x3300
Glenn L McGrath545106f2002-11-11 06:21:00 +0000329};
330
331/* simple builtins */
332enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000333 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000334 F_ti, F_le, F_sy, F_ff, F_cl
335};
336
337/* builtins */
338enum {
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +0200339 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_mt, B_lo, B_up,
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000340 B_ge, B_gs, B_su,
341 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000342};
343
344/* tokens and their corresponding info values */
345
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200346#define NTC "\377" /* switch to next token class (tc<<1) */
347#define NTCC '\377'
Glenn L McGrath545106f2002-11-11 06:21:00 +0000348
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200349#define OC_B OC_BUILTIN
Glenn L McGrath545106f2002-11-11 06:21:00 +0000350
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000351static const char tokenlist[] ALIGN1 =
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200352 "\1(" NTC
353 "\1)" NTC
354 "\1/" NTC /* REGEXP */
355 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
356 "\2++" "\2--" NTC /* UOPPOST */
357 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
358 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
359 "\2*=" "\2/=" "\2%=" "\2^="
360 "\1+" "\1-" "\3**=" "\2**"
361 "\1/" "\1%" "\1^" "\1*"
362 "\2!=" "\2>=" "\2<=" "\1>"
363 "\1<" "\2!~" "\1~" "\2&&"
364 "\2||" "\1?" "\1:" NTC
365 "\2in" NTC
366 "\1," NTC
367 "\1|" NTC
368 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
369 "\1]" NTC
370 "\1{" NTC
371 "\1}" NTC
372 "\1;" NTC
373 "\1\n" NTC
374 "\2if" "\2do" "\3for" "\5break" /* STATX */
375 "\10continue" "\6delete" "\5print"
376 "\6printf" "\4next" "\10nextfile"
377 "\6return" "\4exit" NTC
378 "\5while" NTC
379 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000380
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200381 "\3and" "\5compl" "\6lshift" "\2or"
382 "\6rshift" "\3xor"
383 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
384 "\3cos" "\3exp" "\3int" "\3log"
385 "\4rand" "\3sin" "\4sqrt" "\5srand"
386 "\6gensub" "\4gsub" "\5index" "\6length"
387 "\5match" "\5split" "\7sprintf" "\3sub"
388 "\6substr" "\7systime" "\10strftime" "\6mktime"
389 "\7tolower" "\7toupper" NTC
390 "\7getline" NTC
391 "\4func" "\10function" NTC
392 "\5BEGIN" NTC
393 "\3END"
394 /* compiler adds trailing "\0" */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000395 ;
396
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000397static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000398 0,
399 0,
400 OC_REGEXP,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200401 xS|'a', xS|'w', xS|'|',
402 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
403 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5),
404 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
405 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
406 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
407 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
408 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
409 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
410 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':',
411 OC_IN|SV|P(49), /* in */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000412 OC_COMMA|SS|P(80),
413 OC_PGETLINE|SV|P(37),
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200414 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!',
415 0, /* ] */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000416 0,
417 0,
418 0,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200419 0, /* \n */
420 ST_IF, ST_DO, ST_FOR, OC_BREAK,
421 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
422 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
423 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000424 ST_WHILE,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200425 0, /* else */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000426
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000427 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
428 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000429 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
430 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
431 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
432 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
433 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +0200434 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000435 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
436 OC_GETLINE|SV|P(0),
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200437 0, 0,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000438 0,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200439 0 /* END */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000440};
441
442/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000443/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000444enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000445 CONVFMT, OFMT, FS, OFS,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000446 ORS, RS, RT, FILENAME,
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000447 SUBSEP, F0, ARGIND, ARGC,
448 ARGV, ERRNO, FNR, NR,
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200449 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS
Glenn L McGrath545106f2002-11-11 06:21:00 +0000450};
451
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000452static const char vNames[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000453 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
454 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000455 "SUBSEP\0" "$\0*" "ARGIND\0" "ARGC\0"
456 "ARGV\0" "ERRNO\0" "FNR\0" "NR\0"
457 "NF\0*" "IGNORECASE\0*" "ENVIRON\0" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000458
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000459static const char vValues[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000460 "%.6g\0" "%.6g\0" " \0" " \0"
461 "\n\0" "\n\0" "\0" "\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000462 "\034\0" "\0" "\377";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000463
464/* hash size may grow to these values */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000465#define FIRST_PRIME 61
466static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000467
Glenn L McGrath545106f2002-11-11 06:21:00 +0000468
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000469/* Globals. Split in two parts so that first one is addressed
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000470 * with (mostly short) negative offsets.
471 * NB: it's unsafe to put members of type "double"
472 * into globals2 (gcc may fail to align them).
473 */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000474struct globals {
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000475 double t_double;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000476 chain beginseq, mainseq, endseq;
477 chain *seq;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000478 node *break_ptr, *continue_ptr;
479 rstream *iF;
480 xhash *vhash, *ahash, *fdhash, *fnhash;
481 const char *g_progname;
482 int g_lineno;
483 int nfields;
484 int maxfields; /* used in fsrealloc() only */
485 var *Fields;
486 nvblock *g_cb;
487 char *g_pos;
488 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000489 smallint icase;
490 smallint exiting;
491 smallint nextrec;
492 smallint nextfile;
493 smallint is_f0_split;
Denys Vlasenko7b46d112011-09-11 00:30:56 +0200494 smallint t_rollback;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000495};
496struct globals2 {
497 uint32_t t_info; /* often used */
498 uint32_t t_tclass;
499 char *t_string;
500 int t_lineno;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000501
502 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000503
504 /* former statics from various functions */
505 char *split_f0__fstrings;
506
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000507 uint32_t next_token__save_tclass;
508 uint32_t next_token__save_info;
509 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000510 smallint next_token__concat_inserted;
511
512 smallint next_input_file__files_happen;
513 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000514
515 var *evaluate__fnargs;
516 unsigned evaluate__seed;
517 regex_t evaluate__sreg;
518
519 var ptest__v;
520
521 tsplitter exec_builtin__tspl;
522
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000523 /* biggest and least used members go last */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000524 tsplitter fsplitter, rsplitter;
Denys Vlasenko3dbc5a92010-02-05 14:54:22 +0100525};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000526#define G1 (ptr_to_globals[-1])
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000527#define G (*(struct globals2 *)ptr_to_globals)
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000528/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000529/*char G1size[sizeof(G1)]; - 0x74 */
530/*char Gsize[sizeof(G)]; - 0x1c4 */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000531/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000532/*char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
533#define t_double (G1.t_double )
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000534#define beginseq (G1.beginseq )
535#define mainseq (G1.mainseq )
536#define endseq (G1.endseq )
537#define seq (G1.seq )
538#define break_ptr (G1.break_ptr )
539#define continue_ptr (G1.continue_ptr)
540#define iF (G1.iF )
541#define vhash (G1.vhash )
542#define ahash (G1.ahash )
543#define fdhash (G1.fdhash )
544#define fnhash (G1.fnhash )
545#define g_progname (G1.g_progname )
546#define g_lineno (G1.g_lineno )
547#define nfields (G1.nfields )
548#define maxfields (G1.maxfields )
549#define Fields (G1.Fields )
550#define g_cb (G1.g_cb )
551#define g_pos (G1.g_pos )
552#define g_buf (G1.g_buf )
553#define icase (G1.icase )
554#define exiting (G1.exiting )
555#define nextrec (G1.nextrec )
556#define nextfile (G1.nextfile )
557#define is_f0_split (G1.is_f0_split )
Denys Vlasenko7b46d112011-09-11 00:30:56 +0200558#define t_rollback (G1.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000559#define t_info (G.t_info )
560#define t_tclass (G.t_tclass )
561#define t_string (G.t_string )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000562#define t_lineno (G.t_lineno )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000563#define intvar (G.intvar )
564#define fsplitter (G.fsplitter )
565#define rsplitter (G.rsplitter )
566#define INIT_G() do { \
Denys Vlasenko90a99042009-09-06 02:36:23 +0200567 SET_PTR_TO_GLOBALS((char*)xzalloc(sizeof(G1)+sizeof(G)) + sizeof(G1)); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000568 G.next_token__ltclass = TC_OPTERM; \
569 G.evaluate__seed = 1; \
570} while (0)
571
Glenn L McGrath545106f2002-11-11 06:21:00 +0000572
573/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000574static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000575static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000576static void chain_group(void);
577static var *evaluate(node *, var *);
578static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000579static int fmt_num(char *, int, const char *, double, int);
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000580static int awk_exit(int) NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000581
582/* ---- error handling ---- */
583
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000584static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
585static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
586static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
587static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
588static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
589static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
590static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
591static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
592static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000593static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000594
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100595static void zero_out_var(var *vp)
Denis Vlasenkof782f522007-01-01 23:51:30 +0000596{
597 memset(vp, 0, sizeof(*vp));
598}
599
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000600static void syntax_error(const char *message) NORETURN;
601static void syntax_error(const char *message)
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000602{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000603 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000604}
605
Glenn L McGrath545106f2002-11-11 06:21:00 +0000606/* ---- hash stuff ---- */
607
Denis Vlasenkof782f522007-01-01 23:51:30 +0000608static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000609{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000610 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000611
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100612 while (*name)
613 idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000614 return idx;
615}
616
617/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000618static xhash *hash_init(void)
619{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000620 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000621
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100622 newhash = xzalloc(sizeof(*newhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000623 newhash->csize = FIRST_PRIME;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100624 newhash->items = xzalloc(FIRST_PRIME * sizeof(newhash->items[0]));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000625
626 return newhash;
627}
628
629/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000630static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000631{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000632 hash_item *hi;
633
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100634 hi = hash->items[hashidx(name) % hash->csize];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000635 while (hi) {
636 if (strcmp(hi->name, name) == 0)
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100637 return &hi->data;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000638 hi = hi->next;
639 }
640 return NULL;
641}
642
643/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000644static void hash_rebuild(xhash *hash)
645{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000646 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000647 hash_item **newitems, *hi, *thi;
648
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000649 if (hash->nprime == ARRAY_SIZE(PRIMES))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000650 return;
651
652 newsize = PRIMES[hash->nprime++];
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100653 newitems = xzalloc(newsize * sizeof(newitems[0]));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000654
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000655 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000656 hi = hash->items[i];
657 while (hi) {
658 thi = hi;
659 hi = thi->next;
660 idx = hashidx(thi->name) % newsize;
661 thi->next = newitems[idx];
662 newitems[idx] = thi;
663 }
664 }
665
666 free(hash->items);
667 hash->csize = newsize;
668 hash->items = newitems;
669}
670
671/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000672static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000673{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000674 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000675 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000676 int l;
677
678 hi = hash_search(hash, name);
Denis Vlasenkob78c7822007-07-18 18:31:11 +0000679 if (!hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000680 if (++hash->nel / hash->csize > 10)
681 hash_rebuild(hash);
682
Rob Landleya3896512006-05-07 20:20:34 +0000683 l = strlen(name) + 1;
Denis Vlasenko7a676642009-03-15 22:20:31 +0000684 hi = xzalloc(sizeof(*hi) + l);
685 strcpy(hi->name, name);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000686
687 idx = hashidx(name) % hash->csize;
688 hi->next = hash->items[idx];
689 hash->items[idx] = hi;
690 hash->glen += l;
691 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100692 return &hi->data;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000693}
694
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000695#define findvar(hash, name) ((var*) hash_find((hash), (name)))
696#define newvar(name) ((var*) hash_find(vhash, (name)))
697#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
698#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000699
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000700static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000701{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000702 hash_item *hi, **phi;
703
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100704 phi = &hash->items[hashidx(name) % hash->csize];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000705 while (*phi) {
706 hi = *phi;
707 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000708 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000709 hash->nel--;
710 *phi = hi->next;
711 free(hi);
712 break;
713 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100714 phi = &hi->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000715 }
716}
717
718/* ------ some useful functions ------ */
719
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100720static char *skip_spaces(char *p)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000721{
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000722 while (1) {
723 if (*p == '\\' && p[1] == '\n') {
724 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000725 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000726 } else if (*p != ' ' && *p != '\t') {
727 break;
728 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000729 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000730 }
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100731 return p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000732}
733
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100734/* returns old *s, advances *s past word and terminating NUL */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000735static char *nextword(char **s)
736{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000737 char *p = *s;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100738 while (*(*s)++ != '\0')
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100739 continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000740 return p;
741}
742
Mike Frysinger10a11e22005-09-27 02:23:02 +0000743static char nextchar(char **s)
744{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000745 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000746
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100747 c = *(*s)++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000748 pps = *s;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100749 if (c == '\\')
750 c = bb_process_escape_sequence((const char**)s);
Denys Vlasenkoea664dd2012-06-22 18:41:01 +0200751 /* Example awk statement:
752 * s = "abc\"def"
753 * we must treat \" as "
754 */
Denys Vlasenko2b299fe2010-10-24 01:58:04 +0200755 if (c == '\\' && *s == pps) { /* unrecognized \z? */
756 c = *(*s); /* yes, fetch z */
757 if (c)
758 (*s)++; /* advance unless z = NUL */
759 }
Glenn L McGrath545106f2002-11-11 06:21:00 +0000760 return c;
761}
762
Denys Vlasenkoea664dd2012-06-22 18:41:01 +0200763/* TODO: merge with strcpy_and_process_escape_sequences()?
764 */
765static void unescape_string_in_place(char *s1)
766{
767 char *s = s1;
768 while ((*s1 = nextchar(&s)) != '\0')
769 s1++;
770}
771
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000772static ALWAYS_INLINE int isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000773{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000774 return (isalnum(c) || c == '_');
775}
776
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000777static double my_strtod(char **pp)
778{
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200779 char *cp = *pp;
Rob Landleyd8205b32010-10-24 03:27:22 +0200780 if (ENABLE_DESKTOP && cp[0] == '0') {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200781 /* Might be hex or octal integer: 0x123abc or 07777 */
782 char c = (cp[1] | 0x20);
783 if (c == 'x' || isdigit(cp[1])) {
784 unsigned long long ull = strtoull(cp, pp, 0);
785 if (c == 'x')
786 return ull;
787 c = **pp;
788 if (!isdigit(c) && c != '.')
789 return ull;
790 /* else: it may be a floating number. Examples:
791 * 009.123 (*pp points to '9')
792 * 000.123 (*pp points to '.')
793 * fall through to strtod.
794 */
795 }
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000796 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200797 return strtod(cp, pp);
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000798}
799
Glenn L McGrath545106f2002-11-11 06:21:00 +0000800/* -------- working with variables (set/get/copy/etc) -------- */
801
Mike Frysinger10a11e22005-09-27 02:23:02 +0000802static xhash *iamarray(var *v)
803{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000804 var *a = v;
805
806 while (a->type & VF_CHILD)
807 a = a->x.parent;
808
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000809 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000810 a->type |= VF_ARRAY;
811 a->x.array = hash_init();
812 }
813 return a->x.array;
814}
815
Mike Frysinger10a11e22005-09-27 02:23:02 +0000816static void clear_array(xhash *array)
817{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000818 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000819 hash_item *hi, *thi;
820
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000821 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000822 hi = array->items[i];
823 while (hi) {
824 thi = hi;
825 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000826 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000827 free(thi);
828 }
829 array->items[i] = NULL;
830 }
831 array->glen = array->nel = 0;
832}
833
834/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000835static var *clrvar(var *v)
836{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000837 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000838 free(v->string);
839
840 v->type &= VF_DONTTOUCH;
841 v->type |= VF_DIRTY;
842 v->string = NULL;
843 return v;
844}
845
846/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000847static var *setvar_p(var *v, char *value)
848{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000849 clrvar(v);
850 v->string = value;
851 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000852 return v;
853}
854
855/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000856static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000857{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000858 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000859}
860
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100861/* same as setvar_s but sets USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000862static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000863{
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100864 v = setvar_s(v, value);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000865 v->type |= VF_USER;
866 return v;
867}
868
869/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000870static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000871{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000872 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000873
Denys Vlasenko7bb346f2009-10-06 22:09:50 +0200874 v = findvar(iamarray(a), itoa(idx));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000875 setvar_u(v, s);
876}
877
878/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000879static var *setvar_i(var *v, double value)
880{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000881 clrvar(v);
882 v->type |= VF_NUMBER;
883 v->number = value;
884 handle_special(v);
885 return v;
886}
887
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000888static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000889{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000890 /* if v is numeric and has no cached string, convert it to string */
891 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000892 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
893 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000894 v->type |= VF_CACHED;
895 }
896 return (v->string == NULL) ? "" : v->string;
897}
898
Mike Frysinger10a11e22005-09-27 02:23:02 +0000899static double getvar_i(var *v)
900{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000901 char *s;
902
903 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
904 v->number = 0;
905 s = v->string;
906 if (s && *s) {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200907 debug_printf_eval("getvar_i: '%s'->", s);
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000908 v->number = my_strtod(&s);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200909 debug_printf_eval("%f (s:'%s')\n", v->number, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000910 if (v->type & VF_USER) {
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100911 s = skip_spaces(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000912 if (*s != '\0')
913 v->type &= ~VF_USER;
914 }
915 } else {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200916 debug_printf_eval("getvar_i: '%s'->zero\n", s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000917 v->type &= ~VF_USER;
918 }
919 v->type |= VF_CACHED;
920 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200921 debug_printf_eval("getvar_i: %f\n", v->number);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000922 return v->number;
923}
924
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000925/* Used for operands of bitwise ops */
926static unsigned long getvar_i_int(var *v)
927{
928 double d = getvar_i(v);
929
930 /* Casting doubles to longs is undefined for values outside
931 * of target type range. Try to widen it as much as possible */
932 if (d >= 0)
933 return (unsigned long)d;
Denis Vlasenko665eaff2008-09-05 04:59:02 +0000934 /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000935 return - (long) (unsigned long) (-d);
936}
937
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000938static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000939{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000940 if (dest != src) {
941 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000942 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200943 debug_printf_eval("copyvar: number:%f string:'%s'\n", src->number, src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000944 dest->number = src->number;
945 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000946 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000947 }
948 handle_special(dest);
949 return dest;
950}
951
Mike Frysinger10a11e22005-09-27 02:23:02 +0000952static var *incvar(var *v)
953{
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100954 return setvar_i(v, getvar_i(v) + 1.0);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000955}
956
957/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000958static int is_numeric(var *v)
959{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000960 getvar_i(v);
961 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
962}
963
964/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000965static int istrue(var *v)
966{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000967 if (is_numeric(v))
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100968 return (v->number != 0);
969 return (v->string && v->string[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000970}
971
Eric Andersenaff114c2004-04-14 17:51:38 +0000972/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000973static var *nvalloc(int n)
974{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000975 nvblock *pb = NULL;
976 var *v, *r;
977 int size;
978
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000979 while (g_cb) {
980 pb = g_cb;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100981 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size)
982 break;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000983 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000984 }
985
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000986 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000987 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000988 g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000989 g_cb->size = size;
990 g_cb->pos = g_cb->nv;
991 g_cb->prev = pb;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000992 /*g_cb->next = NULL; - xzalloc did it */
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100993 if (pb)
994 pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000995 }
996
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000997 v = r = g_cb->pos;
998 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000999
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001000 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001001 v->type = 0;
1002 v->string = NULL;
1003 v++;
1004 }
1005
1006 return r;
1007}
1008
Mike Frysinger10a11e22005-09-27 02:23:02 +00001009static void nvfree(var *v)
1010{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001011 var *p;
1012
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001013 if (v < g_cb->nv || v >= g_cb->pos)
1014 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001015
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001016 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001017 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001018 clear_array(iamarray(p));
1019 free(p->x.array->items);
1020 free(p->x.array);
1021 }
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001022 if (p->type & VF_WALK) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001023 walker_list *n;
1024 walker_list *w = p->x.walker;
1025 debug_printf_walker("nvfree: freeing walker @%p\n", &p->x.walker);
1026 p->x.walker = NULL;
1027 while (w) {
1028 n = w->prev;
1029 debug_printf_walker(" free(%p)\n", w);
1030 free(w);
1031 w = n;
1032 }
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001033 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001034 clrvar(p);
1035 }
1036
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001037 g_cb->pos = v;
1038 while (g_cb->prev && g_cb->pos == g_cb->nv) {
1039 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001040 }
1041}
1042
1043/* ------- awk program text parsing ------- */
1044
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001045/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +00001046 * If token isn't expected, give away. Return token class
1047 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001048static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001049{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001050#define concat_inserted (G.next_token__concat_inserted)
1051#define save_tclass (G.next_token__save_tclass)
1052#define save_info (G.next_token__save_info)
1053/* Initialized to TC_OPTERM: */
1054#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001055
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001056 char *p, *s;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001057 const char *tl;
1058 uint32_t tc;
1059 const uint32_t *ti;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001060
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001061 if (t_rollback) {
1062 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001063
1064 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001065 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001066 t_tclass = save_tclass;
1067 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001068
1069 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001070 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001071 readnext:
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +01001072 p = skip_spaces(p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001073 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001074 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001075 while (*p != '\n' && *p != '\0')
1076 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001077
1078 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001079 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001080
1081 if (*p == '\0') {
1082 tc = TC_EOF;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001083 debug_printf_parse("%s: token found: TC_EOF\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001084
1085 } else if (*p == '\"') {
1086 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001087 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001088 while (*p != '\"') {
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02001089 char *pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001090 if (*p == '\0' || *p == '\n')
1091 syntax_error(EMSG_UNEXP_EOS);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02001092 pp = p;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001093 *s++ = nextchar(&pp);
1094 p = pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001095 }
1096 p++;
1097 *s = '\0';
1098 tc = TC_STRING;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001099 debug_printf_parse("%s: token found:'%s' TC_STRING\n", __func__, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001100
1101 } else if ((expected & TC_REGEXP) && *p == '/') {
1102 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001103 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001104 while (*p != '/') {
1105 if (*p == '\0' || *p == '\n')
1106 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +00001107 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001108 if (*s++ == '\\') {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001109 char *pp = p;
1110 s[-1] = bb_process_escape_sequence((const char **)&pp);
1111 if (*p == '\\')
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001112 *s++ = '\\';
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001113 if (pp == p)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001114 *s++ = *p++;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001115 else
1116 p = pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001117 }
1118 }
1119 p++;
1120 *s = '\0';
1121 tc = TC_REGEXP;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001122 debug_printf_parse("%s: token found:'%s' TC_REGEXP\n", __func__, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001123
1124 } else if (*p == '.' || isdigit(*p)) {
1125 /* it's a number */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001126 char *pp = p;
1127 t_double = my_strtod(&pp);
1128 p = pp;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001129 if (*p == '.')
Glenn L McGrath545106f2002-11-11 06:21:00 +00001130 syntax_error(EMSG_UNEXP_TOKEN);
1131 tc = TC_NUMBER;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001132 debug_printf_parse("%s: token found:%f TC_NUMBER\n", __func__, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001133
1134 } else {
1135 /* search for something known */
1136 tl = tokenlist;
1137 tc = 0x00000001;
1138 ti = tokeninfo;
1139 while (*tl) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001140 int l = (unsigned char) *tl++;
1141 if (l == (unsigned char) NTCC) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001142 tc <<= 1;
1143 continue;
1144 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001145 /* if token class is expected,
1146 * token matches,
1147 * and it's not a longer word,
Glenn L McGrath545106f2002-11-11 06:21:00 +00001148 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001149 if ((tc & (expected | TC_WORD | TC_NEWLINE))
Denys Vlasenko28458c62010-10-05 16:49:03 +02001150 && strncmp(p, tl, l) == 0
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001151 && !((tc & TC_WORD) && isalnum_(p[l]))
1152 ) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001153 /* then this is what we are looking for */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001154 t_info = *ti;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001155 debug_printf_parse("%s: token found:'%.*s' t_info:%x\n", __func__, l, p, t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001156 p += l;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001157 goto token_found;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001158 }
1159 ti++;
1160 tl += l;
1161 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001162 /* not a known token */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001163
Denys Vlasenko28458c62010-10-05 16:49:03 +02001164 /* is it a name? (var/array/function) */
1165 if (!isalnum_(*p))
1166 syntax_error(EMSG_UNEXP_TOKEN); /* no */
1167 /* yes */
1168 t_string = --p;
1169 while (isalnum_(*++p)) {
1170 p[-1] = *p;
1171 }
1172 p[-1] = '\0';
1173 tc = TC_VARIABLE;
1174 /* also consume whitespace between functionname and bracket */
1175 if (!(expected & TC_VARIABLE) || (expected & TC_ARRAY))
1176 p = skip_spaces(p);
1177 if (*p == '(') {
1178 tc = TC_FUNCTION;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001179 debug_printf_parse("%s: token found:'%s' TC_FUNCTION\n", __func__, t_string);
Denys Vlasenko28458c62010-10-05 16:49:03 +02001180 } else {
1181 if (*p == '[') {
1182 p++;
1183 tc = TC_ARRAY;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001184 debug_printf_parse("%s: token found:'%s' TC_ARRAY\n", __func__, t_string);
1185 } else
1186 debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001187 }
1188 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001189 token_found:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001190 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001191
1192 /* skipping newlines in some cases */
1193 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1194 goto readnext;
1195
1196 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001197 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001198 concat_inserted = TRUE;
1199 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001200 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001201 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001202 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001203 }
1204
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001205 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001206 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001207 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001208
1209 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001210 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001211 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001212 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001213
1214 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001215#undef concat_inserted
1216#undef save_tclass
1217#undef save_info
1218#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001219}
1220
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001221static void rollback_token(void)
1222{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001223 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001224}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001225
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001226static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001227{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001228 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001229
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001230 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001231 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001232 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001233 return n;
1234}
1235
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001236static void mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001237{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001238 n->info = OC_REGEXP;
1239 n->l.re = re;
1240 n->r.ire = re + 1;
1241 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001242 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001243}
1244
Mike Frysinger10a11e22005-09-27 02:23:02 +00001245static node *condition(void)
1246{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001247 next_token(TC_SEQSTART);
1248 return parse_expr(TC_SEQTERM);
1249}
1250
1251/* parse expression terminated by given argument, return ptr
1252 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001253static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001254{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001255 node sn;
1256 node *cn = &sn;
1257 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001258 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001259 var *v;
1260
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001261 debug_printf_parse("%s(%x)\n", __func__, iexp);
1262
Glenn L McGrath545106f2002-11-11 06:21:00 +00001263 sn.info = PRIMASK;
1264 sn.r.n = glptr = NULL;
1265 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1266
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001267 while (!((tc = next_token(xtc)) & iexp)) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001268
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001269 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001270 /* input redirection (<) attached to glptr node */
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001271 debug_printf_parse("%s: input redir\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001272 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001273 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001274 xtc = TC_OPERAND | TC_UOPPRE;
1275 glptr = NULL;
1276
1277 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001278 debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001279 /* for binary and postfix-unary operators, jump back over
1280 * previous operators with higher priority */
1281 vn = cn;
Denys Vlasenkocdeda162009-11-30 01:14:16 +01001282 while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1283 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON))
1284 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001285 vn = vn->a.n;
Denys Vlasenkocdeda162009-11-30 01:14:16 +01001286 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001287 if ((t_info & OPCLSMASK) == OC_TERNARY)
1288 t_info += P(6);
1289 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001290 cn->a.n = vn->a.n;
1291 if (tc & TC_BINOP) {
1292 cn->l.n = vn;
1293 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001294 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001295 /* it's a pipe */
1296 next_token(TC_GETLINE);
1297 /* give maximum priority to this pipe */
1298 cn->info &= ~PRIMASK;
1299 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1300 }
1301 } else {
1302 cn->r.n = vn;
1303 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1304 }
1305 vn->a.n = cn;
1306
1307 } else {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001308 debug_printf_parse("%s: other\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001309 /* for operands and prefix-unary operators, attach them
1310 * to last node */
1311 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001312 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001313 cn->a.n = vn;
1314 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1315 if (tc & (TC_OPERAND | TC_REGEXP)) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001316 debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__);
Rob Landleyed830e82005-06-07 02:43:52 +00001317 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001318 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001319 * only simple tclasses should be used! */
1320 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001321 case TC_VARIABLE:
1322 case TC_ARRAY:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001323 debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001324 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001325 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001326 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001327 cn->info = OC_FNARG;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001328 cn->l.aidx = v->x.aidx;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001329 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001330 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001331 }
1332 if (tc & TC_ARRAY) {
1333 cn->info |= xS;
1334 cn->r.n = parse_expr(TC_ARRTERM);
1335 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001336 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001337
Denis Vlasenkof782f522007-01-01 23:51:30 +00001338 case TC_NUMBER:
1339 case TC_STRING:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001340 debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001341 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001342 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001343 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001344 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001345 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001346 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001347 break;
1348
Denis Vlasenkof782f522007-01-01 23:51:30 +00001349 case TC_REGEXP:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001350 debug_printf_parse("%s: TC_REGEXP\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001351 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001352 break;
1353
Denis Vlasenkof782f522007-01-01 23:51:30 +00001354 case TC_FUNCTION:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001355 debug_printf_parse("%s: TC_FUNCTION\n", __func__);
Mike Frysingerde2b9382005-09-27 03:18:00 +00001356 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001357 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001358 cn->l.n = condition();
1359 break;
1360
Denis Vlasenkof782f522007-01-01 23:51:30 +00001361 case TC_SEQSTART:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001362 debug_printf_parse("%s: TC_SEQSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001363 cn = vn->r.n = parse_expr(TC_SEQTERM);
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001364 if (!cn)
1365 syntax_error("Empty sequence");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001366 cn->a.n = vn;
1367 break;
1368
Denis Vlasenkof782f522007-01-01 23:51:30 +00001369 case TC_GETLINE:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001370 debug_printf_parse("%s: TC_GETLINE\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001371 glptr = cn;
1372 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1373 break;
1374
Denis Vlasenkof782f522007-01-01 23:51:30 +00001375 case TC_BUILTIN:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001376 debug_printf_parse("%s: TC_BUILTIN\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001377 cn->l.n = condition();
1378 break;
1379 }
1380 }
1381 }
1382 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001383
1384 debug_printf_parse("%s() returns %p\n", __func__, sn.r.n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001385 return sn.r.n;
1386}
1387
1388/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001389static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001390{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001391 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001392
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001393 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001394 seq->first = seq->last = new_node(0);
1395
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001396 if (seq->programname != g_progname) {
1397 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001398 n = chain_node(OC_NEWSOURCE);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001399 n->l.new_progname = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001400 }
1401
1402 n = seq->last;
1403 n->info = info;
1404 seq->last = n->a.n = new_node(OC_DONE);
1405
1406 return n;
1407}
1408
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001409static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001410{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001411 node *n;
1412
1413 n = chain_node(info);
1414 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001415 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001416 rollback_token();
1417}
1418
Mike Frysinger10a11e22005-09-27 02:23:02 +00001419static node *chain_loop(node *nn)
1420{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001421 node *n, *n2, *save_brk, *save_cont;
1422
1423 save_brk = break_ptr;
1424 save_cont = continue_ptr;
1425
1426 n = chain_node(OC_BR | Vx);
1427 continue_ptr = new_node(OC_EXEC);
1428 break_ptr = new_node(OC_EXEC);
1429 chain_group();
1430 n2 = chain_node(OC_EXEC | Vx);
1431 n2->l.n = nn;
1432 n2->a.n = n;
1433 continue_ptr->a.n = n2;
1434 break_ptr->a.n = n->r.n = seq->last;
1435
1436 continue_ptr = save_cont;
1437 break_ptr = save_brk;
1438
1439 return n;
1440}
1441
1442/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001443static void chain_group(void)
1444{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001445 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001446 node *n, *n2, *n3;
1447
1448 do {
1449 c = next_token(TC_GRPSEQ);
1450 } while (c & TC_NEWLINE);
1451
1452 if (c & TC_GRPSTART) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001453 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001454 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001455 debug_printf_parse("%s: !TC_GRPTERM\n", __func__);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001456 if (t_tclass & TC_NEWLINE)
1457 continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001458 rollback_token();
1459 chain_group();
1460 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001461 debug_printf_parse("%s: TC_GRPTERM\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001462 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001463 debug_printf_parse("%s: TC_OPSEQ | TC_OPTERM\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001464 rollback_token();
1465 chain_expr(OC_EXEC | Vx);
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001466 } else {
1467 /* TC_STATEMNT */
1468 debug_printf_parse("%s: TC_STATEMNT(?)\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001469 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001470 case ST_IF:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001471 debug_printf_parse("%s: ST_IF\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001472 n = chain_node(OC_BR | Vx);
1473 n->l.n = condition();
1474 chain_group();
1475 n2 = chain_node(OC_EXEC);
1476 n->r.n = seq->last;
1477 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001478 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001479 n2->a.n = seq->last;
1480 } else {
1481 rollback_token();
1482 }
1483 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001484
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001485 case ST_WHILE:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001486 debug_printf_parse("%s: ST_WHILE\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001487 n2 = condition();
1488 n = chain_loop(NULL);
1489 n->l.n = n2;
1490 break;
1491
1492 case ST_DO:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001493 debug_printf_parse("%s: ST_DO\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001494 n2 = chain_node(OC_EXEC);
1495 n = chain_loop(NULL);
1496 n2->a.n = n->a.n;
1497 next_token(TC_WHILE);
1498 n->l.n = condition();
1499 break;
1500
1501 case ST_FOR:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001502 debug_printf_parse("%s: ST_FOR\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001503 next_token(TC_SEQSTART);
1504 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001505 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001506 if ((n2->info & OPCLSMASK) != OC_IN)
1507 syntax_error(EMSG_UNEXP_TOKEN);
1508 n = chain_node(OC_WALKINIT | VV);
1509 n->l.n = n2->l.n;
1510 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001511 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001512 n->info = OC_WALKNEXT | Vx;
1513 n->l.n = n2->l.n;
1514 } else { /* for (;;) */
1515 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001516 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001517 n2 = parse_expr(TC_SEMICOL);
1518 n3 = parse_expr(TC_SEQTERM);
1519 n = chain_loop(n3);
1520 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001521 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001522 n->info = OC_EXEC;
1523 }
1524 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001525
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001526 case OC_PRINT:
1527 case OC_PRINTF:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001528 debug_printf_parse("%s: OC_PRINT[F]\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001529 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001530 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001531 if (t_tclass & TC_OUTRDR) {
1532 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001533 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1534 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001535 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001536 rollback_token();
1537 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001538
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001539 case OC_BREAK:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001540 debug_printf_parse("%s: OC_BREAK\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001541 n = chain_node(OC_EXEC);
1542 n->a.n = break_ptr;
Denys Vlasenko5f8daef2014-06-26 16:40:28 +02001543 chain_expr(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001544 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001545
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001546 case OC_CONTINUE:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001547 debug_printf_parse("%s: OC_CONTINUE\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001548 n = chain_node(OC_EXEC);
1549 n->a.n = continue_ptr;
Denys Vlasenko5f8daef2014-06-26 16:40:28 +02001550 chain_expr(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001551 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001552
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001553 /* delete, next, nextfile, return, exit */
1554 default:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001555 debug_printf_parse("%s: default\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001556 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001557 }
1558 }
1559}
1560
Mike Frysinger10a11e22005-09-27 02:23:02 +00001561static void parse_program(char *p)
1562{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001563 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001564 node *cn;
1565 func *f;
1566 var *v;
1567
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001568 g_pos = p;
1569 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001570 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001571 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001572
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001573 if (tclass & TC_OPTERM) {
1574 debug_printf_parse("%s: TC_OPTERM\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001575 continue;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001576 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001577
1578 seq = &mainseq;
1579 if (tclass & TC_BEGIN) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001580 debug_printf_parse("%s: TC_BEGIN\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001581 seq = &beginseq;
1582 chain_group();
1583
1584 } else if (tclass & TC_END) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001585 debug_printf_parse("%s: TC_END\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001586 seq = &endseq;
1587 chain_group();
1588
1589 } else if (tclass & TC_FUNCDECL) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001590 debug_printf_parse("%s: TC_FUNCDECL\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001591 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001592 g_pos++;
1593 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001594 f->body.first = NULL;
1595 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001596 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001597 v = findvar(ahash, t_string);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001598 v->x.aidx = f->nargs++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001599
1600 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1601 break;
1602 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001603 seq = &f->body;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001604 chain_group();
1605 clear_array(ahash);
1606
1607 } else if (tclass & TC_OPSEQ) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001608 debug_printf_parse("%s: TC_OPSEQ\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001609 rollback_token();
1610 cn = chain_node(OC_TEST);
1611 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001612 if (t_tclass & TC_GRPSTART) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001613 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001614 rollback_token();
1615 chain_group();
1616 } else {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001617 debug_printf_parse("%s: !TC_GRPSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001618 chain_node(OC_PRINT);
1619 }
1620 cn->r.n = mainseq.last;
1621
1622 } else /* if (tclass & TC_GRPSTART) */ {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001623 debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001624 rollback_token();
1625 chain_group();
1626 }
1627 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001628 debug_printf_parse("%s: TC_EOF\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001629}
1630
1631
1632/* -------- program execution part -------- */
1633
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001634static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001635{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001636 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001637 node *n;
1638
1639 re = &spl->re[0];
1640 ire = &spl->re[1];
1641 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001642 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001643 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001644 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001645 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001646 if (s[0] && s[1]) { /* strlen(s) > 1 */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001647 mk_re_node(s, n, re);
1648 } else {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001649 n->info = (uint32_t) s[0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001650 }
1651
1652 return n;
1653}
1654
1655/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001656 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001657 * be later regfree'd manually
1658 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001659static regex_t *as_regex(node *op, regex_t *preg)
1660{
Denis Vlasenko7a676642009-03-15 22:20:31 +00001661 int cflags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001662 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001663 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001664
1665 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1666 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001667 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001668 v = nvalloc(1);
1669 s = getvar_s(evaluate(op, v));
Denis Vlasenko7a676642009-03-15 22:20:31 +00001670
1671 cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED;
1672 /* Testcase where REG_EXTENDED fails (unpaired '{'):
1673 * echo Hi | awk 'gsub("@(samp|code|file)\{","");'
1674 * gawk 3.1.5 eats this. We revert to ~REG_EXTENDED
1675 * (maybe gsub is not supposed to use REG_EXTENDED?).
1676 */
1677 if (regcomp(preg, s, cflags)) {
1678 cflags &= ~REG_EXTENDED;
1679 xregcomp(preg, s, cflags);
1680 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001681 nvfree(v);
1682 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001683}
1684
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001685/* gradually increasing buffer.
1686 * note that we reallocate even if n == old_size,
1687 * and thus there is at least one extra allocated byte.
1688 */
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001689static char* qrealloc(char *b, int n, int *size)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001690{
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001691 if (!b || n >= *size) {
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001692 *size = n + (n>>1) + 80;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001693 b = xrealloc(b, *size);
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001694 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001695 return b;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001696}
1697
1698/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001699static void fsrealloc(int size)
1700{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001701 int i;
1702
1703 if (size >= maxfields) {
1704 i = maxfields;
1705 maxfields = size + 16;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001706 Fields = xrealloc(Fields, maxfields * sizeof(Fields[0]));
Denis Vlasenkof782f522007-01-01 23:51:30 +00001707 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001708 Fields[i].type = VF_SPECIAL;
1709 Fields[i].string = NULL;
1710 }
1711 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001712 /* if size < nfields, clear extra field variables */
1713 for (i = size; i < nfields; i++) {
1714 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001715 }
1716 nfields = size;
1717}
1718
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001719static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001720{
Denys Vlasenko28458c62010-10-05 16:49:03 +02001721 int l, n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001722 char c[4];
1723 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001724 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001725
1726 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001727 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1728 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001729
1730 c[0] = c[1] = (char)spl->info;
1731 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001732 if (*getvar_s(intvar[RS]) == '\0')
1733 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001734
Denys Vlasenko28458c62010-10-05 16:49:03 +02001735 n = 0;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001736 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1737 if (!*s)
1738 return n; /* "": zero fields */
1739 n++; /* at least one field will be there */
1740 do {
1741 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001742 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1743 && pmatch[0].rm_so <= l
1744 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001745 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001746 if (pmatch[0].rm_eo == 0) {
1747 l++;
1748 pmatch[0].rm_eo++;
1749 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001750 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001751 } else {
1752 pmatch[0].rm_eo = l;
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001753 if (s[l])
1754 pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001755 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001756 memcpy(s1, s, l);
Denis Vlasenko67b5eeb2009-04-12 13:54:13 +00001757 /* make sure we remove *all* of the separator chars */
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001758 do {
1759 s1[l] = '\0';
1760 } while (++l < pmatch[0].rm_eo);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001761 nextword(&s1);
1762 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001763 } while (*s);
1764 return n;
1765 }
1766 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001767 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001768 *s1++ = *s++;
1769 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001770 n++;
1771 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001772 return n;
1773 }
1774 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001775 if (icase) {
1776 c[0] = toupper(c[0]);
1777 c[1] = tolower(c[1]);
1778 }
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001779 if (*s1)
1780 n++;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001781 while ((s1 = strpbrk(s1, c)) != NULL) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001782 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001783 n++;
1784 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001785 return n;
1786 }
1787 /* space split */
1788 while (*s) {
1789 s = skip_whitespace(s);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001790 if (!*s)
1791 break;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001792 n++;
1793 while (*s && !isspace(*s))
1794 *s1++ = *s++;
1795 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001796 }
1797 return n;
1798}
1799
Mike Frysinger10a11e22005-09-27 02:23:02 +00001800static void split_f0(void)
1801{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001802/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001803#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001804
Glenn L McGrath545106f2002-11-11 06:21:00 +00001805 int i, n;
1806 char *s;
1807
1808 if (is_f0_split)
1809 return;
1810
1811 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001812 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001813 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001814 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001815 fsrealloc(n);
1816 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001817 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001818 Fields[i].string = nextword(&s);
1819 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1820 }
1821
1822 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001823 clrvar(intvar[NF]);
1824 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1825 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001826#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001827}
1828
1829/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001830static void handle_special(var *v)
1831{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001832 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001833 char *b;
1834 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001835 int sl, l, len, i, bsize;
1836
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001837 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001838 return;
1839
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001840 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001841 n = (int)getvar_i(v);
1842 fsrealloc(n);
1843
1844 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001845 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001846 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001847 b = NULL;
1848 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001849 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001850 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001851 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001852 if (b) {
1853 memcpy(b+len, sep, sl);
1854 len += sl;
1855 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001856 b = qrealloc(b, len+l+sl, &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001857 memcpy(b+len, s, l);
1858 len += l;
1859 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001860 if (b)
1861 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001862 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001863 is_f0_split = TRUE;
1864
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001865 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001866 is_f0_split = FALSE;
1867
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001868 } else if (v == intvar[FS]) {
Denys Vlasenkodf8066a2012-07-11 01:27:15 +02001869 /*
1870 * The POSIX-2008 standard says that changing FS should have no effect on the
1871 * current input line, but only on the next one. The language is:
1872 *
1873 * > Before the first reference to a field in the record is evaluated, the record
1874 * > shall be split into fields, according to the rules in Regular Expressions,
1875 * > using the value of FS that was current at the time the record was read.
1876 *
1877 * So, split up current line before assignment to FS:
1878 */
1879 split_f0();
1880
Glenn L McGrath545106f2002-11-11 06:21:00 +00001881 mk_splitter(getvar_s(v), &fsplitter);
1882
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001883 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001884 mk_splitter(getvar_s(v), &rsplitter);
1885
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001886 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001887 icase = istrue(v);
1888
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001889 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001890 n = getvar_i(intvar[NF]);
1891 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001892 /* right here v is invalid. Just to note... */
1893 }
1894}
1895
1896/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001897static node *nextarg(node **pn)
1898{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001899 node *n;
1900
1901 n = *pn;
1902 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1903 *pn = n->r.n;
1904 n = n->l.n;
1905 } else {
1906 *pn = NULL;
1907 }
1908 return n;
1909}
1910
Mike Frysinger10a11e22005-09-27 02:23:02 +00001911static void hashwalk_init(var *v, xhash *array)
1912{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001913 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001914 unsigned i;
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001915 walker_list *w;
1916 walker_list *prev_walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001917
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001918 if (v->type & VF_WALK) {
1919 prev_walker = v->x.walker;
1920 } else {
1921 v->type |= VF_WALK;
1922 prev_walker = NULL;
1923 }
1924 debug_printf_walker("hashwalk_init: prev_walker:%p\n", prev_walker);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001925
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001926 w = v->x.walker = xzalloc(sizeof(*w) + array->glen + 1); /* why + 1? */
1927 debug_printf_walker(" walker@%p=%p\n", &v->x.walker, w);
1928 w->cur = w->end = w->wbuf;
1929 w->prev = prev_walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001930 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001931 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001932 while (hi) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001933 strcpy(w->end, hi->name);
1934 nextword(&w->end);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001935 hi = hi->next;
1936 }
1937 }
1938}
1939
Mike Frysinger10a11e22005-09-27 02:23:02 +00001940static int hashwalk_next(var *v)
1941{
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001942 walker_list *w = v->x.walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001943
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001944 if (w->cur >= w->end) {
1945 walker_list *prev_walker = w->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001946
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001947 debug_printf_walker("end of iteration, free(walker@%p:%p), prev_walker:%p\n", &v->x.walker, w, prev_walker);
1948 free(w);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001949 v->x.walker = prev_walker;
1950 return FALSE;
1951 }
1952
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001953 setvar_s(v, nextword(&w->cur));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001954 return TRUE;
1955}
1956
1957/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001958static int ptest(node *pattern)
1959{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001960 /* ptest__v is "static": to save stack space? */
1961 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001962}
1963
1964/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001965static int awk_getline(rstream *rsm, var *v)
1966{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001967 char *b;
1968 regmatch_t pmatch[2];
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001969 int size, a, p, pp = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001970 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001971 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001972
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02001973 debug_printf_eval("entered %s()\n", __func__);
1974
Glenn L McGrath545106f2002-11-11 06:21:00 +00001975 /* we're using our own buffer since we need access to accumulating
1976 * characters
1977 */
1978 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001979 m = rsm->buffer;
1980 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001981 p = rsm->pos;
1982 size = rsm->size;
1983 c = (char) rsplitter.n.info;
1984 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001985
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001986 if (!m)
1987 m = qrealloc(m, 256, &size);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001988
Glenn L McGrath545106f2002-11-11 06:21:00 +00001989 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001990 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001991 so = eo = p;
1992 r = 1;
1993 if (p > 0) {
1994 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1995 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001996 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001997 so = pmatch[0].rm_so;
1998 eo = pmatch[0].rm_eo;
1999 if (b[eo] != '\0')
2000 break;
2001 }
2002 } else if (c != '\0') {
2003 s = strchr(b+pp, c);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002004 if (!s)
2005 s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002006 if (s) {
2007 so = eo = s-b;
2008 eo++;
2009 break;
2010 }
2011 } else {
2012 while (b[rp] == '\n')
2013 rp++;
2014 s = strstr(b+rp, "\n\n");
2015 if (s) {
2016 so = eo = s-b;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002017 while (b[eo] == '\n')
2018 eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002019 if (b[eo] != '\0')
2020 break;
2021 }
2022 }
2023 }
2024
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002025 if (a > 0) {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002026 memmove(m, m+a, p+1);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002027 b = m;
2028 a = 0;
2029 }
2030
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01002031 m = qrealloc(m, a+p+128, &size);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002032 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002033 pp = p;
2034 p += safe_read(fd, b+p, size-p-1);
2035 if (p < pp) {
2036 p = 0;
2037 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002038 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002039 }
2040 b[p] = '\0';
2041
2042 } while (p > pp);
2043
2044 if (p == 0) {
2045 r--;
2046 } else {
2047 c = b[so]; b[so] = '\0';
2048 setvar_s(v, b+rp);
2049 v->type |= VF_USER;
2050 b[so] = c;
2051 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002052 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002053 b[eo] = c;
2054 }
2055
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002056 rsm->buffer = m;
2057 rsm->adv = a + eo;
2058 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002059 rsm->size = size;
2060
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002061 debug_printf_eval("returning from %s(): %d\n", __func__, r);
2062
Glenn L McGrath545106f2002-11-11 06:21:00 +00002063 return r;
2064}
2065
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002066static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002067{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002068 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002069 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002070 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002071
Denys Vlasenko1390a012013-07-20 21:23:01 +02002072 if (int_as_int && n == (long long)n) {
2073 r = snprintf(b, size, "%lld", (long long)n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002074 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002075 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002076 if (strchr("diouxX", c)) {
2077 r = snprintf(b, size, format, (int)n);
2078 } else if (strchr("eEfgG", c)) {
2079 r = snprintf(b, size, format, n);
2080 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002081 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002082 }
2083 }
2084 return r;
2085}
2086
Glenn L McGrath545106f2002-11-11 06:21:00 +00002087/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002088static char *awk_printf(node *n)
2089{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002090 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002091 char *fmt, *s, *f;
2092 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002093 int i, j, incr, bsize;
2094 char c, c1;
2095 var *v, *arg;
2096
2097 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00002098 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002099
2100 i = 0;
2101 while (*f) {
2102 s = f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002103 while (*f && (*f != '%' || *++f == '%'))
Glenn L McGrath545106f2002-11-11 06:21:00 +00002104 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00002105 while (*f && !isalpha(*f)) {
2106 if (*f == '*')
2107 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002108 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00002109 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002110
2111 incr = (f - s) + MAXVARFMT;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01002112 b = qrealloc(b, incr + i, &bsize);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002113 c = *f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002114 if (c != '\0')
2115 f++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002116 c1 = *f;
2117 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00002118 arg = evaluate(nextarg(&n), v);
2119
2120 j = i;
2121 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002122 i += sprintf(b+i, s, is_numeric(arg) ?
2123 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002124 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00002125 s1 = getvar_s(arg);
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01002126 b = qrealloc(b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002127 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002128 } else {
2129 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
2130 }
2131 *f = c1;
2132
2133 /* if there was an error while sprintf, return value is negative */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002134 if (i < j)
2135 i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002136 }
2137
Glenn L McGrath545106f2002-11-11 06:21:00 +00002138 free(fmt);
2139 nvfree(v);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002140 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002141 b[i] = '\0';
2142 return b;
2143}
2144
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002145/* Common substitution routine.
2146 * Replace (nm)'th substring of (src) that matches (rn) with (repl),
2147 * store result into (dest), return number of substitutions.
2148 * If nm = 0, replace all matches.
2149 * If src or dst is NULL, use $0.
2150 * If subexp != 0, enable subexpression matching (\1-\9).
Glenn L McGrath545106f2002-11-11 06:21:00 +00002151 */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002152static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int subexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002153{
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002154 char *resbuf;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002155 const char *sp;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002156 int match_no, residx, replen, resbufsize;
2157 int regexec_flags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002158 regmatch_t pmatch[10];
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002159 regex_t sreg, *regex;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002160
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002161 resbuf = NULL;
2162 residx = 0;
2163 match_no = 0;
2164 regexec_flags = 0;
2165 regex = as_regex(rn, &sreg);
2166 sp = getvar_s(src ? src : intvar[F0]);
2167 replen = strlen(repl);
2168 while (regexec(regex, sp, 10, pmatch, regexec_flags) == 0) {
2169 int so = pmatch[0].rm_so;
2170 int eo = pmatch[0].rm_eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002171
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002172 //bb_error_msg("match %u: [%u,%u] '%s'%p", match_no+1, so, eo, sp,sp);
2173 resbuf = qrealloc(resbuf, residx + eo + replen, &resbufsize);
2174 memcpy(resbuf + residx, sp, eo);
2175 residx += eo;
2176 if (++match_no >= nm) {
2177 const char *s;
2178 int nbs;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002179
Glenn L McGrath545106f2002-11-11 06:21:00 +00002180 /* replace */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002181 residx -= (eo - so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002182 nbs = 0;
2183 for (s = repl; *s; s++) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002184 char c = resbuf[residx++] = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002185 if (c == '\\') {
2186 nbs++;
2187 continue;
2188 }
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002189 if (c == '&' || (subexp && c >= '0' && c <= '9')) {
2190 int j;
2191 residx -= ((nbs + 3) >> 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002192 j = 0;
2193 if (c != '&') {
2194 j = c - '0';
2195 nbs++;
2196 }
2197 if (nbs % 2) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002198 resbuf[residx++] = c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002199 } else {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002200 int n = pmatch[j].rm_eo - pmatch[j].rm_so;
2201 resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize);
2202 memcpy(resbuf + residx, sp + pmatch[j].rm_so, n);
2203 residx += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002204 }
2205 }
2206 nbs = 0;
2207 }
2208 }
2209
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002210 regexec_flags = REG_NOTBOL;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002211 sp += eo;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002212 if (match_no == nm)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002213 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002214 if (eo == so) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002215 /* Empty match (e.g. "b*" will match anywhere).
2216 * Advance by one char. */
2217//BUG (bug 1333):
2218//gsub(/\<b*/,"") on "abc" will reach this point, advance to "bc"
2219//... and will erroneously match "b" even though it is NOT at the word start.
2220//we need REG_NOTBOW but it does not exist...
Denys Vlasenko7379cd12010-04-04 01:48:12 +02002221//TODO: if EXTRA_COMPAT=y, use GNU matching and re_search,
2222//it should be able to do it correctly.
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002223 /* Subtle: this is safe only because
2224 * qrealloc allocated at least one extra byte */
2225 resbuf[residx] = *sp;
2226 if (*sp == '\0')
2227 goto ret;
2228 sp++;
2229 residx++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002230 }
2231 }
2232
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002233 resbuf = qrealloc(resbuf, residx + strlen(sp), &resbufsize);
2234 strcpy(resbuf + residx, sp);
2235 ret:
2236 //bb_error_msg("end sp:'%s'%p", sp,sp);
2237 setvar_p(dest ? dest : intvar[F0], resbuf);
2238 if (regex == &sreg)
2239 regfree(regex);
2240 return match_no;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002241}
2242
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002243static NOINLINE int do_mktime(const char *ds)
2244{
2245 struct tm then;
2246 int count;
2247
2248 /*memset(&then, 0, sizeof(then)); - not needed */
2249 then.tm_isdst = -1; /* default is unknown */
2250
2251 /* manpage of mktime says these fields are ints,
2252 * so we can sscanf stuff directly into them */
2253 count = sscanf(ds, "%u %u %u %u %u %u %d",
2254 &then.tm_year, &then.tm_mon, &then.tm_mday,
2255 &then.tm_hour, &then.tm_min, &then.tm_sec,
2256 &then.tm_isdst);
2257
2258 if (count < 6
2259 || (unsigned)then.tm_mon < 1
2260 || (unsigned)then.tm_year < 1900
2261 ) {
2262 return -1;
2263 }
2264
2265 then.tm_mon -= 1;
Denys Vlasenkobc3e9472009-09-21 04:16:00 +02002266 then.tm_year -= 1900;
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002267
2268 return mktime(&then);
2269}
2270
2271static NOINLINE var *exec_builtin(node *op, var *res)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002272{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002273#define tspl (G.exec_builtin__tspl)
2274
Glenn L McGrath545106f2002-11-11 06:21:00 +00002275 var *tv;
2276 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002277 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002278 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002279 regmatch_t pmatch[2];
2280 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002281 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002282 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002283 int nargs;
2284 time_t tt;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002285 int i, l, ll, n;
2286
2287 tv = nvalloc(4);
2288 isr = info = op->info;
2289 op = op->l.n;
2290
2291 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002292 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002293 an[i] = nextarg(&op);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002294 if (isr & 0x09000000)
2295 av[i] = evaluate(an[i], &tv[i]);
2296 if (isr & 0x08000000)
2297 as[i] = getvar_s(av[i]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002298 isr >>= 1;
2299 }
2300
2301 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002302 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002303 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002304
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002305 info &= OPNMASK;
2306 switch (info) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002307
Denis Vlasenkof782f522007-01-01 23:51:30 +00002308 case B_a2:
Rob Landleyd8205b32010-10-24 03:27:22 +02002309 if (ENABLE_FEATURE_AWK_LIBM)
2310 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
2311 else
2312 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002313 break;
2314
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002315 case B_sp: {
2316 char *s, *s1;
2317
Glenn L McGrath545106f2002-11-11 06:21:00 +00002318 if (nargs > 2) {
2319 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2320 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2321 } else {
2322 spl = &fsplitter.n;
2323 }
2324
2325 n = awk_split(as[0], spl, &s);
2326 s1 = s;
2327 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002328 for (i = 1; i <= n; i++)
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002329 setari_u(av[1], i, nextword(&s));
2330 free(s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002331 setvar_i(res, n);
2332 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002333 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002334
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002335 case B_ss: {
2336 char *s;
2337
Rob Landleya3896512006-05-07 20:20:34 +00002338 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002339 i = getvar_i(av[1]) - 1;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002340 if (i > l)
2341 i = l;
2342 if (i < 0)
2343 i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002344 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002345 if (n < 0)
2346 n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002347 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002348 setvar_p(res, s);
2349 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002350 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002351
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002352 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2353 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002354 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002355 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002356 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002357
Denis Vlasenkof782f522007-01-01 23:51:30 +00002358 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002359 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002360 break;
2361
Denis Vlasenkof782f522007-01-01 23:51:30 +00002362 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002363 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002364 break;
2365
Denis Vlasenkof782f522007-01-01 23:51:30 +00002366 case B_or:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002367 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002368 break;
2369
Denis Vlasenkof782f522007-01-01 23:51:30 +00002370 case B_rs:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002371 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002372 break;
2373
Denis Vlasenkof782f522007-01-01 23:51:30 +00002374 case B_xo:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002375 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002376 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002377
Denis Vlasenkof782f522007-01-01 23:51:30 +00002378 case B_lo:
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002379 case B_up: {
2380 char *s, *s1;
Rob Landleyd921b2e2006-08-03 15:41:12 +00002381 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002382 while (*s1) {
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002383 //*s1 = (info == B_up) ? toupper(*s1) : tolower(*s1);
2384 if ((unsigned char)((*s1 | 0x20) - 'a') <= ('z' - 'a'))
2385 *s1 = (info == B_up) ? (*s1 & 0xdf) : (*s1 | 0x20);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002386 s1++;
2387 }
2388 setvar_p(res, s);
2389 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002390 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002391
Denis Vlasenkof782f522007-01-01 23:51:30 +00002392 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002393 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002394 ll = strlen(as[1]);
2395 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002396 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002397 if (!icase) {
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002398 char *s = strstr(as[0], as[1]);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002399 if (s)
2400 n = (s - as[0]) + 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002401 } else {
2402 /* this piece of code is terribly slow and
2403 * really should be rewritten
2404 */
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002405 for (i = 0; i <= l; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002406 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2407 n = i+1;
2408 break;
2409 }
2410 }
2411 }
2412 }
2413 setvar_i(res, n);
2414 break;
2415
Denis Vlasenkof782f522007-01-01 23:51:30 +00002416 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002417 if (nargs > 1)
2418 tt = getvar_i(av[1]);
2419 else
2420 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002421 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002422 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002423 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2424 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002425 g_buf[i] = '\0';
2426 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002427 break;
2428
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002429 case B_mt:
2430 setvar_i(res, do_mktime(as[0]));
2431 break;
2432
Denis Vlasenkof782f522007-01-01 23:51:30 +00002433 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002434 re = as_regex(an[1], &sreg);
2435 n = regexec(re, as[0], 1, pmatch, 0);
2436 if (n == 0) {
2437 pmatch[0].rm_so++;
2438 pmatch[0].rm_eo++;
2439 } else {
2440 pmatch[0].rm_so = 0;
2441 pmatch[0].rm_eo = -1;
2442 }
2443 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2444 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2445 setvar_i(res, pmatch[0].rm_so);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002446 if (re == &sreg)
2447 regfree(re);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002448 break;
2449
Denis Vlasenkof782f522007-01-01 23:51:30 +00002450 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002451 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2452 break;
2453
Denis Vlasenkof782f522007-01-01 23:51:30 +00002454 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002455 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2456 break;
2457
Denis Vlasenkof782f522007-01-01 23:51:30 +00002458 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002459 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2460 break;
2461 }
2462
2463 nvfree(tv);
2464 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002465#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002466}
2467
2468/*
2469 * Evaluate node - the heart of the program. Supplied with subtree
2470 * and place where to store result. returns ptr to result.
2471 */
2472#define XC(n) ((n) >> 8)
2473
Mike Frysinger10a11e22005-09-27 02:23:02 +00002474static var *evaluate(node *op, var *res)
2475{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002476/* This procedure is recursive so we should count every byte */
2477#define fnargs (G.evaluate__fnargs)
2478/* seed is initialized to 1 */
2479#define seed (G.evaluate__seed)
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002480#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002481
Glenn L McGrath545106f2002-11-11 06:21:00 +00002482 var *v1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002483
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002484 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002485 return setvar_s(res, NULL);
2486
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002487 debug_printf_eval("entered %s()\n", __func__);
2488
Glenn L McGrath545106f2002-11-11 06:21:00 +00002489 v1 = nvalloc(2);
2490
2491 while (op) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002492 struct {
2493 var *v;
2494 const char *s;
2495 } L = L; /* for compiler */
2496 struct {
2497 var *v;
2498 const char *s;
2499 } R = R;
2500 double L_d = L_d;
2501 uint32_t opinfo;
2502 int opn;
2503 node *op1;
2504
Glenn L McGrath545106f2002-11-11 06:21:00 +00002505 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002506 opn = (opinfo & OPNMASK);
2507 g_lineno = op->lineno;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002508 op1 = op->l.n;
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002509 debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002510
Mike Frysingerde2b9382005-09-27 03:18:00 +00002511 /* execute inevitable things */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002512 if (opinfo & OF_RES1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002513 L.v = evaluate(op1, v1);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002514 if (opinfo & OF_RES2)
2515 R.v = evaluate(op->r.n, v1+1);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002516 if (opinfo & OF_STR1) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002517 L.s = getvar_s(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002518 debug_printf_eval("L.s:'%s'\n", L.s);
2519 }
2520 if (opinfo & OF_STR2) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002521 R.s = getvar_s(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002522 debug_printf_eval("R.s:'%s'\n", R.s);
2523 }
2524 if (opinfo & OF_NUM1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002525 L_d = getvar_i(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002526 debug_printf_eval("L_d:%f\n", L_d);
2527 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002528
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002529 debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002530 switch (XC(opinfo & OPCLSMASK)) {
2531
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002532 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002533
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002534 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002535 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002536 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2537 /* it's range pattern */
2538 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2539 op->info |= OF_CHECKED;
2540 if (ptest(op1->r.n))
2541 op->info &= ~OF_CHECKED;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002542 op = op->a.n;
2543 } else {
2544 op = op->r.n;
2545 }
2546 } else {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002547 op = ptest(op1) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002548 }
2549 break;
2550
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002551 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002552 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002553 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002554
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002555 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002556 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002557 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002558 break;
2559
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002560 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002561 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002562 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002563 break;
2564
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002565 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002566 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002567 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2568 break;
2569
Denis Vlasenkof782f522007-01-01 23:51:30 +00002570 case XC( OC_PRINT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002571 case XC( OC_PRINTF ): {
2572 FILE *F = stdout;
2573
Mike Frysingerde2b9382005-09-27 03:18:00 +00002574 if (op->r.n) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002575 rstream *rsm = newfile(R.s);
2576 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002577 if (opn == '|') {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002578 rsm->F = popen(R.s, "w");
2579 if (rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002580 bb_perror_msg_and_die("popen");
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002581 rsm->is_pipe = 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002582 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002583 rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002584 }
2585 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002586 F = rsm->F;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002587 }
2588
2589 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002590 if (!op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002591 fputs(getvar_s(intvar[F0]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002592 } else {
2593 while (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002594 var *v = evaluate(nextarg(&op1), v1);
2595 if (v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002596 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002597 getvar_i(v), TRUE);
2598 fputs(g_buf, F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002599 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002600 fputs(getvar_s(v), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002601 }
2602
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002603 if (op1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002604 fputs(getvar_s(intvar[OFS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002605 }
2606 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002607 fputs(getvar_s(intvar[ORS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002608
2609 } else { /* OC_PRINTF */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002610 char *s = awk_printf(op1);
2611 fputs(s, F);
2612 free(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002613 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002614 fflush(F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002615 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002616 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002617
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002618 case XC( OC_DELETE ): {
2619 uint32_t info = op1->info & OPCLSMASK;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002620 var *v;
2621
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002622 if (info == OC_VAR) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002623 v = op1->l.v;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002624 } else if (info == OC_FNARG) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002625 v = &fnargs[op1->l.aidx];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002626 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002627 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002628 }
2629
Mike Frysingerde2b9382005-09-27 03:18:00 +00002630 if (op1->r.n) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002631 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002632 clrvar(L.v);
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002633 s = getvar_s(evaluate(op1->r.n, v1));
2634 hash_remove(iamarray(v), s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002635 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002636 clear_array(iamarray(v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002637 }
2638 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002639 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002640
Denis Vlasenkof782f522007-01-01 23:51:30 +00002641 case XC( OC_NEWSOURCE ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002642 g_progname = op->l.new_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002643 break;
2644
Denis Vlasenkof782f522007-01-01 23:51:30 +00002645 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002646 copyvar(res, L.v);
2647 break;
2648
Denis Vlasenkof782f522007-01-01 23:51:30 +00002649 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002650 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002651 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002652 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002653 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002654 clrvar(res);
2655 break;
2656
Denis Vlasenkof782f522007-01-01 23:51:30 +00002657 case XC( OC_EXIT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002658 awk_exit(L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002659
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002660 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002661
Denis Vlasenkof782f522007-01-01 23:51:30 +00002662 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002663 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002664 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002665 split_f0();
2666 goto v_cont;
2667
Denis Vlasenkof782f522007-01-01 23:51:30 +00002668 case XC( OC_FNARG ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002669 L.v = &fnargs[op->l.aidx];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002670 v_cont:
2671 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002672 break;
2673
Denis Vlasenkof782f522007-01-01 23:51:30 +00002674 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002675 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2676 break;
2677
Denis Vlasenkof782f522007-01-01 23:51:30 +00002678 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002679 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002680 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002681 goto re_cont;
2682
Denis Vlasenkof782f522007-01-01 23:51:30 +00002683 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002684 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002685 re_cont:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002686 {
2687 regex_t *re = as_regex(op1, &sreg);
2688 int i = regexec(re, L.s, 0, NULL, 0);
2689 if (re == &sreg)
2690 regfree(re);
2691 setvar_i(res, (i == 0) ^ (opn == '!'));
2692 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002693 break;
2694
Denis Vlasenkof782f522007-01-01 23:51:30 +00002695 case XC( OC_MOVE ):
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002696 debug_printf_eval("MOVE\n");
Mike Frysingerde2b9382005-09-27 03:18:00 +00002697 /* if source is a temporary string, jusk relink it to dest */
Denys Vlasenko12847742009-11-30 01:15:04 +01002698//Disabled: if R.v is numeric but happens to have cached R.v->string,
2699//then L.v ends up being a string, which is wrong
2700// if (R.v == v1+1 && R.v->string) {
2701// res = setvar_p(L.v, R.v->string);
2702// R.v->string = NULL;
2703// } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002704 res = copyvar(L.v, R.v);
Denys Vlasenko12847742009-11-30 01:15:04 +01002705// }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002706 break;
2707
Denis Vlasenkof782f522007-01-01 23:51:30 +00002708 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002709 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002710 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002711 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2712 break;
2713
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002714 case XC( OC_FUNC ): {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002715 var *vbeg, *v;
2716 const char *sv_progname;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002717
Bernhard Reutner-Fischerb79a0fe2013-03-06 21:01:05 +01002718 /* The body might be empty, still has to eval the args */
Bernhard Reutner-Fischera060a1a2013-07-31 15:29:20 +02002719 if (!op->r.n->info && !op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002720 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002721
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002722 vbeg = v = nvalloc(op->r.f->nargs + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002723 while (op1) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002724 var *arg = evaluate(nextarg(&op1), v1);
2725 copyvar(v, arg);
2726 v->type |= VF_CHILD;
2727 v->x.parent = arg;
2728 if (++v - vbeg >= op->r.f->nargs)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002729 break;
2730 }
2731
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002732 v = fnargs;
2733 fnargs = vbeg;
2734 sv_progname = g_progname;
2735
2736 res = evaluate(op->r.f->body.first, res);
2737
2738 g_progname = sv_progname;
2739 nvfree(fnargs);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002740 fnargs = v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002741
Glenn L McGrath545106f2002-11-11 06:21:00 +00002742 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002743 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002744
Denis Vlasenkof782f522007-01-01 23:51:30 +00002745 case XC( OC_GETLINE ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002746 case XC( OC_PGETLINE ): {
2747 rstream *rsm;
2748 int i;
2749
Mike Frysingerde2b9382005-09-27 03:18:00 +00002750 if (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002751 rsm = newfile(L.s);
2752 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002753 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002754 rsm->F = popen(L.s, "r");
2755 rsm->is_pipe = TRUE;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002756 } else {
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002757 rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002758 }
2759 }
2760 } else {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002761 if (!iF)
2762 iF = next_input_file();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002763 rsm = iF;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002764 }
2765
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02002766 if (!rsm || !rsm->F) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002767 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002768 setvar_i(res, -1);
2769 break;
2770 }
2771
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002772 if (!op->r.n)
2773 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002774
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002775 i = awk_getline(rsm, R.v);
2776 if (i > 0 && !op1) {
2777 incvar(intvar[FNR]);
2778 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002779 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002780 setvar_i(res, i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002781 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002782 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002783
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002784 /* simple builtins */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002785 case XC( OC_FBLTIN ): {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002786 double R_d = R_d; /* for compiler */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002787
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002788 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002789 case F_in:
Denys Vlasenko1390a012013-07-20 21:23:01 +02002790 R_d = (long long)L_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002791 break;
2792
Denis Vlasenkof782f522007-01-01 23:51:30 +00002793 case F_rn:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002794 R_d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002795 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002796
Denis Vlasenkof782f522007-01-01 23:51:30 +00002797 case F_co:
Rob Landleyd8205b32010-10-24 03:27:22 +02002798 if (ENABLE_FEATURE_AWK_LIBM) {
2799 R_d = cos(L_d);
2800 break;
2801 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002802
Denis Vlasenkof782f522007-01-01 23:51:30 +00002803 case F_ex:
Rob Landleyd8205b32010-10-24 03:27:22 +02002804 if (ENABLE_FEATURE_AWK_LIBM) {
2805 R_d = exp(L_d);
2806 break;
2807 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002808
Denis Vlasenkof782f522007-01-01 23:51:30 +00002809 case F_lg:
Rob Landleyd8205b32010-10-24 03:27:22 +02002810 if (ENABLE_FEATURE_AWK_LIBM) {
2811 R_d = log(L_d);
2812 break;
2813 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002814
Denis Vlasenkof782f522007-01-01 23:51:30 +00002815 case F_si:
Rob Landleyd8205b32010-10-24 03:27:22 +02002816 if (ENABLE_FEATURE_AWK_LIBM) {
2817 R_d = sin(L_d);
2818 break;
2819 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002820
Denis Vlasenkof782f522007-01-01 23:51:30 +00002821 case F_sq:
Rob Landleyd8205b32010-10-24 03:27:22 +02002822 if (ENABLE_FEATURE_AWK_LIBM) {
2823 R_d = sqrt(L_d);
2824 break;
2825 }
2826
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002827 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002828 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002829
Denis Vlasenkof782f522007-01-01 23:51:30 +00002830 case F_sr:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002831 R_d = (double)seed;
2832 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002833 srand(seed);
2834 break;
2835
Denis Vlasenkof782f522007-01-01 23:51:30 +00002836 case F_ti:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002837 R_d = time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002838 break;
2839
Denis Vlasenkof782f522007-01-01 23:51:30 +00002840 case F_le:
Denys Vlasenko7985bc12013-10-12 04:51:54 +02002841 debug_printf_eval("length: L.s:'%s'\n", L.s);
2842 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002843 L.s = getvar_s(intvar[F0]);
Denys Vlasenko7985bc12013-10-12 04:51:54 +02002844 debug_printf_eval("length: L.s='%s'\n", L.s);
2845 }
2846 else if (L.v->type & VF_ARRAY) {
2847 R_d = L.v->x.array->nel;
2848 debug_printf_eval("length: array_len:%d\n", L.v->x.array->nel);
2849 break;
2850 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002851 R_d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002852 break;
2853
Denis Vlasenkof782f522007-01-01 23:51:30 +00002854 case F_sy:
Denys Vlasenko8131eea2009-11-02 14:19:51 +01002855 fflush_all();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002856 R_d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002857 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002858 break;
2859
Denis Vlasenkof782f522007-01-01 23:51:30 +00002860 case F_ff:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002861 if (!op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002862 fflush(stdout);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002863 } else if (L.s && *L.s) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002864 rstream *rsm = newfile(L.s);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002865 fflush(rsm->F);
2866 } else {
2867 fflush_all();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002868 }
2869 break;
2870
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002871 case F_cl: {
2872 rstream *rsm;
2873 int err = 0;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002874 rsm = (rstream *)hash_search(fdhash, L.s);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002875 debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002876 if (rsm) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002877 debug_printf_eval("OC_FBLTIN F_cl "
2878 "rsm->is_pipe:%d, ->F:%p\n",
2879 rsm->is_pipe, rsm->F);
2880 /* Can be NULL if open failed. Example:
2881 * getline line <"doesnt_exist";
2882 * close("doesnt_exist"); <--- here rsm->F is NULL
2883 */
2884 if (rsm->F)
2885 err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002886 free(rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002887 hash_remove(fdhash, L.s);
2888 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002889 if (err)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002890 setvar_i(intvar[ERRNO], errno);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002891 R_d = (double)err;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002892 break;
2893 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002894 } /* switch */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002895 setvar_i(res, R_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002896 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002897 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002898
Denis Vlasenkof782f522007-01-01 23:51:30 +00002899 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002900 res = exec_builtin(op, res);
2901 break;
2902
Denis Vlasenkof782f522007-01-01 23:51:30 +00002903 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002904 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002905 break;
2906
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002907 case XC( OC_UNARY ): {
2908 double Ld, R_d;
2909
2910 Ld = R_d = getvar_i(R.v);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002911 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002912 case 'P':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002913 Ld = ++R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002914 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002915 case 'p':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002916 R_d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002917 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002918 case 'M':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002919 Ld = --R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002920 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002921 case 'm':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002922 R_d--;
2923 r_op_change:
2924 setvar_i(R.v, R_d);
2925 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002926 case '!':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002927 Ld = !istrue(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002928 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002929 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002930 Ld = -R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002931 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002932 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002933 setvar_i(res, Ld);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002934 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002935 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002936
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002937 case XC( OC_FIELD ): {
2938 int i = (int)getvar_i(R.v);
2939 if (i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002940 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002941 } else {
2942 split_f0();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002943 if (i > nfields)
2944 fsrealloc(i);
2945 res = &Fields[i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002946 }
2947 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002948 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002949
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002950 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002951 case XC( OC_CONCAT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002952 case XC( OC_COMMA ): {
2953 const char *sep = "";
2954 if ((opinfo & OPCLSMASK) == OC_COMMA)
2955 sep = getvar_s(intvar[SUBSEP]);
2956 setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002957 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002958 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002959
Denis Vlasenkof782f522007-01-01 23:51:30 +00002960 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002961 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2962 break;
2963
Denis Vlasenkof782f522007-01-01 23:51:30 +00002964 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002965 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2966 break;
2967
Denis Vlasenkof782f522007-01-01 23:51:30 +00002968 case XC( OC_BINARY ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002969 case XC( OC_REPLACE ): {
2970 double R_d = getvar_i(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002971 debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002972 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002973 case '+':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002974 L_d += R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002975 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002976 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002977 L_d -= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002978 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002979 case '*':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002980 L_d *= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002981 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002982 case '/':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002983 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002984 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002985 L_d /= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002986 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002987 case '&':
Rob Landleyd8205b32010-10-24 03:27:22 +02002988 if (ENABLE_FEATURE_AWK_LIBM)
2989 L_d = pow(L_d, R_d);
2990 else
2991 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002992 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002993 case '%':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002994 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002995 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenko1390a012013-07-20 21:23:01 +02002996 L_d -= (long long)(L_d / R_d) * R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002997 break;
2998 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002999 debug_printf_eval("BINARY/REPLACE result:%f\n", L_d);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003000 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003001 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003002 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003003
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003004 case XC( OC_COMPARE ): {
3005 int i = i; /* for compiler */
3006 double Ld;
3007
Glenn L McGrath545106f2002-11-11 06:21:00 +00003008 if (is_numeric(L.v) && is_numeric(R.v)) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003009 Ld = getvar_i(L.v) - getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003010 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01003011 const char *l = getvar_s(L.v);
3012 const char *r = getvar_s(R.v);
3013 Ld = icase ? strcasecmp(l, r) : strcmp(l, r);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003014 }
3015 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00003016 case 0:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003017 i = (Ld > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003018 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003019 case 2:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003020 i = (Ld >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003021 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003022 case 4:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003023 i = (Ld == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003024 break;
3025 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003026 setvar_i(res, (i == 0) ^ (opn & 1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003027 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003028 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003029
Denis Vlasenkof782f522007-01-01 23:51:30 +00003030 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003031 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003032 }
3033 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
3034 op = op->a.n;
3035 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
3036 break;
3037 if (nextrec)
3038 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003039 } /* while (op) */
3040
Glenn L McGrath545106f2002-11-11 06:21:00 +00003041 nvfree(v1);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003042 debug_printf_eval("returning from %s(): %p\n", __func__, res);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003043 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003044#undef fnargs
3045#undef seed
3046#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00003047}
3048
3049
3050/* -------- main & co. -------- */
3051
Mike Frysinger10a11e22005-09-27 02:23:02 +00003052static int awk_exit(int r)
3053{
Denis Vlasenkof782f522007-01-01 23:51:30 +00003054 var tv;
3055 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003056 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003057
Denis Vlasenkof782f522007-01-01 23:51:30 +00003058 zero_out_var(&tv);
3059
3060 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003061 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00003062 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003063 evaluate(endseq.first, &tv);
3064 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003065
3066 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003067 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003068 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00003069 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003070 if (hi->data.rs.F && hi->data.rs.is_pipe)
3071 pclose(hi->data.rs.F);
3072 hi = hi->next;
3073 }
3074 }
3075
3076 exit(r);
3077}
3078
3079/* if expr looks like "var=value", perform assignment and return 1,
3080 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00003081static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00003082{
Denys Vlasenkoea664dd2012-06-22 18:41:01 +02003083 char *exprc, *val;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003084
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003085 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003086 return FALSE;
3087 }
3088
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003089 exprc = xstrdup(expr);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003090 val = exprc + (val - expr);
3091 *val++ = '\0';
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003092
Denys Vlasenkoea664dd2012-06-22 18:41:01 +02003093 unescape_string_in_place(val);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003094 setvar_u(newvar(exprc), val);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003095 free(exprc);
3096 return TRUE;
3097}
3098
3099/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00003100static rstream *next_input_file(void)
3101{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003102#define rsm (G.next_input_file__rsm)
3103#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003104
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003105 FILE *F;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00003106 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003107
Denys Vlasenkocdeda162009-11-30 01:14:16 +01003108 if (rsm.F)
3109 fclose(rsm.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003110 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003111 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003112
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003113 for (;;) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003114 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003115 if (files_happen)
3116 return NULL;
3117 fname = "-";
3118 F = stdin;
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003119 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003120 }
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003121 ind = getvar_s(incvar(intvar[ARGIND]));
3122 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
3123 if (fname && *fname && !is_assignment(fname)) {
3124 F = xfopen_stdin(fname);
3125 break;
3126 }
3127 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003128
3129 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003130 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003131 rsm.F = F;
3132 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003133#undef rsm
3134#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00003135}
3136
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00003137int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00003138int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00003139{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00003140 unsigned opt;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02003141 char *opt_F;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003142 llist_t *list_v = NULL;
3143 llist_t *list_f = NULL;
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003144#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
3145 llist_t *list_e = NULL;
3146#endif
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003147 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003148 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003149 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003150 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003151 char *vnames = (char *)vNames; /* cheat */
3152 char *vvalues = (char *)vValues;
3153
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003154 INIT_G();
3155
Denis Vlasenko150f4022007-01-13 21:06:21 +00003156 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00003157 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
3158 if (ENABLE_LOCALE_SUPPORT)
3159 setlocale(LC_NUMERIC, "C");
3160
Denis Vlasenkof782f522007-01-01 23:51:30 +00003161 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003162
3163 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003164 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003165
3166 vhash = hash_init();
3167 ahash = hash_init();
3168 fdhash = hash_init();
3169 fnhash = hash_init();
3170
3171 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003172 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003173 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00003174 if (*vvalues != '\377')
3175 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003176 else
3177 setvar_i(v, 0);
3178
Denis Vlasenkof782f522007-01-01 23:51:30 +00003179 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003180 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003181 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003182 }
3183 }
3184
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003185 handle_special(intvar[FS]);
3186 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003187
Denis Vlasenkof782f522007-01-01 23:51:30 +00003188 newfile("/dev/stdin")->F = stdin;
3189 newfile("/dev/stdout")->F = stdout;
3190 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003191
Denis Vlasenkof71d9162007-05-03 22:57:56 +00003192 /* Huh, people report that sometimes environ is NULL. Oh well. */
3193 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003194 /* environ is writable, thus we don't strdup it needlessly */
3195 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003196 char *s1 = strchr(s, '=');
3197 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003198 *s1 = '\0';
3199 /* Both findvar and setvar_u take const char*
3200 * as 2nd arg -> environment is not trashed */
3201 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
3202 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00003203 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003204 }
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003205 opt_complementary = OPTCOMPLSTR_AWK;
3206 opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003207 argv += optind;
3208 argc -= optind;
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003209 if (opt & OPT_W)
3210 bb_error_msg("warning: option -W is ignored");
3211 if (opt & OPT_F) {
Denys Vlasenkoea664dd2012-06-22 18:41:01 +02003212 unescape_string_in_place(opt_F);
3213 setvar_s(intvar[FS], opt_F);
3214 }
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003215 while (list_v) {
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003216 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00003217 bb_show_usage();
3218 }
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003219 while (list_f) {
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003220 char *s = NULL;
3221 FILE *from_file;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003222
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003223 g_progname = llist_pop(&list_f);
3224 from_file = xfopen_stdin(g_progname);
3225 /* one byte is reserved for some trick in next_token */
3226 for (i = j = 1; j > 0; i += j) {
3227 s = xrealloc(s, i + 4096);
3228 j = fread(s + i, 1, 4094, from_file);
3229 }
3230 s[i] = '\0';
3231 fclose(from_file);
3232 parse_program(s + 1);
3233 free(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003234 }
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003235 g_progname = "cmd. line";
3236#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003237 while (list_e) {
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003238 parse_program(llist_pop(&list_e));
3239 }
3240#endif
3241 if (!(opt & (OPT_f | OPT_e))) {
3242 if (!*argv)
3243 bb_show_usage();
3244 parse_program(*argv++);
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003245 argc--;
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003246 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003247
Glenn L McGrath545106f2002-11-11 06:21:00 +00003248 /* fill in ARGV array */
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003249 setvar_i(intvar[ARGC], argc + 1);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003250 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00003251 i = 0;
3252 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003253 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003254
3255 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003256 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00003257 awk_exit(EXIT_SUCCESS);
3258
3259 /* input file could already be opened in BEGIN block */
Denys Vlasenkocdeda162009-11-30 01:14:16 +01003260 if (!iF)
3261 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003262
3263 /* passing through input files */
3264 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003265 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003266 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003267
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003268 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003269 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003270 incvar(intvar[NR]);
3271 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003272 evaluate(mainseq.first, &tv);
3273
3274 if (nextfile)
3275 break;
3276 }
3277
Denis Vlasenkof782f522007-01-01 23:51:30 +00003278 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003279 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003280
3281 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003282 }
3283
Glenn L McGrath545106f2002-11-11 06:21:00 +00003284 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003285 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00003286}