blob: d0e3781e751cb1b4a909499ce4965cf614c5e2cd [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;
1543 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001544
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001545 case OC_CONTINUE:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001546 debug_printf_parse("%s: OC_CONTINUE\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001547 n = chain_node(OC_EXEC);
1548 n->a.n = continue_ptr;
1549 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001550
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001551 /* delete, next, nextfile, return, exit */
1552 default:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001553 debug_printf_parse("%s: default\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001554 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001555 }
1556 }
1557}
1558
Mike Frysinger10a11e22005-09-27 02:23:02 +00001559static void parse_program(char *p)
1560{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001561 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001562 node *cn;
1563 func *f;
1564 var *v;
1565
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001566 g_pos = p;
1567 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001568 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001569 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001570
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001571 if (tclass & TC_OPTERM) {
1572 debug_printf_parse("%s: TC_OPTERM\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001573 continue;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001574 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001575
1576 seq = &mainseq;
1577 if (tclass & TC_BEGIN) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001578 debug_printf_parse("%s: TC_BEGIN\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001579 seq = &beginseq;
1580 chain_group();
1581
1582 } else if (tclass & TC_END) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001583 debug_printf_parse("%s: TC_END\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001584 seq = &endseq;
1585 chain_group();
1586
1587 } else if (tclass & TC_FUNCDECL) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001588 debug_printf_parse("%s: TC_FUNCDECL\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001589 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001590 g_pos++;
1591 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001592 f->body.first = NULL;
1593 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001594 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001595 v = findvar(ahash, t_string);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001596 v->x.aidx = f->nargs++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001597
1598 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1599 break;
1600 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001601 seq = &f->body;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001602 chain_group();
1603 clear_array(ahash);
1604
1605 } else if (tclass & TC_OPSEQ) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001606 debug_printf_parse("%s: TC_OPSEQ\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001607 rollback_token();
1608 cn = chain_node(OC_TEST);
1609 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001610 if (t_tclass & TC_GRPSTART) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001611 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001612 rollback_token();
1613 chain_group();
1614 } else {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001615 debug_printf_parse("%s: !TC_GRPSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001616 chain_node(OC_PRINT);
1617 }
1618 cn->r.n = mainseq.last;
1619
1620 } else /* if (tclass & TC_GRPSTART) */ {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001621 debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001622 rollback_token();
1623 chain_group();
1624 }
1625 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001626 debug_printf_parse("%s: TC_EOF\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001627}
1628
1629
1630/* -------- program execution part -------- */
1631
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001632static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001633{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001634 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001635 node *n;
1636
1637 re = &spl->re[0];
1638 ire = &spl->re[1];
1639 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001640 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001641 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001642 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001643 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001644 if (s[0] && s[1]) { /* strlen(s) > 1 */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001645 mk_re_node(s, n, re);
1646 } else {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001647 n->info = (uint32_t) s[0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001648 }
1649
1650 return n;
1651}
1652
1653/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001654 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001655 * be later regfree'd manually
1656 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001657static regex_t *as_regex(node *op, regex_t *preg)
1658{
Denis Vlasenko7a676642009-03-15 22:20:31 +00001659 int cflags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001660 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001661 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001662
1663 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1664 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001665 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001666 v = nvalloc(1);
1667 s = getvar_s(evaluate(op, v));
Denis Vlasenko7a676642009-03-15 22:20:31 +00001668
1669 cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED;
1670 /* Testcase where REG_EXTENDED fails (unpaired '{'):
1671 * echo Hi | awk 'gsub("@(samp|code|file)\{","");'
1672 * gawk 3.1.5 eats this. We revert to ~REG_EXTENDED
1673 * (maybe gsub is not supposed to use REG_EXTENDED?).
1674 */
1675 if (regcomp(preg, s, cflags)) {
1676 cflags &= ~REG_EXTENDED;
1677 xregcomp(preg, s, cflags);
1678 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001679 nvfree(v);
1680 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001681}
1682
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001683/* gradually increasing buffer.
1684 * note that we reallocate even if n == old_size,
1685 * and thus there is at least one extra allocated byte.
1686 */
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001687static char* qrealloc(char *b, int n, int *size)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001688{
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001689 if (!b || n >= *size) {
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001690 *size = n + (n>>1) + 80;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001691 b = xrealloc(b, *size);
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001692 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001693 return b;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001694}
1695
1696/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001697static void fsrealloc(int size)
1698{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001699 int i;
1700
1701 if (size >= maxfields) {
1702 i = maxfields;
1703 maxfields = size + 16;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001704 Fields = xrealloc(Fields, maxfields * sizeof(Fields[0]));
Denis Vlasenkof782f522007-01-01 23:51:30 +00001705 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001706 Fields[i].type = VF_SPECIAL;
1707 Fields[i].string = NULL;
1708 }
1709 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001710 /* if size < nfields, clear extra field variables */
1711 for (i = size; i < nfields; i++) {
1712 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001713 }
1714 nfields = size;
1715}
1716
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001717static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001718{
Denys Vlasenko28458c62010-10-05 16:49:03 +02001719 int l, n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001720 char c[4];
1721 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001722 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001723
1724 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001725 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1726 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001727
1728 c[0] = c[1] = (char)spl->info;
1729 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001730 if (*getvar_s(intvar[RS]) == '\0')
1731 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001732
Denys Vlasenko28458c62010-10-05 16:49:03 +02001733 n = 0;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001734 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1735 if (!*s)
1736 return n; /* "": zero fields */
1737 n++; /* at least one field will be there */
1738 do {
1739 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001740 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1741 && pmatch[0].rm_so <= l
1742 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001743 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001744 if (pmatch[0].rm_eo == 0) {
1745 l++;
1746 pmatch[0].rm_eo++;
1747 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001748 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001749 } else {
1750 pmatch[0].rm_eo = l;
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001751 if (s[l])
1752 pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001753 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001754 memcpy(s1, s, l);
Denis Vlasenko67b5eeb2009-04-12 13:54:13 +00001755 /* make sure we remove *all* of the separator chars */
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001756 do {
1757 s1[l] = '\0';
1758 } while (++l < pmatch[0].rm_eo);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001759 nextword(&s1);
1760 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001761 } while (*s);
1762 return n;
1763 }
1764 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001765 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001766 *s1++ = *s++;
1767 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001768 n++;
1769 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001770 return n;
1771 }
1772 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001773 if (icase) {
1774 c[0] = toupper(c[0]);
1775 c[1] = tolower(c[1]);
1776 }
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001777 if (*s1)
1778 n++;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001779 while ((s1 = strpbrk(s1, c)) != NULL) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001780 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001781 n++;
1782 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001783 return n;
1784 }
1785 /* space split */
1786 while (*s) {
1787 s = skip_whitespace(s);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001788 if (!*s)
1789 break;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001790 n++;
1791 while (*s && !isspace(*s))
1792 *s1++ = *s++;
1793 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001794 }
1795 return n;
1796}
1797
Mike Frysinger10a11e22005-09-27 02:23:02 +00001798static void split_f0(void)
1799{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001800/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001801#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001802
Glenn L McGrath545106f2002-11-11 06:21:00 +00001803 int i, n;
1804 char *s;
1805
1806 if (is_f0_split)
1807 return;
1808
1809 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001810 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001811 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001812 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001813 fsrealloc(n);
1814 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001815 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001816 Fields[i].string = nextword(&s);
1817 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1818 }
1819
1820 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001821 clrvar(intvar[NF]);
1822 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1823 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001824#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001825}
1826
1827/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001828static void handle_special(var *v)
1829{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001830 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001831 char *b;
1832 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001833 int sl, l, len, i, bsize;
1834
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001835 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001836 return;
1837
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001838 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001839 n = (int)getvar_i(v);
1840 fsrealloc(n);
1841
1842 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001843 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001844 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001845 b = NULL;
1846 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001847 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001848 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001849 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001850 if (b) {
1851 memcpy(b+len, sep, sl);
1852 len += sl;
1853 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001854 b = qrealloc(b, len+l+sl, &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001855 memcpy(b+len, s, l);
1856 len += l;
1857 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001858 if (b)
1859 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001860 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001861 is_f0_split = TRUE;
1862
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001863 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001864 is_f0_split = FALSE;
1865
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001866 } else if (v == intvar[FS]) {
Denys Vlasenkodf8066a2012-07-11 01:27:15 +02001867 /*
1868 * The POSIX-2008 standard says that changing FS should have no effect on the
1869 * current input line, but only on the next one. The language is:
1870 *
1871 * > Before the first reference to a field in the record is evaluated, the record
1872 * > shall be split into fields, according to the rules in Regular Expressions,
1873 * > using the value of FS that was current at the time the record was read.
1874 *
1875 * So, split up current line before assignment to FS:
1876 */
1877 split_f0();
1878
Glenn L McGrath545106f2002-11-11 06:21:00 +00001879 mk_splitter(getvar_s(v), &fsplitter);
1880
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001881 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001882 mk_splitter(getvar_s(v), &rsplitter);
1883
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001884 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001885 icase = istrue(v);
1886
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001887 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001888 n = getvar_i(intvar[NF]);
1889 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001890 /* right here v is invalid. Just to note... */
1891 }
1892}
1893
1894/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001895static node *nextarg(node **pn)
1896{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001897 node *n;
1898
1899 n = *pn;
1900 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1901 *pn = n->r.n;
1902 n = n->l.n;
1903 } else {
1904 *pn = NULL;
1905 }
1906 return n;
1907}
1908
Mike Frysinger10a11e22005-09-27 02:23:02 +00001909static void hashwalk_init(var *v, xhash *array)
1910{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001911 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001912 unsigned i;
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001913 walker_list *w;
1914 walker_list *prev_walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001915
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001916 if (v->type & VF_WALK) {
1917 prev_walker = v->x.walker;
1918 } else {
1919 v->type |= VF_WALK;
1920 prev_walker = NULL;
1921 }
1922 debug_printf_walker("hashwalk_init: prev_walker:%p\n", prev_walker);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001923
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001924 w = v->x.walker = xzalloc(sizeof(*w) + array->glen + 1); /* why + 1? */
1925 debug_printf_walker(" walker@%p=%p\n", &v->x.walker, w);
1926 w->cur = w->end = w->wbuf;
1927 w->prev = prev_walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001928 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001929 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001930 while (hi) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001931 strcpy(w->end, hi->name);
1932 nextword(&w->end);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001933 hi = hi->next;
1934 }
1935 }
1936}
1937
Mike Frysinger10a11e22005-09-27 02:23:02 +00001938static int hashwalk_next(var *v)
1939{
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001940 walker_list *w = v->x.walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001941
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001942 if (w->cur >= w->end) {
1943 walker_list *prev_walker = w->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001944
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001945 debug_printf_walker("end of iteration, free(walker@%p:%p), prev_walker:%p\n", &v->x.walker, w, prev_walker);
1946 free(w);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001947 v->x.walker = prev_walker;
1948 return FALSE;
1949 }
1950
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001951 setvar_s(v, nextword(&w->cur));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001952 return TRUE;
1953}
1954
1955/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001956static int ptest(node *pattern)
1957{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001958 /* ptest__v is "static": to save stack space? */
1959 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001960}
1961
1962/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001963static int awk_getline(rstream *rsm, var *v)
1964{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001965 char *b;
1966 regmatch_t pmatch[2];
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001967 int size, a, p, pp = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001968 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001969 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001970
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02001971 debug_printf_eval("entered %s()\n", __func__);
1972
Glenn L McGrath545106f2002-11-11 06:21:00 +00001973 /* we're using our own buffer since we need access to accumulating
1974 * characters
1975 */
1976 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001977 m = rsm->buffer;
1978 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001979 p = rsm->pos;
1980 size = rsm->size;
1981 c = (char) rsplitter.n.info;
1982 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001983
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001984 if (!m)
1985 m = qrealloc(m, 256, &size);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001986
Glenn L McGrath545106f2002-11-11 06:21:00 +00001987 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001988 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001989 so = eo = p;
1990 r = 1;
1991 if (p > 0) {
1992 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1993 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001994 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001995 so = pmatch[0].rm_so;
1996 eo = pmatch[0].rm_eo;
1997 if (b[eo] != '\0')
1998 break;
1999 }
2000 } else if (c != '\0') {
2001 s = strchr(b+pp, c);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002002 if (!s)
2003 s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002004 if (s) {
2005 so = eo = s-b;
2006 eo++;
2007 break;
2008 }
2009 } else {
2010 while (b[rp] == '\n')
2011 rp++;
2012 s = strstr(b+rp, "\n\n");
2013 if (s) {
2014 so = eo = s-b;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002015 while (b[eo] == '\n')
2016 eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002017 if (b[eo] != '\0')
2018 break;
2019 }
2020 }
2021 }
2022
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002023 if (a > 0) {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002024 memmove(m, m+a, p+1);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002025 b = m;
2026 a = 0;
2027 }
2028
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01002029 m = qrealloc(m, a+p+128, &size);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002030 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002031 pp = p;
2032 p += safe_read(fd, b+p, size-p-1);
2033 if (p < pp) {
2034 p = 0;
2035 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002036 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002037 }
2038 b[p] = '\0';
2039
2040 } while (p > pp);
2041
2042 if (p == 0) {
2043 r--;
2044 } else {
2045 c = b[so]; b[so] = '\0';
2046 setvar_s(v, b+rp);
2047 v->type |= VF_USER;
2048 b[so] = c;
2049 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002050 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002051 b[eo] = c;
2052 }
2053
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002054 rsm->buffer = m;
2055 rsm->adv = a + eo;
2056 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002057 rsm->size = size;
2058
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002059 debug_printf_eval("returning from %s(): %d\n", __func__, r);
2060
Glenn L McGrath545106f2002-11-11 06:21:00 +00002061 return r;
2062}
2063
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002064static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002065{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002066 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002067 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002068 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002069
Denys Vlasenko1390a012013-07-20 21:23:01 +02002070 if (int_as_int && n == (long long)n) {
2071 r = snprintf(b, size, "%lld", (long long)n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002072 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002073 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002074 if (strchr("diouxX", c)) {
2075 r = snprintf(b, size, format, (int)n);
2076 } else if (strchr("eEfgG", c)) {
2077 r = snprintf(b, size, format, n);
2078 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002079 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002080 }
2081 }
2082 return r;
2083}
2084
Glenn L McGrath545106f2002-11-11 06:21:00 +00002085/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002086static char *awk_printf(node *n)
2087{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002088 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002089 char *fmt, *s, *f;
2090 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002091 int i, j, incr, bsize;
2092 char c, c1;
2093 var *v, *arg;
2094
2095 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00002096 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002097
2098 i = 0;
2099 while (*f) {
2100 s = f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002101 while (*f && (*f != '%' || *++f == '%'))
Glenn L McGrath545106f2002-11-11 06:21:00 +00002102 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00002103 while (*f && !isalpha(*f)) {
2104 if (*f == '*')
2105 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002106 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00002107 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002108
2109 incr = (f - s) + MAXVARFMT;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01002110 b = qrealloc(b, incr + i, &bsize);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002111 c = *f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002112 if (c != '\0')
2113 f++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002114 c1 = *f;
2115 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00002116 arg = evaluate(nextarg(&n), v);
2117
2118 j = i;
2119 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002120 i += sprintf(b+i, s, is_numeric(arg) ?
2121 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002122 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00002123 s1 = getvar_s(arg);
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01002124 b = qrealloc(b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002125 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002126 } else {
2127 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
2128 }
2129 *f = c1;
2130
2131 /* if there was an error while sprintf, return value is negative */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002132 if (i < j)
2133 i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002134 }
2135
Glenn L McGrath545106f2002-11-11 06:21:00 +00002136 free(fmt);
2137 nvfree(v);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002138 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002139 b[i] = '\0';
2140 return b;
2141}
2142
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002143/* Common substitution routine.
2144 * Replace (nm)'th substring of (src) that matches (rn) with (repl),
2145 * store result into (dest), return number of substitutions.
2146 * If nm = 0, replace all matches.
2147 * If src or dst is NULL, use $0.
2148 * If subexp != 0, enable subexpression matching (\1-\9).
Glenn L McGrath545106f2002-11-11 06:21:00 +00002149 */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002150static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int subexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002151{
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002152 char *resbuf;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002153 const char *sp;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002154 int match_no, residx, replen, resbufsize;
2155 int regexec_flags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002156 regmatch_t pmatch[10];
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002157 regex_t sreg, *regex;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002158
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002159 resbuf = NULL;
2160 residx = 0;
2161 match_no = 0;
2162 regexec_flags = 0;
2163 regex = as_regex(rn, &sreg);
2164 sp = getvar_s(src ? src : intvar[F0]);
2165 replen = strlen(repl);
2166 while (regexec(regex, sp, 10, pmatch, regexec_flags) == 0) {
2167 int so = pmatch[0].rm_so;
2168 int eo = pmatch[0].rm_eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002169
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002170 //bb_error_msg("match %u: [%u,%u] '%s'%p", match_no+1, so, eo, sp,sp);
2171 resbuf = qrealloc(resbuf, residx + eo + replen, &resbufsize);
2172 memcpy(resbuf + residx, sp, eo);
2173 residx += eo;
2174 if (++match_no >= nm) {
2175 const char *s;
2176 int nbs;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002177
Glenn L McGrath545106f2002-11-11 06:21:00 +00002178 /* replace */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002179 residx -= (eo - so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002180 nbs = 0;
2181 for (s = repl; *s; s++) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002182 char c = resbuf[residx++] = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002183 if (c == '\\') {
2184 nbs++;
2185 continue;
2186 }
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002187 if (c == '&' || (subexp && c >= '0' && c <= '9')) {
2188 int j;
2189 residx -= ((nbs + 3) >> 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002190 j = 0;
2191 if (c != '&') {
2192 j = c - '0';
2193 nbs++;
2194 }
2195 if (nbs % 2) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002196 resbuf[residx++] = c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002197 } else {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002198 int n = pmatch[j].rm_eo - pmatch[j].rm_so;
2199 resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize);
2200 memcpy(resbuf + residx, sp + pmatch[j].rm_so, n);
2201 residx += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002202 }
2203 }
2204 nbs = 0;
2205 }
2206 }
2207
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002208 regexec_flags = REG_NOTBOL;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002209 sp += eo;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002210 if (match_no == nm)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002211 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002212 if (eo == so) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002213 /* Empty match (e.g. "b*" will match anywhere).
2214 * Advance by one char. */
2215//BUG (bug 1333):
2216//gsub(/\<b*/,"") on "abc" will reach this point, advance to "bc"
2217//... and will erroneously match "b" even though it is NOT at the word start.
2218//we need REG_NOTBOW but it does not exist...
Denys Vlasenko7379cd12010-04-04 01:48:12 +02002219//TODO: if EXTRA_COMPAT=y, use GNU matching and re_search,
2220//it should be able to do it correctly.
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002221 /* Subtle: this is safe only because
2222 * qrealloc allocated at least one extra byte */
2223 resbuf[residx] = *sp;
2224 if (*sp == '\0')
2225 goto ret;
2226 sp++;
2227 residx++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002228 }
2229 }
2230
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002231 resbuf = qrealloc(resbuf, residx + strlen(sp), &resbufsize);
2232 strcpy(resbuf + residx, sp);
2233 ret:
2234 //bb_error_msg("end sp:'%s'%p", sp,sp);
2235 setvar_p(dest ? dest : intvar[F0], resbuf);
2236 if (regex == &sreg)
2237 regfree(regex);
2238 return match_no;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002239}
2240
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002241static NOINLINE int do_mktime(const char *ds)
2242{
2243 struct tm then;
2244 int count;
2245
2246 /*memset(&then, 0, sizeof(then)); - not needed */
2247 then.tm_isdst = -1; /* default is unknown */
2248
2249 /* manpage of mktime says these fields are ints,
2250 * so we can sscanf stuff directly into them */
2251 count = sscanf(ds, "%u %u %u %u %u %u %d",
2252 &then.tm_year, &then.tm_mon, &then.tm_mday,
2253 &then.tm_hour, &then.tm_min, &then.tm_sec,
2254 &then.tm_isdst);
2255
2256 if (count < 6
2257 || (unsigned)then.tm_mon < 1
2258 || (unsigned)then.tm_year < 1900
2259 ) {
2260 return -1;
2261 }
2262
2263 then.tm_mon -= 1;
Denys Vlasenkobc3e9472009-09-21 04:16:00 +02002264 then.tm_year -= 1900;
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002265
2266 return mktime(&then);
2267}
2268
2269static NOINLINE var *exec_builtin(node *op, var *res)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002270{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002271#define tspl (G.exec_builtin__tspl)
2272
Glenn L McGrath545106f2002-11-11 06:21:00 +00002273 var *tv;
2274 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002275 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002276 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002277 regmatch_t pmatch[2];
2278 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002279 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002280 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002281 int nargs;
2282 time_t tt;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002283 int i, l, ll, n;
2284
2285 tv = nvalloc(4);
2286 isr = info = op->info;
2287 op = op->l.n;
2288
2289 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002290 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002291 an[i] = nextarg(&op);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002292 if (isr & 0x09000000)
2293 av[i] = evaluate(an[i], &tv[i]);
2294 if (isr & 0x08000000)
2295 as[i] = getvar_s(av[i]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002296 isr >>= 1;
2297 }
2298
2299 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002300 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002301 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002302
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002303 info &= OPNMASK;
2304 switch (info) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002305
Denis Vlasenkof782f522007-01-01 23:51:30 +00002306 case B_a2:
Rob Landleyd8205b32010-10-24 03:27:22 +02002307 if (ENABLE_FEATURE_AWK_LIBM)
2308 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
2309 else
2310 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002311 break;
2312
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002313 case B_sp: {
2314 char *s, *s1;
2315
Glenn L McGrath545106f2002-11-11 06:21:00 +00002316 if (nargs > 2) {
2317 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2318 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2319 } else {
2320 spl = &fsplitter.n;
2321 }
2322
2323 n = awk_split(as[0], spl, &s);
2324 s1 = s;
2325 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002326 for (i = 1; i <= n; i++)
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002327 setari_u(av[1], i, nextword(&s));
2328 free(s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002329 setvar_i(res, n);
2330 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002331 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002332
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002333 case B_ss: {
2334 char *s;
2335
Rob Landleya3896512006-05-07 20:20:34 +00002336 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002337 i = getvar_i(av[1]) - 1;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002338 if (i > l)
2339 i = l;
2340 if (i < 0)
2341 i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002342 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002343 if (n < 0)
2344 n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002345 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002346 setvar_p(res, s);
2347 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002348 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002349
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002350 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2351 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002352 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002353 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002354 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002355
Denis Vlasenkof782f522007-01-01 23:51:30 +00002356 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002357 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002358 break;
2359
Denis Vlasenkof782f522007-01-01 23:51:30 +00002360 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002361 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002362 break;
2363
Denis Vlasenkof782f522007-01-01 23:51:30 +00002364 case B_or:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002365 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002366 break;
2367
Denis Vlasenkof782f522007-01-01 23:51:30 +00002368 case B_rs:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002369 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002370 break;
2371
Denis Vlasenkof782f522007-01-01 23:51:30 +00002372 case B_xo:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002373 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002374 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002375
Denis Vlasenkof782f522007-01-01 23:51:30 +00002376 case B_lo:
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002377 case B_up: {
2378 char *s, *s1;
Rob Landleyd921b2e2006-08-03 15:41:12 +00002379 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002380 while (*s1) {
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002381 //*s1 = (info == B_up) ? toupper(*s1) : tolower(*s1);
2382 if ((unsigned char)((*s1 | 0x20) - 'a') <= ('z' - 'a'))
2383 *s1 = (info == B_up) ? (*s1 & 0xdf) : (*s1 | 0x20);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002384 s1++;
2385 }
2386 setvar_p(res, s);
2387 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002388 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002389
Denis Vlasenkof782f522007-01-01 23:51:30 +00002390 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002391 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002392 ll = strlen(as[1]);
2393 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002394 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002395 if (!icase) {
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002396 char *s = strstr(as[0], as[1]);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002397 if (s)
2398 n = (s - as[0]) + 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002399 } else {
2400 /* this piece of code is terribly slow and
2401 * really should be rewritten
2402 */
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002403 for (i = 0; i <= l; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002404 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2405 n = i+1;
2406 break;
2407 }
2408 }
2409 }
2410 }
2411 setvar_i(res, n);
2412 break;
2413
Denis Vlasenkof782f522007-01-01 23:51:30 +00002414 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002415 if (nargs > 1)
2416 tt = getvar_i(av[1]);
2417 else
2418 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002419 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002420 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002421 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2422 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002423 g_buf[i] = '\0';
2424 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002425 break;
2426
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002427 case B_mt:
2428 setvar_i(res, do_mktime(as[0]));
2429 break;
2430
Denis Vlasenkof782f522007-01-01 23:51:30 +00002431 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002432 re = as_regex(an[1], &sreg);
2433 n = regexec(re, as[0], 1, pmatch, 0);
2434 if (n == 0) {
2435 pmatch[0].rm_so++;
2436 pmatch[0].rm_eo++;
2437 } else {
2438 pmatch[0].rm_so = 0;
2439 pmatch[0].rm_eo = -1;
2440 }
2441 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2442 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2443 setvar_i(res, pmatch[0].rm_so);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002444 if (re == &sreg)
2445 regfree(re);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002446 break;
2447
Denis Vlasenkof782f522007-01-01 23:51:30 +00002448 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002449 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2450 break;
2451
Denis Vlasenkof782f522007-01-01 23:51:30 +00002452 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002453 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2454 break;
2455
Denis Vlasenkof782f522007-01-01 23:51:30 +00002456 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002457 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2458 break;
2459 }
2460
2461 nvfree(tv);
2462 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002463#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002464}
2465
2466/*
2467 * Evaluate node - the heart of the program. Supplied with subtree
2468 * and place where to store result. returns ptr to result.
2469 */
2470#define XC(n) ((n) >> 8)
2471
Mike Frysinger10a11e22005-09-27 02:23:02 +00002472static var *evaluate(node *op, var *res)
2473{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002474/* This procedure is recursive so we should count every byte */
2475#define fnargs (G.evaluate__fnargs)
2476/* seed is initialized to 1 */
2477#define seed (G.evaluate__seed)
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002478#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002479
Glenn L McGrath545106f2002-11-11 06:21:00 +00002480 var *v1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002481
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002482 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002483 return setvar_s(res, NULL);
2484
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002485 debug_printf_eval("entered %s()\n", __func__);
2486
Glenn L McGrath545106f2002-11-11 06:21:00 +00002487 v1 = nvalloc(2);
2488
2489 while (op) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002490 struct {
2491 var *v;
2492 const char *s;
2493 } L = L; /* for compiler */
2494 struct {
2495 var *v;
2496 const char *s;
2497 } R = R;
2498 double L_d = L_d;
2499 uint32_t opinfo;
2500 int opn;
2501 node *op1;
2502
Glenn L McGrath545106f2002-11-11 06:21:00 +00002503 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002504 opn = (opinfo & OPNMASK);
2505 g_lineno = op->lineno;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002506 op1 = op->l.n;
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002507 debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002508
Mike Frysingerde2b9382005-09-27 03:18:00 +00002509 /* execute inevitable things */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002510 if (opinfo & OF_RES1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002511 L.v = evaluate(op1, v1);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002512 if (opinfo & OF_RES2)
2513 R.v = evaluate(op->r.n, v1+1);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002514 if (opinfo & OF_STR1) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002515 L.s = getvar_s(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002516 debug_printf_eval("L.s:'%s'\n", L.s);
2517 }
2518 if (opinfo & OF_STR2) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002519 R.s = getvar_s(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002520 debug_printf_eval("R.s:'%s'\n", R.s);
2521 }
2522 if (opinfo & OF_NUM1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002523 L_d = getvar_i(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002524 debug_printf_eval("L_d:%f\n", L_d);
2525 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002526
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002527 debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002528 switch (XC(opinfo & OPCLSMASK)) {
2529
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002530 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002531
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002532 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002533 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002534 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2535 /* it's range pattern */
2536 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2537 op->info |= OF_CHECKED;
2538 if (ptest(op1->r.n))
2539 op->info &= ~OF_CHECKED;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002540 op = op->a.n;
2541 } else {
2542 op = op->r.n;
2543 }
2544 } else {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002545 op = ptest(op1) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002546 }
2547 break;
2548
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002549 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002550 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002551 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002552
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002553 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002554 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002555 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002556 break;
2557
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002558 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002559 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002560 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002561 break;
2562
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002563 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002564 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002565 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2566 break;
2567
Denis Vlasenkof782f522007-01-01 23:51:30 +00002568 case XC( OC_PRINT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002569 case XC( OC_PRINTF ): {
2570 FILE *F = stdout;
2571
Mike Frysingerde2b9382005-09-27 03:18:00 +00002572 if (op->r.n) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002573 rstream *rsm = newfile(R.s);
2574 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002575 if (opn == '|') {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002576 rsm->F = popen(R.s, "w");
2577 if (rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002578 bb_perror_msg_and_die("popen");
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002579 rsm->is_pipe = 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002580 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002581 rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002582 }
2583 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002584 F = rsm->F;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002585 }
2586
2587 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002588 if (!op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002589 fputs(getvar_s(intvar[F0]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002590 } else {
2591 while (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002592 var *v = evaluate(nextarg(&op1), v1);
2593 if (v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002594 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002595 getvar_i(v), TRUE);
2596 fputs(g_buf, F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002597 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002598 fputs(getvar_s(v), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002599 }
2600
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002601 if (op1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002602 fputs(getvar_s(intvar[OFS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002603 }
2604 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002605 fputs(getvar_s(intvar[ORS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002606
2607 } else { /* OC_PRINTF */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002608 char *s = awk_printf(op1);
2609 fputs(s, F);
2610 free(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002611 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002612 fflush(F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002613 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002614 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002615
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002616 case XC( OC_DELETE ): {
2617 uint32_t info = op1->info & OPCLSMASK;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002618 var *v;
2619
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002620 if (info == OC_VAR) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002621 v = op1->l.v;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002622 } else if (info == OC_FNARG) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002623 v = &fnargs[op1->l.aidx];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002624 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002625 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002626 }
2627
Mike Frysingerde2b9382005-09-27 03:18:00 +00002628 if (op1->r.n) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002629 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002630 clrvar(L.v);
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002631 s = getvar_s(evaluate(op1->r.n, v1));
2632 hash_remove(iamarray(v), s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002633 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002634 clear_array(iamarray(v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002635 }
2636 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002637 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002638
Denis Vlasenkof782f522007-01-01 23:51:30 +00002639 case XC( OC_NEWSOURCE ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002640 g_progname = op->l.new_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002641 break;
2642
Denis Vlasenkof782f522007-01-01 23:51:30 +00002643 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002644 copyvar(res, L.v);
2645 break;
2646
Denis Vlasenkof782f522007-01-01 23:51:30 +00002647 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002648 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002649 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002650 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002651 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002652 clrvar(res);
2653 break;
2654
Denis Vlasenkof782f522007-01-01 23:51:30 +00002655 case XC( OC_EXIT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002656 awk_exit(L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002657
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002658 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002659
Denis Vlasenkof782f522007-01-01 23:51:30 +00002660 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002661 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002662 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002663 split_f0();
2664 goto v_cont;
2665
Denis Vlasenkof782f522007-01-01 23:51:30 +00002666 case XC( OC_FNARG ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002667 L.v = &fnargs[op->l.aidx];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002668 v_cont:
2669 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002670 break;
2671
Denis Vlasenkof782f522007-01-01 23:51:30 +00002672 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002673 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2674 break;
2675
Denis Vlasenkof782f522007-01-01 23:51:30 +00002676 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002677 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002678 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002679 goto re_cont;
2680
Denis Vlasenkof782f522007-01-01 23:51:30 +00002681 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002682 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002683 re_cont:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002684 {
2685 regex_t *re = as_regex(op1, &sreg);
2686 int i = regexec(re, L.s, 0, NULL, 0);
2687 if (re == &sreg)
2688 regfree(re);
2689 setvar_i(res, (i == 0) ^ (opn == '!'));
2690 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002691 break;
2692
Denis Vlasenkof782f522007-01-01 23:51:30 +00002693 case XC( OC_MOVE ):
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002694 debug_printf_eval("MOVE\n");
Mike Frysingerde2b9382005-09-27 03:18:00 +00002695 /* if source is a temporary string, jusk relink it to dest */
Denys Vlasenko12847742009-11-30 01:15:04 +01002696//Disabled: if R.v is numeric but happens to have cached R.v->string,
2697//then L.v ends up being a string, which is wrong
2698// if (R.v == v1+1 && R.v->string) {
2699// res = setvar_p(L.v, R.v->string);
2700// R.v->string = NULL;
2701// } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002702 res = copyvar(L.v, R.v);
Denys Vlasenko12847742009-11-30 01:15:04 +01002703// }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002704 break;
2705
Denis Vlasenkof782f522007-01-01 23:51:30 +00002706 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002707 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002708 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002709 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2710 break;
2711
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002712 case XC( OC_FUNC ): {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002713 var *vbeg, *v;
2714 const char *sv_progname;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002715
Bernhard Reutner-Fischerb79a0fe2013-03-06 21:01:05 +01002716 /* The body might be empty, still has to eval the args */
Bernhard Reutner-Fischera060a1a2013-07-31 15:29:20 +02002717 if (!op->r.n->info && !op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002718 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002719
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002720 vbeg = v = nvalloc(op->r.f->nargs + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002721 while (op1) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002722 var *arg = evaluate(nextarg(&op1), v1);
2723 copyvar(v, arg);
2724 v->type |= VF_CHILD;
2725 v->x.parent = arg;
2726 if (++v - vbeg >= op->r.f->nargs)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002727 break;
2728 }
2729
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002730 v = fnargs;
2731 fnargs = vbeg;
2732 sv_progname = g_progname;
2733
2734 res = evaluate(op->r.f->body.first, res);
2735
2736 g_progname = sv_progname;
2737 nvfree(fnargs);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002738 fnargs = v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002739
Glenn L McGrath545106f2002-11-11 06:21:00 +00002740 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002741 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002742
Denis Vlasenkof782f522007-01-01 23:51:30 +00002743 case XC( OC_GETLINE ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002744 case XC( OC_PGETLINE ): {
2745 rstream *rsm;
2746 int i;
2747
Mike Frysingerde2b9382005-09-27 03:18:00 +00002748 if (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002749 rsm = newfile(L.s);
2750 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002751 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002752 rsm->F = popen(L.s, "r");
2753 rsm->is_pipe = TRUE;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002754 } else {
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002755 rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002756 }
2757 }
2758 } else {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002759 if (!iF)
2760 iF = next_input_file();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002761 rsm = iF;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002762 }
2763
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02002764 if (!rsm || !rsm->F) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002765 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002766 setvar_i(res, -1);
2767 break;
2768 }
2769
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002770 if (!op->r.n)
2771 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002772
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002773 i = awk_getline(rsm, R.v);
2774 if (i > 0 && !op1) {
2775 incvar(intvar[FNR]);
2776 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002777 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002778 setvar_i(res, i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002779 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002780 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002781
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002782 /* simple builtins */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002783 case XC( OC_FBLTIN ): {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002784 double R_d = R_d; /* for compiler */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002785
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002786 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002787 case F_in:
Denys Vlasenko1390a012013-07-20 21:23:01 +02002788 R_d = (long long)L_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002789 break;
2790
Denis Vlasenkof782f522007-01-01 23:51:30 +00002791 case F_rn:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002792 R_d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002793 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002794
Denis Vlasenkof782f522007-01-01 23:51:30 +00002795 case F_co:
Rob Landleyd8205b32010-10-24 03:27:22 +02002796 if (ENABLE_FEATURE_AWK_LIBM) {
2797 R_d = cos(L_d);
2798 break;
2799 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002800
Denis Vlasenkof782f522007-01-01 23:51:30 +00002801 case F_ex:
Rob Landleyd8205b32010-10-24 03:27:22 +02002802 if (ENABLE_FEATURE_AWK_LIBM) {
2803 R_d = exp(L_d);
2804 break;
2805 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002806
Denis Vlasenkof782f522007-01-01 23:51:30 +00002807 case F_lg:
Rob Landleyd8205b32010-10-24 03:27:22 +02002808 if (ENABLE_FEATURE_AWK_LIBM) {
2809 R_d = log(L_d);
2810 break;
2811 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002812
Denis Vlasenkof782f522007-01-01 23:51:30 +00002813 case F_si:
Rob Landleyd8205b32010-10-24 03:27:22 +02002814 if (ENABLE_FEATURE_AWK_LIBM) {
2815 R_d = sin(L_d);
2816 break;
2817 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002818
Denis Vlasenkof782f522007-01-01 23:51:30 +00002819 case F_sq:
Rob Landleyd8205b32010-10-24 03:27:22 +02002820 if (ENABLE_FEATURE_AWK_LIBM) {
2821 R_d = sqrt(L_d);
2822 break;
2823 }
2824
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002825 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002826 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002827
Denis Vlasenkof782f522007-01-01 23:51:30 +00002828 case F_sr:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002829 R_d = (double)seed;
2830 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002831 srand(seed);
2832 break;
2833
Denis Vlasenkof782f522007-01-01 23:51:30 +00002834 case F_ti:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002835 R_d = time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002836 break;
2837
Denis Vlasenkof782f522007-01-01 23:51:30 +00002838 case F_le:
Denys Vlasenko7985bc12013-10-12 04:51:54 +02002839 debug_printf_eval("length: L.s:'%s'\n", L.s);
2840 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002841 L.s = getvar_s(intvar[F0]);
Denys Vlasenko7985bc12013-10-12 04:51:54 +02002842 debug_printf_eval("length: L.s='%s'\n", L.s);
2843 }
2844 else if (L.v->type & VF_ARRAY) {
2845 R_d = L.v->x.array->nel;
2846 debug_printf_eval("length: array_len:%d\n", L.v->x.array->nel);
2847 break;
2848 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002849 R_d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002850 break;
2851
Denis Vlasenkof782f522007-01-01 23:51:30 +00002852 case F_sy:
Denys Vlasenko8131eea2009-11-02 14:19:51 +01002853 fflush_all();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002854 R_d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002855 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002856 break;
2857
Denis Vlasenkof782f522007-01-01 23:51:30 +00002858 case F_ff:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002859 if (!op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002860 fflush(stdout);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002861 } else if (L.s && *L.s) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002862 rstream *rsm = newfile(L.s);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002863 fflush(rsm->F);
2864 } else {
2865 fflush_all();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002866 }
2867 break;
2868
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002869 case F_cl: {
2870 rstream *rsm;
2871 int err = 0;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002872 rsm = (rstream *)hash_search(fdhash, L.s);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002873 debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002874 if (rsm) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002875 debug_printf_eval("OC_FBLTIN F_cl "
2876 "rsm->is_pipe:%d, ->F:%p\n",
2877 rsm->is_pipe, rsm->F);
2878 /* Can be NULL if open failed. Example:
2879 * getline line <"doesnt_exist";
2880 * close("doesnt_exist"); <--- here rsm->F is NULL
2881 */
2882 if (rsm->F)
2883 err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002884 free(rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002885 hash_remove(fdhash, L.s);
2886 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002887 if (err)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002888 setvar_i(intvar[ERRNO], errno);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002889 R_d = (double)err;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002890 break;
2891 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002892 } /* switch */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002893 setvar_i(res, R_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002894 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002895 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002896
Denis Vlasenkof782f522007-01-01 23:51:30 +00002897 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002898 res = exec_builtin(op, res);
2899 break;
2900
Denis Vlasenkof782f522007-01-01 23:51:30 +00002901 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002902 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002903 break;
2904
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002905 case XC( OC_UNARY ): {
2906 double Ld, R_d;
2907
2908 Ld = R_d = getvar_i(R.v);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002909 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002910 case 'P':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002911 Ld = ++R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002912 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002913 case 'p':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002914 R_d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002915 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002916 case 'M':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002917 Ld = --R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002918 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002919 case 'm':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002920 R_d--;
2921 r_op_change:
2922 setvar_i(R.v, R_d);
2923 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002924 case '!':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002925 Ld = !istrue(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002926 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002927 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002928 Ld = -R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002929 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002930 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002931 setvar_i(res, Ld);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002932 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002933 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002934
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002935 case XC( OC_FIELD ): {
2936 int i = (int)getvar_i(R.v);
2937 if (i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002938 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002939 } else {
2940 split_f0();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002941 if (i > nfields)
2942 fsrealloc(i);
2943 res = &Fields[i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002944 }
2945 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002946 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002947
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002948 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002949 case XC( OC_CONCAT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002950 case XC( OC_COMMA ): {
2951 const char *sep = "";
2952 if ((opinfo & OPCLSMASK) == OC_COMMA)
2953 sep = getvar_s(intvar[SUBSEP]);
2954 setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002955 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002956 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002957
Denis Vlasenkof782f522007-01-01 23:51:30 +00002958 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002959 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2960 break;
2961
Denis Vlasenkof782f522007-01-01 23:51:30 +00002962 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002963 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2964 break;
2965
Denis Vlasenkof782f522007-01-01 23:51:30 +00002966 case XC( OC_BINARY ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002967 case XC( OC_REPLACE ): {
2968 double R_d = getvar_i(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002969 debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002970 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002971 case '+':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002972 L_d += R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002973 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002974 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002975 L_d -= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002976 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002977 case '*':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002978 L_d *= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002979 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002980 case '/':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002981 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002982 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002983 L_d /= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002984 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002985 case '&':
Rob Landleyd8205b32010-10-24 03:27:22 +02002986 if (ENABLE_FEATURE_AWK_LIBM)
2987 L_d = pow(L_d, R_d);
2988 else
2989 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002990 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002991 case '%':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002992 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002993 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenko1390a012013-07-20 21:23:01 +02002994 L_d -= (long long)(L_d / R_d) * R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002995 break;
2996 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002997 debug_printf_eval("BINARY/REPLACE result:%f\n", L_d);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002998 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002999 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003000 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003001
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003002 case XC( OC_COMPARE ): {
3003 int i = i; /* for compiler */
3004 double Ld;
3005
Glenn L McGrath545106f2002-11-11 06:21:00 +00003006 if (is_numeric(L.v) && is_numeric(R.v)) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003007 Ld = getvar_i(L.v) - getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003008 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01003009 const char *l = getvar_s(L.v);
3010 const char *r = getvar_s(R.v);
3011 Ld = icase ? strcasecmp(l, r) : strcmp(l, r);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003012 }
3013 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00003014 case 0:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003015 i = (Ld > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003016 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003017 case 2:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003018 i = (Ld >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003019 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003020 case 4:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003021 i = (Ld == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003022 break;
3023 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003024 setvar_i(res, (i == 0) ^ (opn & 1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003025 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003026 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003027
Denis Vlasenkof782f522007-01-01 23:51:30 +00003028 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003029 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003030 }
3031 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
3032 op = op->a.n;
3033 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
3034 break;
3035 if (nextrec)
3036 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01003037 } /* while (op) */
3038
Glenn L McGrath545106f2002-11-11 06:21:00 +00003039 nvfree(v1);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003040 debug_printf_eval("returning from %s(): %p\n", __func__, res);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003041 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003042#undef fnargs
3043#undef seed
3044#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00003045}
3046
3047
3048/* -------- main & co. -------- */
3049
Mike Frysinger10a11e22005-09-27 02:23:02 +00003050static int awk_exit(int r)
3051{
Denis Vlasenkof782f522007-01-01 23:51:30 +00003052 var tv;
3053 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003054 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003055
Denis Vlasenkof782f522007-01-01 23:51:30 +00003056 zero_out_var(&tv);
3057
3058 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003059 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00003060 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003061 evaluate(endseq.first, &tv);
3062 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003063
3064 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003065 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003066 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00003067 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003068 if (hi->data.rs.F && hi->data.rs.is_pipe)
3069 pclose(hi->data.rs.F);
3070 hi = hi->next;
3071 }
3072 }
3073
3074 exit(r);
3075}
3076
3077/* if expr looks like "var=value", perform assignment and return 1,
3078 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00003079static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00003080{
Denys Vlasenkoea664dd2012-06-22 18:41:01 +02003081 char *exprc, *val;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003082
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003083 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003084 return FALSE;
3085 }
3086
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003087 exprc = xstrdup(expr);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003088 val = exprc + (val - expr);
3089 *val++ = '\0';
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003090
Denys Vlasenkoea664dd2012-06-22 18:41:01 +02003091 unescape_string_in_place(val);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003092 setvar_u(newvar(exprc), val);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003093 free(exprc);
3094 return TRUE;
3095}
3096
3097/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00003098static rstream *next_input_file(void)
3099{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003100#define rsm (G.next_input_file__rsm)
3101#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003102
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003103 FILE *F;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00003104 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003105
Denys Vlasenkocdeda162009-11-30 01:14:16 +01003106 if (rsm.F)
3107 fclose(rsm.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003108 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003109 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003110
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003111 for (;;) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003112 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003113 if (files_happen)
3114 return NULL;
3115 fname = "-";
3116 F = stdin;
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003117 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003118 }
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003119 ind = getvar_s(incvar(intvar[ARGIND]));
3120 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
3121 if (fname && *fname && !is_assignment(fname)) {
3122 F = xfopen_stdin(fname);
3123 break;
3124 }
3125 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003126
3127 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003128 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003129 rsm.F = F;
3130 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003131#undef rsm
3132#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00003133}
3134
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00003135int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00003136int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00003137{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00003138 unsigned opt;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02003139 char *opt_F;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003140 llist_t *list_v = NULL;
3141 llist_t *list_f = NULL;
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003142#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
3143 llist_t *list_e = NULL;
3144#endif
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003145 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003146 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003147 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003148 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003149 char *vnames = (char *)vNames; /* cheat */
3150 char *vvalues = (char *)vValues;
3151
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003152 INIT_G();
3153
Denis Vlasenko150f4022007-01-13 21:06:21 +00003154 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00003155 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
3156 if (ENABLE_LOCALE_SUPPORT)
3157 setlocale(LC_NUMERIC, "C");
3158
Denis Vlasenkof782f522007-01-01 23:51:30 +00003159 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003160
3161 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003162 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003163
3164 vhash = hash_init();
3165 ahash = hash_init();
3166 fdhash = hash_init();
3167 fnhash = hash_init();
3168
3169 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003170 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003171 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00003172 if (*vvalues != '\377')
3173 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003174 else
3175 setvar_i(v, 0);
3176
Denis Vlasenkof782f522007-01-01 23:51:30 +00003177 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003178 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003179 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003180 }
3181 }
3182
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003183 handle_special(intvar[FS]);
3184 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003185
Denis Vlasenkof782f522007-01-01 23:51:30 +00003186 newfile("/dev/stdin")->F = stdin;
3187 newfile("/dev/stdout")->F = stdout;
3188 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003189
Denis Vlasenkof71d9162007-05-03 22:57:56 +00003190 /* Huh, people report that sometimes environ is NULL. Oh well. */
3191 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003192 /* environ is writable, thus we don't strdup it needlessly */
3193 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003194 char *s1 = strchr(s, '=');
3195 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003196 *s1 = '\0';
3197 /* Both findvar and setvar_u take const char*
3198 * as 2nd arg -> environment is not trashed */
3199 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
3200 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00003201 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003202 }
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003203 opt_complementary = OPTCOMPLSTR_AWK;
3204 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 +00003205 argv += optind;
3206 argc -= optind;
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003207 if (opt & OPT_W)
3208 bb_error_msg("warning: option -W is ignored");
3209 if (opt & OPT_F) {
Denys Vlasenkoea664dd2012-06-22 18:41:01 +02003210 unescape_string_in_place(opt_F);
3211 setvar_s(intvar[FS], opt_F);
3212 }
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003213 while (list_v) {
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003214 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00003215 bb_show_usage();
3216 }
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003217 while (list_f) {
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003218 char *s = NULL;
3219 FILE *from_file;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003220
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003221 g_progname = llist_pop(&list_f);
3222 from_file = xfopen_stdin(g_progname);
3223 /* one byte is reserved for some trick in next_token */
3224 for (i = j = 1; j > 0; i += j) {
3225 s = xrealloc(s, i + 4096);
3226 j = fread(s + i, 1, 4094, from_file);
3227 }
3228 s[i] = '\0';
3229 fclose(from_file);
3230 parse_program(s + 1);
3231 free(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003232 }
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003233 g_progname = "cmd. line";
3234#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003235 while (list_e) {
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003236 parse_program(llist_pop(&list_e));
3237 }
3238#endif
3239 if (!(opt & (OPT_f | OPT_e))) {
3240 if (!*argv)
3241 bb_show_usage();
3242 parse_program(*argv++);
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003243 argc--;
Sven-Göran Berghf200f732013-11-12 14:18:25 +01003244 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003245
Glenn L McGrath545106f2002-11-11 06:21:00 +00003246 /* fill in ARGV array */
Denys Vlasenkobd0e2212013-11-21 15:09:55 +01003247 setvar_i(intvar[ARGC], argc + 1);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003248 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00003249 i = 0;
3250 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003251 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003252
3253 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003254 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00003255 awk_exit(EXIT_SUCCESS);
3256
3257 /* input file could already be opened in BEGIN block */
Denys Vlasenkocdeda162009-11-30 01:14:16 +01003258 if (!iF)
3259 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003260
3261 /* passing through input files */
3262 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003263 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003264 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003265
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003266 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003267 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003268 incvar(intvar[NR]);
3269 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003270 evaluate(mainseq.first, &tv);
3271
3272 if (nextfile)
3273 break;
3274 }
3275
Denis Vlasenkof782f522007-01-01 23:51:30 +00003276 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003277 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003278
3279 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003280 }
3281
Glenn L McGrath545106f2002-11-11 06:21:00 +00003282 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003283 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00003284}