blob: 9d306bf5fd113fe668ca85869f8e356bb0ef0cba [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 *
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00007 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Glenn L McGrath545106f2002-11-11 06:21:00 +00008 */
9
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000010#include "libbb.h"
Rob Landleyd921b2e2006-08-03 15:41:12 +000011#include "xregex.h"
12#include <math.h>
Denis Vlasenko5b340832007-05-17 23:02:14 +000013extern char **environ;
Glenn L McGrath545106f2002-11-11 06:21:00 +000014
Denis Vlasenko99912ca2007-04-10 15:43:37 +000015/* This is a NOEXEC applet. Be very careful! */
16
Glenn L McGrath545106f2002-11-11 06:21:00 +000017
Denis Vlasenko629563b2007-02-24 17:05:52 +000018#define MAXVARFMT 240
19#define MINNVBLOCK 64
Glenn L McGrath545106f2002-11-11 06:21:00 +000020
21/* variable flags */
Denis Vlasenko629563b2007-02-24 17:05:52 +000022#define VF_NUMBER 0x0001 /* 1 = primary type is number */
23#define VF_ARRAY 0x0002 /* 1 = it's an array */
Glenn L McGrath545106f2002-11-11 06:21:00 +000024
Denis Vlasenko629563b2007-02-24 17:05:52 +000025#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
26#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
27#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
28#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
29#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
30#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
31#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
Glenn L McGrath545106f2002-11-11 06:21:00 +000032
33/* these flags are static, don't change them when value is changed */
Denis Vlasenko629563b2007-02-24 17:05:52 +000034#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
Glenn L McGrath545106f2002-11-11 06:21:00 +000035
36/* Variable */
37typedef struct var_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000038 unsigned type; /* flags */
Glenn L McGrath545106f2002-11-11 06:21:00 +000039 double number;
40 char *string;
41 union {
Denis Vlasenko629563b2007-02-24 17:05:52 +000042 int aidx; /* func arg idx (for compilation stage) */
43 struct xhash_s *array; /* array ptr */
44 struct var_s *parent; /* for func args, ptr to actual parameter */
45 char **walker; /* list of array elements (for..in) */
Glenn L McGrath545106f2002-11-11 06:21:00 +000046 } x;
47} var;
48
49/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
50typedef struct chain_s {
51 struct node_s *first;
52 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +000053 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +000054} chain;
55
56/* Function */
57typedef struct func_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000058 unsigned nargs;
Glenn L McGrath545106f2002-11-11 06:21:00 +000059 struct chain_s body;
60} func;
61
62/* I/O stream */
63typedef struct rstream_s {
64 FILE *F;
65 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +000066 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +000067 int size;
68 int pos;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000069 smallint is_pipe;
Glenn L McGrath545106f2002-11-11 06:21:00 +000070} rstream;
71
72typedef struct hash_item_s {
73 union {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000074 struct var_s v; /* variable/array hash */
75 struct rstream_s rs; /* redirect streams hash */
76 struct func_s f; /* functions hash */
Glenn L McGrath545106f2002-11-11 06:21:00 +000077 } data;
Denis Vlasenkoffba9412007-05-17 23:03:35 +000078 struct hash_item_s *next; /* next in chain */
79 char name[1]; /* really it's longer */
Glenn L McGrath545106f2002-11-11 06:21:00 +000080} hash_item;
81
82typedef struct xhash_s {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000083 unsigned nel; /* num of elements */
84 unsigned csize; /* current hash size */
85 unsigned nprime; /* next hash size in PRIMES[] */
86 unsigned glen; /* summary length of item names */
Glenn L McGrath545106f2002-11-11 06:21:00 +000087 struct hash_item_s **items;
88} xhash;
89
90/* Tree node */
91typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +000092 uint32_t info;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +000093 unsigned lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +000094 union {
95 struct node_s *n;
96 var *v;
97 int i;
98 char *s;
99 regex_t *re;
100 } l;
101 union {
102 struct node_s *n;
103 regex_t *ire;
104 func *f;
105 int argno;
106 } r;
107 union {
108 struct node_s *n;
109 } a;
110} node;
111
112/* Block of temporary variables */
113typedef struct nvblock_s {
114 int size;
115 var *pos;
116 struct nvblock_s *prev;
117 struct nvblock_s *next;
118 var nv[0];
119} nvblock;
120
121typedef struct tsplitter_s {
122 node n;
123 regex_t re[2];
124} tsplitter;
125
126/* simple token classes */
127/* Order and hex values are very important!!! See next_token() */
128#define TC_SEQSTART 1 /* ( */
129#define TC_SEQTERM (1 << 1) /* ) */
130#define TC_REGEXP (1 << 2) /* /.../ */
131#define TC_OUTRDR (1 << 3) /* | > >> */
132#define TC_UOPPOST (1 << 4) /* unary postfix operator */
133#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
134#define TC_BINOPX (1 << 6) /* two-opnd operator */
135#define TC_IN (1 << 7)
136#define TC_COMMA (1 << 8)
137#define TC_PIPE (1 << 9) /* input redirection pipe */
138#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
139#define TC_ARRTERM (1 << 11) /* ] */
140#define TC_GRPSTART (1 << 12) /* { */
141#define TC_GRPTERM (1 << 13) /* } */
142#define TC_SEMICOL (1 << 14)
143#define TC_NEWLINE (1 << 15)
144#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
145#define TC_WHILE (1 << 17)
146#define TC_ELSE (1 << 18)
147#define TC_BUILTIN (1 << 19)
148#define TC_GETLINE (1 << 20)
149#define TC_FUNCDECL (1 << 21) /* `function' `func' */
150#define TC_BEGIN (1 << 22)
151#define TC_END (1 << 23)
152#define TC_EOF (1 << 24)
153#define TC_VARIABLE (1 << 25)
154#define TC_ARRAY (1 << 26)
155#define TC_FUNCTION (1 << 27)
156#define TC_STRING (1 << 28)
157#define TC_NUMBER (1 << 29)
158
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000159#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000160
161/* combined token classes */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000162#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
163#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
164#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
165 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000166
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000167#define TC_STATEMNT (TC_STATX | TC_WHILE)
168#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000169
170/* word tokens, cannot mean something else if not expected */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000171#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
172 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000173
174/* discard newlines after these */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000175#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
176 | TC_BINOP | TC_OPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000177
178/* what can expression begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000179#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000180/* what can group begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000181#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000182
183/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
184/* operator is inserted between them */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000185#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
186 | TC_STRING | TC_NUMBER | TC_UOPPOST)
187#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000188
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000189#define OF_RES1 0x010000
190#define OF_RES2 0x020000
191#define OF_STR1 0x040000
192#define OF_STR2 0x080000
193#define OF_NUM1 0x100000
194#define OF_CHECKED 0x200000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000195
196/* combined operator flags */
197#define xx 0
198#define xV OF_RES2
199#define xS (OF_RES2 | OF_STR2)
200#define Vx OF_RES1
201#define VV (OF_RES1 | OF_RES2)
202#define Nx (OF_RES1 | OF_NUM1)
203#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
204#define Sx (OF_RES1 | OF_STR1)
205#define SV (OF_RES1 | OF_STR1 | OF_RES2)
206#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
207
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000208#define OPCLSMASK 0xFF00
209#define OPNMASK 0x007F
Glenn L McGrath545106f2002-11-11 06:21:00 +0000210
211/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
212 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
213 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
214 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000215#define P(x) (x << 24)
216#define PRIMASK 0x7F000000
217#define PRIMASK2 0x7E000000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000218
219/* Operation classes */
220
221#define SHIFT_TIL_THIS 0x0600
222#define RECUR_FROM_THIS 0x1000
223
224enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000225 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
226 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000227
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000228 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
229 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
230 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000231
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000232 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
233 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
234 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
235 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
236 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
237 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
238 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
239 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
240 OC_DONE = 0x2800,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000241
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000242 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
243 ST_WHILE = 0x3300
Glenn L McGrath545106f2002-11-11 06:21:00 +0000244};
245
246/* simple builtins */
247enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000248 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000249 F_ti, F_le, F_sy, F_ff, F_cl
250};
251
252/* builtins */
253enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000254 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up,
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000255 B_ge, B_gs, B_su,
256 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000257};
258
259/* tokens and their corresponding info values */
260
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000261#define NTC "\377" /* switch to next token class (tc<<1) */
262#define NTCC '\377'
Glenn L McGrath545106f2002-11-11 06:21:00 +0000263
264#define OC_B OC_BUILTIN
265
Denis Vlasenkof782f522007-01-01 23:51:30 +0000266static const char tokenlist[] =
267 "\1(" NTC
268 "\1)" NTC
269 "\1/" NTC /* REGEXP */
270 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
271 "\2++" "\2--" NTC /* UOPPOST */
272 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
273 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
274 "\2*=" "\2/=" "\2%=" "\2^="
275 "\1+" "\1-" "\3**=" "\2**"
276 "\1/" "\1%" "\1^" "\1*"
277 "\2!=" "\2>=" "\2<=" "\1>"
278 "\1<" "\2!~" "\1~" "\2&&"
279 "\2||" "\1?" "\1:" NTC
280 "\2in" NTC
281 "\1," NTC
282 "\1|" NTC
283 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
284 "\1]" NTC
285 "\1{" NTC
286 "\1}" NTC
287 "\1;" NTC
288 "\1\n" NTC
289 "\2if" "\2do" "\3for" "\5break" /* STATX */
290 "\10continue" "\6delete" "\5print"
291 "\6printf" "\4next" "\10nextfile"
292 "\6return" "\4exit" NTC
293 "\5while" NTC
294 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000295
Denis Vlasenkof782f522007-01-01 23:51:30 +0000296 "\3and" "\5compl" "\6lshift" "\2or"
297 "\6rshift" "\3xor"
298 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
299 "\3cos" "\3exp" "\3int" "\3log"
300 "\4rand" "\3sin" "\4sqrt" "\5srand"
301 "\6gensub" "\4gsub" "\5index" "\6length"
302 "\5match" "\5split" "\7sprintf" "\3sub"
303 "\6substr" "\7systime" "\10strftime"
304 "\7tolower" "\7toupper" NTC
305 "\7getline" NTC
306 "\4func" "\10function" NTC
307 "\5BEGIN" NTC
308 "\3END" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000309 ;
310
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000311static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000312 0,
313 0,
314 OC_REGEXP,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000315 xS|'a', xS|'w', xS|'|',
316 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
317 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M',
318 OC_FIELD|xV|P(5),
319 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74),
320 OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
321 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/',
322 OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
323 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-',
324 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
325 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%',
326 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
327 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
328 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
329 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
330 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
331 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
332 OC_COLON|xx|P(67)|':',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000333 OC_IN|SV|P(49),
334 OC_COMMA|SS|P(80),
335 OC_PGETLINE|SV|P(37),
Denis Vlasenkof782f522007-01-01 23:51:30 +0000336 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',
337 OC_UNARY|xV|P(19)|'!',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000338 0,
339 0,
340 0,
341 0,
342 0,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000343 ST_IF, ST_DO, ST_FOR, OC_BREAK,
344 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
345 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
346 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000347 ST_WHILE,
348 0,
349
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000350 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
351 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000352 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
353 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
354 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
355 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
356 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
357 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b),
358 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
359 OC_GETLINE|SV|P(0),
360 0, 0,
361 0,
362 0
363};
364
365/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000366/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000367enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000368 CONVFMT, OFMT, FS, OFS,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000369 ORS, RS, RT, FILENAME,
370 SUBSEP, ARGIND, ARGC, ARGV,
371 ERRNO, FNR,
372 NR, NF, IGNORECASE,
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000373 ENVIRON, F0, NUM_INTERNAL_VARS
Glenn L McGrath545106f2002-11-11 06:21:00 +0000374};
375
Denis Vlasenkof782f522007-01-01 23:51:30 +0000376static const char vNames[] =
377 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
378 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
379 "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0"
380 "ERRNO\0" "FNR\0"
381 "NR\0" "NF\0*" "IGNORECASE\0*"
382 "ENVIRON\0" "$\0*" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000383
Denis Vlasenkof782f522007-01-01 23:51:30 +0000384static const char vValues[] =
385 "%.6g\0" "%.6g\0" " \0" " \0"
386 "\n\0" "\n\0" "\0" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000387 "\034\0"
388 "\377";
389
390/* hash size may grow to these values */
391#define FIRST_PRIME 61;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000392static const unsigned PRIMES[] = { 251, 1021, 4093, 16381, 65521 };
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000393enum { NPRIMES = sizeof(PRIMES) / sizeof(PRIMES[0]) };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000394
Glenn L McGrath545106f2002-11-11 06:21:00 +0000395
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000396/* Globals. Split in two parts so that first one is addressed
397 * with (mostly short) negative offsets */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000398struct globals {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000399 chain beginseq, mainseq, endseq, *seq;
400 node *break_ptr, *continue_ptr;
401 rstream *iF;
402 xhash *vhash, *ahash, *fdhash, *fnhash;
403 const char *g_progname;
404 int g_lineno;
405 int nfields;
406 int maxfields; /* used in fsrealloc() only */
407 var *Fields;
408 nvblock *g_cb;
409 char *g_pos;
410 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000411 smallint icase;
412 smallint exiting;
413 smallint nextrec;
414 smallint nextfile;
415 smallint is_f0_split;
416};
417struct globals2 {
418 uint32_t t_info; /* often used */
419 uint32_t t_tclass;
420 char *t_string;
421 int t_lineno;
422 int t_rollback;
423
424 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000425
426 /* former statics from various functions */
427 char *split_f0__fstrings;
428
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000429 uint32_t next_token__save_tclass;
430 uint32_t next_token__save_info;
431 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000432 smallint next_token__concat_inserted;
433
434 smallint next_input_file__files_happen;
435 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000436
437 var *evaluate__fnargs;
438 unsigned evaluate__seed;
439 regex_t evaluate__sreg;
440
441 var ptest__v;
442
443 tsplitter exec_builtin__tspl;
444
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000445 /* biggest and least used members go last */
446 double t_double;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000447 tsplitter fsplitter, rsplitter;
448};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000449#define G1 (ptr_to_globals[-1])
450#define G (*(struct globals2 *const)ptr_to_globals)
451/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
452/* char G1size[sizeof(G1)]; - 0x6c */
453/* char Gsize[sizeof(G)]; - 0x1cc */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000454/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000455/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
456#define beginseq (G1.beginseq )
457#define mainseq (G1.mainseq )
458#define endseq (G1.endseq )
459#define seq (G1.seq )
460#define break_ptr (G1.break_ptr )
461#define continue_ptr (G1.continue_ptr)
462#define iF (G1.iF )
463#define vhash (G1.vhash )
464#define ahash (G1.ahash )
465#define fdhash (G1.fdhash )
466#define fnhash (G1.fnhash )
467#define g_progname (G1.g_progname )
468#define g_lineno (G1.g_lineno )
469#define nfields (G1.nfields )
470#define maxfields (G1.maxfields )
471#define Fields (G1.Fields )
472#define g_cb (G1.g_cb )
473#define g_pos (G1.g_pos )
474#define g_buf (G1.g_buf )
475#define icase (G1.icase )
476#define exiting (G1.exiting )
477#define nextrec (G1.nextrec )
478#define nextfile (G1.nextfile )
479#define is_f0_split (G1.is_f0_split )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000480#define t_info (G.t_info )
481#define t_tclass (G.t_tclass )
482#define t_string (G.t_string )
483#define t_double (G.t_double )
484#define t_lineno (G.t_lineno )
485#define t_rollback (G.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000486#define intvar (G.intvar )
487#define fsplitter (G.fsplitter )
488#define rsplitter (G.rsplitter )
489#define INIT_G() do { \
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000490 PTR_TO_GLOBALS = xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000491 G.next_token__ltclass = TC_OPTERM; \
492 G.evaluate__seed = 1; \
493} while (0)
494
Glenn L McGrath545106f2002-11-11 06:21:00 +0000495
496/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000497static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000498static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000499static void chain_group(void);
500static var *evaluate(node *, var *);
501static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000502static int fmt_num(char *, int, const char *, double, int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000503static int awk_exit(int) ATTRIBUTE_NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000504
505/* ---- error handling ---- */
506
507static const char EMSG_INTERNAL_ERROR[] = "Internal error";
508static const char EMSG_UNEXP_EOS[] = "Unexpected end of string";
509static const char EMSG_UNEXP_TOKEN[] = "Unexpected token";
510static const char EMSG_DIV_BY_ZERO[] = "Division by zero";
511static const char EMSG_INV_FMT[] = "Invalid format specifier";
512static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin";
513static const char EMSG_NOT_ARRAY[] = "Not an array";
514static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error";
515static const char EMSG_UNDEF_FUNC[] = "Call to undefined function";
Denis Vlasenkof782f522007-01-01 23:51:30 +0000516#if !ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +0000517static const char EMSG_NO_MATH[] = "Math support is not compiled in";
518#endif
519
Denis Vlasenkof782f522007-01-01 23:51:30 +0000520static void zero_out_var(var * vp)
521{
522 memset(vp, 0, sizeof(*vp));
523}
524
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000525static void syntax_error(const char * const message) ATTRIBUTE_NORETURN;
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000526static void syntax_error(const char * const message)
527{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000528 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000529}
530
Glenn L McGrath545106f2002-11-11 06:21:00 +0000531/* ---- hash stuff ---- */
532
Denis Vlasenkof782f522007-01-01 23:51:30 +0000533static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000534{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000535 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000536
Denis Vlasenkof782f522007-01-01 23:51:30 +0000537 while (*name) idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000538 return idx;
539}
540
541/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000542static xhash *hash_init(void)
543{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000544 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000545
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000546 newhash = xzalloc(sizeof(xhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000547 newhash->csize = FIRST_PRIME;
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000548 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000549
550 return newhash;
551}
552
553/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000554static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000555{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000556 hash_item *hi;
557
558 hi = hash->items [ hashidx(name) % hash->csize ];
559 while (hi) {
560 if (strcmp(hi->name, name) == 0)
561 return &(hi->data);
562 hi = hi->next;
563 }
564 return NULL;
565}
566
567/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000568static void hash_rebuild(xhash *hash)
569{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000570 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000571 hash_item **newitems, *hi, *thi;
572
573 if (hash->nprime == NPRIMES)
574 return;
575
576 newsize = PRIMES[hash->nprime++];
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000577 newitems = xzalloc(newsize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000578
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000579 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000580 hi = hash->items[i];
581 while (hi) {
582 thi = hi;
583 hi = thi->next;
584 idx = hashidx(thi->name) % newsize;
585 thi->next = newitems[idx];
586 newitems[idx] = thi;
587 }
588 }
589
590 free(hash->items);
591 hash->csize = newsize;
592 hash->items = newitems;
593}
594
595/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000596static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000597{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000598 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000599 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000600 int l;
601
602 hi = hash_search(hash, name);
603 if (! hi) {
604 if (++hash->nel / hash->csize > 10)
605 hash_rebuild(hash);
606
Rob Landleya3896512006-05-07 20:20:34 +0000607 l = strlen(name) + 1;
Rob Landley9ffd4232006-05-21 18:30:35 +0000608 hi = xzalloc(sizeof(hash_item) + l);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000609 memcpy(hi->name, name, l);
610
611 idx = hashidx(name) % hash->csize;
612 hi->next = hash->items[idx];
613 hash->items[idx] = hi;
614 hash->glen += l;
615 }
616 return &(hi->data);
617}
618
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000619#define findvar(hash, name) ((var*) hash_find((hash), (name)))
620#define newvar(name) ((var*) hash_find(vhash, (name)))
621#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
622#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000623
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000624static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000625{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000626 hash_item *hi, **phi;
627
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000628 phi = &(hash->items[hashidx(name) % hash->csize]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000629 while (*phi) {
630 hi = *phi;
631 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000632 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000633 hash->nel--;
634 *phi = hi->next;
635 free(hi);
636 break;
637 }
638 phi = &(hi->next);
639 }
640}
641
642/* ------ some useful functions ------ */
643
Mike Frysinger10a11e22005-09-27 02:23:02 +0000644static void skip_spaces(char **s)
645{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000646 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000647
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000648 while (1) {
649 if (*p == '\\' && p[1] == '\n') {
650 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000651 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000652 } else if (*p != ' ' && *p != '\t') {
653 break;
654 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000655 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000656 }
657 *s = p;
658}
659
Mike Frysinger10a11e22005-09-27 02:23:02 +0000660static char *nextword(char **s)
661{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000662 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000663
Denis Vlasenkof782f522007-01-01 23:51:30 +0000664 while (*(*s)++) /* */;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000665
666 return p;
667}
668
Mike Frysinger10a11e22005-09-27 02:23:02 +0000669static char nextchar(char **s)
670{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000671 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000672
673 c = *((*s)++);
674 pps = *s;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000675 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000676 if (c == '\\' && *s == pps) c = *((*s)++);
677 return c;
678}
679
Rob Landley88621d72006-08-29 19:41:06 +0000680static int ATTRIBUTE_ALWAYS_INLINE isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000681{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000682 return (isalnum(c) || c == '_');
683}
684
Mike Frysinger10a11e22005-09-27 02:23:02 +0000685static FILE *afopen(const char *path, const char *mode)
686{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000687 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000688}
689
690/* -------- working with variables (set/get/copy/etc) -------- */
691
Mike Frysinger10a11e22005-09-27 02:23:02 +0000692static xhash *iamarray(var *v)
693{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000694 var *a = v;
695
696 while (a->type & VF_CHILD)
697 a = a->x.parent;
698
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000699 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000700 a->type |= VF_ARRAY;
701 a->x.array = hash_init();
702 }
703 return a->x.array;
704}
705
Mike Frysinger10a11e22005-09-27 02:23:02 +0000706static void clear_array(xhash *array)
707{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000708 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000709 hash_item *hi, *thi;
710
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000711 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000712 hi = array->items[i];
713 while (hi) {
714 thi = hi;
715 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000716 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000717 free(thi);
718 }
719 array->items[i] = NULL;
720 }
721 array->glen = array->nel = 0;
722}
723
724/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000725static var *clrvar(var *v)
726{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000727 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000728 free(v->string);
729
730 v->type &= VF_DONTTOUCH;
731 v->type |= VF_DIRTY;
732 v->string = NULL;
733 return v;
734}
735
736/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000737static var *setvar_p(var *v, char *value)
738{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000739 clrvar(v);
740 v->string = value;
741 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000742 return v;
743}
744
745/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000746static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000747{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000748 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000749}
750
751/* same as setvar_s but set USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000752static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000753{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000754 setvar_s(v, value);
755 v->type |= VF_USER;
756 return v;
757}
758
759/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000760static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000761{
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000762 char sidx[sizeof(int)*3 + 1];
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000763 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000764
765 sprintf(sidx, "%d", idx);
766 v = findvar(iamarray(a), sidx);
767 setvar_u(v, s);
768}
769
770/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000771static var *setvar_i(var *v, double value)
772{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000773 clrvar(v);
774 v->type |= VF_NUMBER;
775 v->number = value;
776 handle_special(v);
777 return v;
778}
779
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000780static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000781{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000782 /* if v is numeric and has no cached string, convert it to string */
783 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000784 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
785 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000786 v->type |= VF_CACHED;
787 }
788 return (v->string == NULL) ? "" : v->string;
789}
790
Mike Frysinger10a11e22005-09-27 02:23:02 +0000791static double getvar_i(var *v)
792{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000793 char *s;
794
795 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
796 v->number = 0;
797 s = v->string;
798 if (s && *s) {
799 v->number = strtod(s, &s);
800 if (v->type & VF_USER) {
801 skip_spaces(&s);
802 if (*s != '\0')
803 v->type &= ~VF_USER;
804 }
805 } else {
806 v->type &= ~VF_USER;
807 }
808 v->type |= VF_CACHED;
809 }
810 return v->number;
811}
812
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000813static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000814{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000815 if (dest != src) {
816 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000817 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000818 dest->number = src->number;
819 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000820 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000821 }
822 handle_special(dest);
823 return dest;
824}
825
Mike Frysinger10a11e22005-09-27 02:23:02 +0000826static var *incvar(var *v)
827{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000828 return setvar_i(v, getvar_i(v)+1.);
829}
830
831/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000832static int is_numeric(var *v)
833{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000834 getvar_i(v);
835 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
836}
837
838/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000839static int istrue(var *v)
840{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000841 if (is_numeric(v))
842 return (v->number == 0) ? 0 : 1;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000843 return (v->string && *(v->string)) ? 1 : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000844}
845
Eric Andersenaff114c2004-04-14 17:51:38 +0000846/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000847static var *nvalloc(int n)
848{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000849 nvblock *pb = NULL;
850 var *v, *r;
851 int size;
852
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000853 while (g_cb) {
854 pb = g_cb;
855 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break;
856 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000857 }
858
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000859 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000860 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000861 g_cb = xmalloc(sizeof(nvblock) + size * sizeof(var));
862 g_cb->size = size;
863 g_cb->pos = g_cb->nv;
864 g_cb->prev = pb;
865 g_cb->next = NULL;
866 if (pb) pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000867 }
868
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000869 v = r = g_cb->pos;
870 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000871
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000872 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000873 v->type = 0;
874 v->string = NULL;
875 v++;
876 }
877
878 return r;
879}
880
Mike Frysinger10a11e22005-09-27 02:23:02 +0000881static void nvfree(var *v)
882{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000883 var *p;
884
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000885 if (v < g_cb->nv || v >= g_cb->pos)
886 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000887
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000888 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000889 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000890 clear_array(iamarray(p));
891 free(p->x.array->items);
892 free(p->x.array);
893 }
894 if (p->type & VF_WALK)
895 free(p->x.walker);
896
897 clrvar(p);
898 }
899
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000900 g_cb->pos = v;
901 while (g_cb->prev && g_cb->pos == g_cb->nv) {
902 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000903 }
904}
905
906/* ------- awk program text parsing ------- */
907
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000908/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000909 * If token isn't expected, give away. Return token class
910 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000911static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000912{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000913#define concat_inserted (G.next_token__concat_inserted)
914#define save_tclass (G.next_token__save_tclass)
915#define save_info (G.next_token__save_info)
916/* Initialized to TC_OPTERM: */
917#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000918
Denis Vlasenkof782f522007-01-01 23:51:30 +0000919 char *p, *pp, *s;
920 const char *tl;
921 uint32_t tc;
922 const uint32_t *ti;
923 int l;
924
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000925 if (t_rollback) {
926 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000927
928 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000929 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000930 t_tclass = save_tclass;
931 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000932
933 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000934 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000935 readnext:
Glenn L McGrath545106f2002-11-11 06:21:00 +0000936 skip_spaces(&p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000937 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000938 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000939 while (*p != '\n' && *p != '\0')
940 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000941
942 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000943 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000944
945 if (*p == '\0') {
946 tc = TC_EOF;
947
948 } else if (*p == '\"') {
949 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000950 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000951 while (*p != '\"') {
952 if (*p == '\0' || *p == '\n')
953 syntax_error(EMSG_UNEXP_EOS);
954 *(s++) = nextchar(&p);
955 }
956 p++;
957 *s = '\0';
958 tc = TC_STRING;
959
960 } else if ((expected & TC_REGEXP) && *p == '/') {
961 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000962 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000963 while (*p != '/') {
964 if (*p == '\0' || *p == '\n')
965 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +0000966 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000967 if (*s++ == '\\') {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000968 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000969 *(s-1) = bb_process_escape_sequence((const char **)&p);
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000970 if (*pp == '\\')
971 *s++ = '\\';
972 if (p == pp)
973 *s++ = *p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000974 }
975 }
976 p++;
977 *s = '\0';
978 tc = TC_REGEXP;
979
980 } else if (*p == '.' || isdigit(*p)) {
981 /* it's a number */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000982 t_double = strtod(p, &p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000983 if (*p == '.')
984 syntax_error(EMSG_UNEXP_TOKEN);
985 tc = TC_NUMBER;
986
987 } else {
988 /* search for something known */
989 tl = tokenlist;
990 tc = 0x00000001;
991 ti = tokeninfo;
992 while (*tl) {
993 l = *(tl++);
994 if (l == NTCC) {
995 tc <<= 1;
996 continue;
997 }
998 /* if token class is expected, token
999 * matches and it's not a longer word,
1000 * then this is what we are looking for
1001 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001002 if ((tc & (expected | TC_WORD | TC_NEWLINE))
1003 && *tl == *p && strncmp(p, tl, l) == 0
1004 && !((tc & TC_WORD) && isalnum_(p[l]))
1005 ) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001006 t_info = *ti;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001007 p += l;
1008 break;
1009 }
1010 ti++;
1011 tl += l;
1012 }
1013
Denis Vlasenkof782f522007-01-01 23:51:30 +00001014 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001015 /* it's a name (var/array/function),
1016 * otherwise it's something wrong
1017 */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001018 if (!isalnum_(*p))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001019 syntax_error(EMSG_UNEXP_TOKEN);
1020
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001021 t_string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001022 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001023 *(p-1) = *p;
1024 }
1025 *(p-1) = '\0';
1026 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +00001027 /* also consume whitespace between functionname and bracket */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001028 if (!(expected & TC_VARIABLE))
1029 skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001030 if (*p == '(') {
1031 tc = TC_FUNCTION;
1032 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001033 if (*p == '[') {
1034 p++;
1035 tc = TC_ARRAY;
1036 }
1037 }
1038 }
1039 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001040 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001041
1042 /* skipping newlines in some cases */
1043 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1044 goto readnext;
1045
1046 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001047 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001048 concat_inserted = TRUE;
1049 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001050 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001051 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001052 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001053 }
1054
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001055 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001056 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001057 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001058
1059 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001060 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001061 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001062 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001063
1064 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001065#undef concat_inserted
1066#undef save_tclass
1067#undef save_info
1068#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001069}
1070
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001071static void rollback_token(void)
1072{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001073 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001074}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001075
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001076static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001077{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001078 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001079
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001080 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001081 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001082 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001083 return n;
1084}
1085
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001086static node *mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001087{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001088 n->info = OC_REGEXP;
1089 n->l.re = re;
1090 n->r.ire = re + 1;
1091 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001092 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001093
1094 return n;
1095}
1096
Mike Frysinger10a11e22005-09-27 02:23:02 +00001097static node *condition(void)
1098{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001099 next_token(TC_SEQSTART);
1100 return parse_expr(TC_SEQTERM);
1101}
1102
1103/* parse expression terminated by given argument, return ptr
1104 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001105static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001106{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001107 node sn;
1108 node *cn = &sn;
1109 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001110 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001111 var *v;
1112
1113 sn.info = PRIMASK;
1114 sn.r.n = glptr = NULL;
1115 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1116
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001117 while (!((tc = next_token(xtc)) & iexp)) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001118 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001119 /* input redirection (<) attached to glptr node */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001120 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001121 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001122 xtc = TC_OPERAND | TC_UOPPRE;
1123 glptr = NULL;
1124
1125 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1126 /* for binary and postfix-unary operators, jump back over
1127 * previous operators with higher priority */
1128 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001129 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1130 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) )
Glenn L McGrath545106f2002-11-11 06:21:00 +00001131 vn = vn->a.n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001132 if ((t_info & OPCLSMASK) == OC_TERNARY)
1133 t_info += P(6);
1134 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001135 cn->a.n = vn->a.n;
1136 if (tc & TC_BINOP) {
1137 cn->l.n = vn;
1138 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001139 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001140 /* it's a pipe */
1141 next_token(TC_GETLINE);
1142 /* give maximum priority to this pipe */
1143 cn->info &= ~PRIMASK;
1144 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1145 }
1146 } else {
1147 cn->r.n = vn;
1148 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1149 }
1150 vn->a.n = cn;
1151
1152 } else {
1153 /* for operands and prefix-unary operators, attach them
1154 * to last node */
1155 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001156 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001157 cn->a.n = vn;
1158 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1159 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001160 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001161 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001162 * only simple tclasses should be used! */
1163 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001164 case TC_VARIABLE:
1165 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001166 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001167 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001168 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001169 cn->info = OC_FNARG;
1170 cn->l.i = v->x.aidx;
1171 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001172 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001173 }
1174 if (tc & TC_ARRAY) {
1175 cn->info |= xS;
1176 cn->r.n = parse_expr(TC_ARRTERM);
1177 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001178 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001179
Denis Vlasenkof782f522007-01-01 23:51:30 +00001180 case TC_NUMBER:
1181 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001182 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001183 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001184 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001185 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001186 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001187 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001188 break;
1189
Denis Vlasenkof782f522007-01-01 23:51:30 +00001190 case TC_REGEXP:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001191 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001192 break;
1193
Denis Vlasenkof782f522007-01-01 23:51:30 +00001194 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001195 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001196 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001197 cn->l.n = condition();
1198 break;
1199
Denis Vlasenkof782f522007-01-01 23:51:30 +00001200 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001201 cn = vn->r.n = parse_expr(TC_SEQTERM);
1202 cn->a.n = vn;
1203 break;
1204
Denis Vlasenkof782f522007-01-01 23:51:30 +00001205 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001206 glptr = cn;
1207 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1208 break;
1209
Denis Vlasenkof782f522007-01-01 23:51:30 +00001210 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001211 cn->l.n = condition();
1212 break;
1213 }
1214 }
1215 }
1216 }
1217 return sn.r.n;
1218}
1219
1220/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001221static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001222{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001223 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001224
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001225 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001226 seq->first = seq->last = new_node(0);
1227
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001228 if (seq->programname != g_progname) {
1229 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001230 n = chain_node(OC_NEWSOURCE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001231 n->l.s = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001232 }
1233
1234 n = seq->last;
1235 n->info = info;
1236 seq->last = n->a.n = new_node(OC_DONE);
1237
1238 return n;
1239}
1240
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001241static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001242{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001243 node *n;
1244
1245 n = chain_node(info);
1246 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001247 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001248 rollback_token();
1249}
1250
Mike Frysinger10a11e22005-09-27 02:23:02 +00001251static node *chain_loop(node *nn)
1252{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001253 node *n, *n2, *save_brk, *save_cont;
1254
1255 save_brk = break_ptr;
1256 save_cont = continue_ptr;
1257
1258 n = chain_node(OC_BR | Vx);
1259 continue_ptr = new_node(OC_EXEC);
1260 break_ptr = new_node(OC_EXEC);
1261 chain_group();
1262 n2 = chain_node(OC_EXEC | Vx);
1263 n2->l.n = nn;
1264 n2->a.n = n;
1265 continue_ptr->a.n = n2;
1266 break_ptr->a.n = n->r.n = seq->last;
1267
1268 continue_ptr = save_cont;
1269 break_ptr = save_brk;
1270
1271 return n;
1272}
1273
1274/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001275static void chain_group(void)
1276{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001277 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001278 node *n, *n2, *n3;
1279
1280 do {
1281 c = next_token(TC_GRPSEQ);
1282 } while (c & TC_NEWLINE);
1283
1284 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001285 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001286 if (t_tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001287 rollback_token();
1288 chain_group();
1289 }
1290 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1291 rollback_token();
1292 chain_expr(OC_EXEC | Vx);
1293 } else { /* TC_STATEMNT */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001294 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001295 case ST_IF:
1296 n = chain_node(OC_BR | Vx);
1297 n->l.n = condition();
1298 chain_group();
1299 n2 = chain_node(OC_EXEC);
1300 n->r.n = seq->last;
1301 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001302 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001303 n2->a.n = seq->last;
1304 } else {
1305 rollback_token();
1306 }
1307 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001308
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001309 case ST_WHILE:
1310 n2 = condition();
1311 n = chain_loop(NULL);
1312 n->l.n = n2;
1313 break;
1314
1315 case ST_DO:
1316 n2 = chain_node(OC_EXEC);
1317 n = chain_loop(NULL);
1318 n2->a.n = n->a.n;
1319 next_token(TC_WHILE);
1320 n->l.n = condition();
1321 break;
1322
1323 case ST_FOR:
1324 next_token(TC_SEQSTART);
1325 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001326 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001327 if ((n2->info & OPCLSMASK) != OC_IN)
1328 syntax_error(EMSG_UNEXP_TOKEN);
1329 n = chain_node(OC_WALKINIT | VV);
1330 n->l.n = n2->l.n;
1331 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001332 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001333 n->info = OC_WALKNEXT | Vx;
1334 n->l.n = n2->l.n;
1335 } else { /* for (;;) */
1336 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001337 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001338 n2 = parse_expr(TC_SEMICOL);
1339 n3 = parse_expr(TC_SEQTERM);
1340 n = chain_loop(n3);
1341 n->l.n = n2;
1342 if (! n2)
1343 n->info = OC_EXEC;
1344 }
1345 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001346
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001347 case OC_PRINT:
1348 case OC_PRINTF:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001349 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001350 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001351 if (t_tclass & TC_OUTRDR) {
1352 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001353 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1354 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001355 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001356 rollback_token();
1357 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001358
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001359 case OC_BREAK:
1360 n = chain_node(OC_EXEC);
1361 n->a.n = break_ptr;
1362 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001363
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001364 case OC_CONTINUE:
1365 n = chain_node(OC_EXEC);
1366 n->a.n = continue_ptr;
1367 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001368
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001369 /* delete, next, nextfile, return, exit */
1370 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001371 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001372 }
1373 }
1374}
1375
Mike Frysinger10a11e22005-09-27 02:23:02 +00001376static void parse_program(char *p)
1377{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001378 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001379 node *cn;
1380 func *f;
1381 var *v;
1382
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001383 g_pos = p;
1384 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001385 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001386 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001387
1388 if (tclass & TC_OPTERM)
1389 continue;
1390
1391 seq = &mainseq;
1392 if (tclass & TC_BEGIN) {
1393 seq = &beginseq;
1394 chain_group();
1395
1396 } else if (tclass & TC_END) {
1397 seq = &endseq;
1398 chain_group();
1399
1400 } else if (tclass & TC_FUNCDECL) {
1401 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001402 g_pos++;
1403 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001404 f->body.first = NULL;
1405 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001406 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001407 v = findvar(ahash, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001408 v->x.aidx = (f->nargs)++;
1409
1410 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1411 break;
1412 }
1413 seq = &(f->body);
1414 chain_group();
1415 clear_array(ahash);
1416
1417 } else if (tclass & TC_OPSEQ) {
1418 rollback_token();
1419 cn = chain_node(OC_TEST);
1420 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001421 if (t_tclass & TC_GRPSTART) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001422 rollback_token();
1423 chain_group();
1424 } else {
1425 chain_node(OC_PRINT);
1426 }
1427 cn->r.n = mainseq.last;
1428
1429 } else /* if (tclass & TC_GRPSTART) */ {
1430 rollback_token();
1431 chain_group();
1432 }
1433 }
1434}
1435
1436
1437/* -------- program execution part -------- */
1438
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001439static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001440{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001441 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001442 node *n;
1443
1444 re = &spl->re[0];
1445 ire = &spl->re[1];
1446 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001447 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001448 regfree(re);
1449 regfree(ire);
1450 }
Rob Landleya3896512006-05-07 20:20:34 +00001451 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001452 mk_re_node(s, n, re);
1453 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001454 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001455 }
1456
1457 return n;
1458}
1459
1460/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001461 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001462 * be later regfree'd manually
1463 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001464static regex_t *as_regex(node *op, regex_t *preg)
1465{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001466 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001467 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001468
1469 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1470 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001471 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001472 v = nvalloc(1);
1473 s = getvar_s(evaluate(op, v));
1474 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1475 nvfree(v);
1476 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001477}
1478
1479/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001480static void qrealloc(char **b, int n, int *size)
1481{
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001482 if (!*b || n >= *size)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001483 *b = xrealloc(*b, *size = n + (n>>1) + 80);
1484}
1485
1486/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001487static void fsrealloc(int size)
1488{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001489 int i;
1490
1491 if (size >= maxfields) {
1492 i = maxfields;
1493 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001494 Fields = xrealloc(Fields, maxfields * sizeof(var));
1495 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001496 Fields[i].type = VF_SPECIAL;
1497 Fields[i].string = NULL;
1498 }
1499 }
1500
1501 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001502 for (i = size; i < nfields; i++) {
1503 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001504 }
1505 }
1506 nfields = size;
1507}
1508
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001509static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001510{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001511 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001512 char c[4];
1513 char *s1;
1514 regmatch_t pmatch[2];
1515
1516 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001517 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1518 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001519
1520 c[0] = c[1] = (char)spl->info;
1521 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001522 if (*getvar_s(intvar[RS]) == '\0')
1523 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001524
1525 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1526 while (*s) {
1527 l = strcspn(s, c+2);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001528 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1529 && pmatch[0].rm_so <= l
1530 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001531 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001532 if (pmatch[0].rm_eo == 0) {
1533 l++;
1534 pmatch[0].rm_eo++;
1535 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001536 } else {
1537 pmatch[0].rm_eo = l;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001538 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001539 }
1540
1541 memcpy(s1, s, l);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001542 s1[l] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001543 nextword(&s1);
1544 s += pmatch[0].rm_eo;
1545 n++;
1546 }
1547 } else if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001548 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001549 *s1++ = *s++;
1550 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001551 n++;
1552 }
1553 } else if (c[0] != ' ') { /* single-character split */
1554 if (icase) {
1555 c[0] = toupper(c[0]);
1556 c[1] = tolower(c[1]);
1557 }
1558 if (*s1) n++;
1559 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001560 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001561 n++;
1562 }
1563 } else { /* space split */
1564 while (*s) {
Denis Vlasenkod18a3a22006-10-25 12:46:03 +00001565 s = skip_whitespace(s);
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001566 if (!*s) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001567 n++;
1568 while (*s && !isspace(*s))
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001569 *s1++ = *s++;
1570 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001571 }
1572 }
1573 return n;
1574}
1575
Mike Frysinger10a11e22005-09-27 02:23:02 +00001576static void split_f0(void)
1577{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001578#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001579
Glenn L McGrath545106f2002-11-11 06:21:00 +00001580 int i, n;
1581 char *s;
1582
1583 if (is_f0_split)
1584 return;
1585
1586 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001587 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001588 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001589 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001590 fsrealloc(n);
1591 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001592 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001593 Fields[i].string = nextword(&s);
1594 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1595 }
1596
1597 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001598 clrvar(intvar[NF]);
1599 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1600 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001601#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001602}
1603
1604/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001605static void handle_special(var *v)
1606{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001607 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001608 char *b;
1609 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001610 int sl, l, len, i, bsize;
1611
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001612 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001613 return;
1614
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001615 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001616 n = (int)getvar_i(v);
1617 fsrealloc(n);
1618
1619 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001620 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001621 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001622 b = NULL;
1623 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001624 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001625 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001626 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001627 if (b) {
1628 memcpy(b+len, sep, sl);
1629 len += sl;
1630 }
1631 qrealloc(&b, len+l+sl, &bsize);
1632 memcpy(b+len, s, l);
1633 len += l;
1634 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001635 if (b)
1636 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001637 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001638 is_f0_split = TRUE;
1639
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001640 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001641 is_f0_split = FALSE;
1642
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001643 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001644 mk_splitter(getvar_s(v), &fsplitter);
1645
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001646 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001647 mk_splitter(getvar_s(v), &rsplitter);
1648
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001649 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001650 icase = istrue(v);
1651
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001652 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001653 n = getvar_i(intvar[NF]);
1654 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001655 /* right here v is invalid. Just to note... */
1656 }
1657}
1658
1659/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001660static node *nextarg(node **pn)
1661{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001662 node *n;
1663
1664 n = *pn;
1665 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1666 *pn = n->r.n;
1667 n = n->l.n;
1668 } else {
1669 *pn = NULL;
1670 }
1671 return n;
1672}
1673
Mike Frysinger10a11e22005-09-27 02:23:02 +00001674static void hashwalk_init(var *v, xhash *array)
1675{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001676 char **w;
1677 hash_item *hi;
1678 int i;
1679
1680 if (v->type & VF_WALK)
1681 free(v->x.walker);
1682
1683 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001684 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001685 w[0] = w[1] = (char *)(w + 2);
1686 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001687 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001688 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001689 strcpy(*w, hi->name);
1690 nextword(w);
1691 hi = hi->next;
1692 }
1693 }
1694}
1695
Mike Frysinger10a11e22005-09-27 02:23:02 +00001696static int hashwalk_next(var *v)
1697{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001698 char **w;
1699
1700 w = v->x.walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001701 if (w[1] == w[0])
Glenn L McGrath545106f2002-11-11 06:21:00 +00001702 return FALSE;
1703
1704 setvar_s(v, nextword(w+1));
1705 return TRUE;
1706}
1707
1708/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001709static int ptest(node *pattern)
1710{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001711 /* ptest__v is "static": to save stack space? */
1712 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001713}
1714
1715/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001716static int awk_getline(rstream *rsm, var *v)
1717{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001718 char *b;
1719 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001720 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001721 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001722 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001723
1724 /* we're using our own buffer since we need access to accumulating
1725 * characters
1726 */
1727 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001728 m = rsm->buffer;
1729 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001730 p = rsm->pos;
1731 size = rsm->size;
1732 c = (char) rsplitter.n.info;
1733 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001734
1735 if (! m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001736 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001737 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001738 so = eo = p;
1739 r = 1;
1740 if (p > 0) {
1741 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1742 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001743 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001744 so = pmatch[0].rm_so;
1745 eo = pmatch[0].rm_eo;
1746 if (b[eo] != '\0')
1747 break;
1748 }
1749 } else if (c != '\0') {
1750 s = strchr(b+pp, c);
Rob Landley46e351d2006-02-14 16:05:32 +00001751 if (! s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001752 if (s) {
1753 so = eo = s-b;
1754 eo++;
1755 break;
1756 }
1757 } else {
1758 while (b[rp] == '\n')
1759 rp++;
1760 s = strstr(b+rp, "\n\n");
1761 if (s) {
1762 so = eo = s-b;
1763 while (b[eo] == '\n') eo++;
1764 if (b[eo] != '\0')
1765 break;
1766 }
1767 }
1768 }
1769
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001770 if (a > 0) {
1771 memmove(m, (const void *)(m+a), p+1);
1772 b = m;
1773 a = 0;
1774 }
1775
1776 qrealloc(&m, a+p+128, &size);
1777 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001778 pp = p;
1779 p += safe_read(fd, b+p, size-p-1);
1780 if (p < pp) {
1781 p = 0;
1782 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001783 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001784 }
1785 b[p] = '\0';
1786
1787 } while (p > pp);
1788
1789 if (p == 0) {
1790 r--;
1791 } else {
1792 c = b[so]; b[so] = '\0';
1793 setvar_s(v, b+rp);
1794 v->type |= VF_USER;
1795 b[so] = c;
1796 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001797 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001798 b[eo] = c;
1799 }
1800
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001801 rsm->buffer = m;
1802 rsm->adv = a + eo;
1803 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001804 rsm->size = size;
1805
1806 return r;
1807}
1808
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001809static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001810{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001811 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001812 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001813 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001814
1815 if (int_as_int && n == (int)n) {
1816 r = snprintf(b, size, "%d", (int)n);
1817 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001818 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001819 if (strchr("diouxX", c)) {
1820 r = snprintf(b, size, format, (int)n);
1821 } else if (strchr("eEfgG", c)) {
1822 r = snprintf(b, size, format, n);
1823 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001824 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001825 }
1826 }
1827 return r;
1828}
1829
1830
1831/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001832static char *awk_printf(node *n)
1833{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001834 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001835 char *fmt, *s, *f;
1836 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001837 int i, j, incr, bsize;
1838 char c, c1;
1839 var *v, *arg;
1840
1841 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001842 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001843
1844 i = 0;
1845 while (*f) {
1846 s = f;
1847 while (*f && (*f != '%' || *(++f) == '%'))
1848 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001849 while (*f && !isalpha(*f)) {
1850 if (*f == '*')
1851 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001852 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001853 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001854
1855 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001856 qrealloc(&b, incr + i, &bsize);
1857 c = *f;
1858 if (c != '\0') f++;
1859 c1 = *f;
1860 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001861 arg = evaluate(nextarg(&n), v);
1862
1863 j = i;
1864 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001865 i += sprintf(b+i, s, is_numeric(arg) ?
1866 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001867 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001868 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001869 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001870 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001871 } else {
1872 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1873 }
1874 *f = c1;
1875
1876 /* if there was an error while sprintf, return value is negative */
1877 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001878 }
1879
Denis Vlasenkof782f522007-01-01 23:51:30 +00001880 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001881 free(fmt);
1882 nvfree(v);
1883 b[i] = '\0';
1884 return b;
1885}
1886
1887/* common substitution routine
1888 * replace (nm) substring of (src) that match (n) with (repl), store
1889 * result into (dest), return number of substitutions. If nm=0, replace
1890 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1891 * subexpression matching (\1-\9)
1892 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001893static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001894{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001895 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001896 const char *s;
1897 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001898 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1899 regmatch_t pmatch[10];
1900 regex_t sreg, *re;
1901
1902 re = as_regex(rn, &sreg);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001903 if (! src) src = intvar[F0];
1904 if (! dest) dest = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001905
1906 i = di = 0;
1907 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001908 rl = strlen(repl);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001909 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001910 so = pmatch[0].rm_so;
1911 eo = pmatch[0].rm_eo;
1912
1913 qrealloc(&ds, di + eo + rl, &dssize);
1914 memcpy(ds + di, sp, eo);
1915 di += eo;
1916 if (++i >= nm) {
1917 /* replace */
1918 di -= (eo - so);
1919 nbs = 0;
1920 for (s = repl; *s; s++) {
1921 ds[di++] = c = *s;
1922 if (c == '\\') {
1923 nbs++;
1924 continue;
1925 }
1926 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1927 di -= ((nbs + 3) >> 1);
1928 j = 0;
1929 if (c != '&') {
1930 j = c - '0';
1931 nbs++;
1932 }
1933 if (nbs % 2) {
1934 ds[di++] = c;
1935 } else {
1936 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1937 qrealloc(&ds, di + rl + n, &dssize);
1938 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1939 di += n;
1940 }
1941 }
1942 nbs = 0;
1943 }
1944 }
1945
1946 sp += eo;
1947 if (i == nm) break;
1948 if (eo == so) {
1949 if (! (ds[di++] = *sp++)) break;
1950 }
1951 }
1952
1953 qrealloc(&ds, di + strlen(sp), &dssize);
1954 strcpy(ds + di, sp);
1955 setvar_p(dest, ds);
1956 if (re == &sreg) regfree(re);
1957 return i;
1958}
1959
Mike Frysinger10a11e22005-09-27 02:23:02 +00001960static var *exec_builtin(node *op, var *res)
1961{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001962#define tspl (G.exec_builtin__tspl)
1963
Glenn L McGrath545106f2002-11-11 06:21:00 +00001964 int (*to_xxx)(int);
1965 var *tv;
1966 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001967 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001968 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001969 regmatch_t pmatch[2];
1970 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001971 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001972 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001973 int nargs;
1974 time_t tt;
1975 char *s, *s1;
1976 int i, l, ll, n;
1977
1978 tv = nvalloc(4);
1979 isr = info = op->info;
1980 op = op->l.n;
1981
1982 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001983 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001984 an[i] = nextarg(&op);
1985 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
1986 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
1987 isr >>= 1;
1988 }
1989
1990 nargs = i;
1991 if (nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001992 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001993
1994 switch (info & OPNMASK) {
1995
Denis Vlasenkof782f522007-01-01 23:51:30 +00001996 case B_a2:
1997#if ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +00001998 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
1999#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002000 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002001#endif
2002 break;
2003
Denis Vlasenkof782f522007-01-01 23:51:30 +00002004 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002005 if (nargs > 2) {
2006 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2007 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2008 } else {
2009 spl = &fsplitter.n;
2010 }
2011
2012 n = awk_split(as[0], spl, &s);
2013 s1 = s;
2014 clear_array(iamarray(av[1]));
2015 for (i=1; i<=n; i++)
2016 setari_u(av[1], i, nextword(&s1));
2017 free(s);
2018 setvar_i(res, n);
2019 break;
2020
Denis Vlasenkof782f522007-01-01 23:51:30 +00002021 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00002022 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002023 i = getvar_i(av[1]) - 1;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002024 if (i > l) i = l;
2025 if (i < 0) i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002026 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002027 if (n < 0) n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002028 s = xmalloc(n+1);
2029 strncpy(s, as[0]+i, n);
2030 s[n] = '\0';
2031 setvar_p(res, s);
2032 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002033
Denis Vlasenkof782f522007-01-01 23:51:30 +00002034 case B_an:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002035 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
2036 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002037
Denis Vlasenkof782f522007-01-01 23:51:30 +00002038 case B_co:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002039 setvar_i(res, ~(long)getvar_i(av[0]));
2040 break;
2041
Denis Vlasenkof782f522007-01-01 23:51:30 +00002042 case B_ls:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002043 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
2044 break;
2045
Denis Vlasenkof782f522007-01-01 23:51:30 +00002046 case B_or:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002047 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
2048 break;
2049
Denis Vlasenkof782f522007-01-01 23:51:30 +00002050 case B_rs:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002051 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
2052 break;
2053
Denis Vlasenkof782f522007-01-01 23:51:30 +00002054 case B_xo:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002055 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
2056 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002057
Denis Vlasenkof782f522007-01-01 23:51:30 +00002058 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002059 to_xxx = tolower;
2060 goto lo_cont;
2061
Denis Vlasenkof782f522007-01-01 23:51:30 +00002062 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002063 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002064 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00002065 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002066 while (*s1) {
2067 *s1 = (*to_xxx)(*s1);
2068 s1++;
2069 }
2070 setvar_p(res, s);
2071 break;
2072
Denis Vlasenkof782f522007-01-01 23:51:30 +00002073 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002074 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002075 ll = strlen(as[1]);
2076 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002077 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002078 if (!icase) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002079 s = strstr(as[0], as[1]);
2080 if (s) n = (s - as[0]) + 1;
2081 } else {
2082 /* this piece of code is terribly slow and
2083 * really should be rewritten
2084 */
2085 for (i=0; i<=l; i++) {
2086 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2087 n = i+1;
2088 break;
2089 }
2090 }
2091 }
2092 }
2093 setvar_i(res, n);
2094 break;
2095
Denis Vlasenkof782f522007-01-01 23:51:30 +00002096 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002097 if (nargs > 1)
2098 tt = getvar_i(av[1]);
2099 else
2100 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002101 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002102 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002103 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2104 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002105 g_buf[i] = '\0';
2106 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002107 break;
2108
Denis Vlasenkof782f522007-01-01 23:51:30 +00002109 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002110 re = as_regex(an[1], &sreg);
2111 n = regexec(re, as[0], 1, pmatch, 0);
2112 if (n == 0) {
2113 pmatch[0].rm_so++;
2114 pmatch[0].rm_eo++;
2115 } else {
2116 pmatch[0].rm_so = 0;
2117 pmatch[0].rm_eo = -1;
2118 }
2119 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2120 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2121 setvar_i(res, pmatch[0].rm_so);
2122 if (re == &sreg) regfree(re);
2123 break;
2124
Denis Vlasenkof782f522007-01-01 23:51:30 +00002125 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002126 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2127 break;
2128
Denis Vlasenkof782f522007-01-01 23:51:30 +00002129 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002130 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2131 break;
2132
Denis Vlasenkof782f522007-01-01 23:51:30 +00002133 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002134 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2135 break;
2136 }
2137
2138 nvfree(tv);
2139 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002140#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002141}
2142
2143/*
2144 * Evaluate node - the heart of the program. Supplied with subtree
2145 * and place where to store result. returns ptr to result.
2146 */
2147#define XC(n) ((n) >> 8)
2148
Mike Frysinger10a11e22005-09-27 02:23:02 +00002149static var *evaluate(node *op, var *res)
2150{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002151/* This procedure is recursive so we should count every byte */
2152#define fnargs (G.evaluate__fnargs)
2153/* seed is initialized to 1 */
2154#define seed (G.evaluate__seed)
2155#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002156
Glenn L McGrath545106f2002-11-11 06:21:00 +00002157 node *op1;
2158 var *v1;
2159 union {
2160 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002161 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002162 double d;
2163 int i;
2164 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002165 uint32_t opinfo;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002166 int opn;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002167 union {
2168 char *s;
2169 rstream *rsm;
2170 FILE *F;
2171 var *v;
2172 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002173 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002174 } X;
2175
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002176 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002177 return setvar_s(res, NULL);
2178
2179 v1 = nvalloc(2);
2180
2181 while (op) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002182 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002183 opn = (opinfo & OPNMASK);
2184 g_lineno = op->lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002185
Mike Frysingerde2b9382005-09-27 03:18:00 +00002186 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002187 op1 = op->l.n;
2188 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2189 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2190 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2191 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2192 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2193
2194 switch (XC(opinfo & OPCLSMASK)) {
2195
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002196 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002197
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002198 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002199 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002200 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2201 /* it's range pattern */
2202 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2203 op->info |= OF_CHECKED;
2204 if (ptest(op1->r.n))
2205 op->info &= ~OF_CHECKED;
2206
2207 op = op->a.n;
2208 } else {
2209 op = op->r.n;
2210 }
2211 } else {
2212 op = (ptest(op1)) ? op->a.n : op->r.n;
2213 }
2214 break;
2215
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002216 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002217 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002218 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002219
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002220 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002221 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002222 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002223 break;
2224
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002225 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002226 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002227 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002228 break;
2229
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002230 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002231 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002232 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2233 break;
2234
Denis Vlasenkof782f522007-01-01 23:51:30 +00002235 case XC( OC_PRINT ):
2236 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002237 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002238 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002239 X.rsm = newfile(R.s);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002240 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002241 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002242 X.rsm->F = popen(R.s, "w");
2243 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002244 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002245 X.rsm->is_pipe = 1;
2246 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002247 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002248 }
2249 }
2250 X.F = X.rsm->F;
2251 }
2252
2253 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002254 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002255 fputs(getvar_s(intvar[F0]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002256 } else {
2257 while (op1) {
2258 L.v = evaluate(nextarg(&op1), v1);
2259 if (L.v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002260 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002261 getvar_i(L.v), TRUE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002262 fputs(g_buf, X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002263 } else {
2264 fputs(getvar_s(L.v), X.F);
2265 }
2266
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002267 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002268 }
2269 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002270 fputs(getvar_s(intvar[ORS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002271
2272 } else { /* OC_PRINTF */
2273 L.s = awk_printf(op1);
2274 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002275 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002276 }
2277 fflush(X.F);
2278 break;
2279
Denis Vlasenkof782f522007-01-01 23:51:30 +00002280 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002281 X.info = op1->info & OPCLSMASK;
2282 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002283 R.v = op1->l.v;
2284 } else if (X.info == OC_FNARG) {
2285 R.v = &fnargs[op1->l.i];
2286 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002287 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002288 }
2289
Mike Frysingerde2b9382005-09-27 03:18:00 +00002290 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002291 clrvar(L.v);
2292 L.s = getvar_s(evaluate(op1->r.n, v1));
2293 hash_remove(iamarray(R.v), L.s);
2294 } else {
2295 clear_array(iamarray(R.v));
2296 }
2297 break;
2298
Denis Vlasenkof782f522007-01-01 23:51:30 +00002299 case XC( OC_NEWSOURCE ):
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002300 g_progname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002301 break;
2302
Denis Vlasenkof782f522007-01-01 23:51:30 +00002303 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002304 copyvar(res, L.v);
2305 break;
2306
Denis Vlasenkof782f522007-01-01 23:51:30 +00002307 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002308 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002309 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002310 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002311 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002312 clrvar(res);
2313 break;
2314
Denis Vlasenkof782f522007-01-01 23:51:30 +00002315 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002316 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002317
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002318 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002319
Denis Vlasenkof782f522007-01-01 23:51:30 +00002320 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002321 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002322 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002323 split_f0();
2324 goto v_cont;
2325
Denis Vlasenkof782f522007-01-01 23:51:30 +00002326 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002327 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002328 v_cont:
2329 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002330 break;
2331
Denis Vlasenkof782f522007-01-01 23:51:30 +00002332 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002333 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2334 break;
2335
Denis Vlasenkof782f522007-01-01 23:51:30 +00002336 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002337 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002338 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002339 goto re_cont;
2340
Denis Vlasenkof782f522007-01-01 23:51:30 +00002341 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002342 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002343 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002344 X.re = as_regex(op1, &sreg);
2345 R.i = regexec(X.re, L.s, 0, NULL, 0);
2346 if (X.re == &sreg) regfree(X.re);
2347 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2348 break;
2349
Denis Vlasenkof782f522007-01-01 23:51:30 +00002350 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002351 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002352 if (R.v == v1+1 && R.v->string) {
2353 res = setvar_p(L.v, R.v->string);
2354 R.v->string = NULL;
2355 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002356 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002357 }
2358 break;
2359
Denis Vlasenkof782f522007-01-01 23:51:30 +00002360 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002361 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002362 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002363 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2364 break;
2365
Denis Vlasenkof782f522007-01-01 23:51:30 +00002366 case XC( OC_FUNC ):
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002367 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002368 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002369
2370 X.v = R.v = nvalloc(op->r.f->nargs+1);
2371 while (op1) {
2372 L.v = evaluate(nextarg(&op1), v1);
2373 copyvar(R.v, L.v);
2374 R.v->type |= VF_CHILD;
2375 R.v->x.parent = L.v;
2376 if (++R.v - X.v >= op->r.f->nargs)
2377 break;
2378 }
2379
2380 R.v = fnargs;
2381 fnargs = X.v;
2382
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002383 L.s = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002384 res = evaluate(op->r.f->body.first, res);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002385 g_progname = L.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002386
2387 nvfree(fnargs);
2388 fnargs = R.v;
2389 break;
2390
Denis Vlasenkof782f522007-01-01 23:51:30 +00002391 case XC( OC_GETLINE ):
2392 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002393 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002394 X.rsm = newfile(L.s);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002395 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002396 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2397 X.rsm->F = popen(L.s, "r");
2398 X.rsm->is_pipe = TRUE;
2399 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002400 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002401 }
2402 }
2403 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002404 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002405 X.rsm = iF;
2406 }
2407
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002408 if (!X.rsm->F) {
2409 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002410 setvar_i(res, -1);
2411 break;
2412 }
2413
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002414 if (!op->r.n)
2415 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002416
2417 L.i = awk_getline(X.rsm, R.v);
2418 if (L.i > 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002419 if (!op1) {
2420 incvar(intvar[FNR]);
2421 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002422 }
2423 }
2424 setvar_i(res, L.i);
2425 break;
2426
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002427 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002428 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002429 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002430
Denis Vlasenkof782f522007-01-01 23:51:30 +00002431 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002432 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002433 break;
2434
Denis Vlasenkof782f522007-01-01 23:51:30 +00002435 case F_rn:
2436 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002437 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002438#if ENABLE_FEATURE_AWK_MATH
2439 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002440 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002441 break;
2442
Denis Vlasenkof782f522007-01-01 23:51:30 +00002443 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002444 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002445 break;
2446
Denis Vlasenkof782f522007-01-01 23:51:30 +00002447 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002448 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002449 break;
2450
Denis Vlasenkof782f522007-01-01 23:51:30 +00002451 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002452 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002453 break;
2454
Denis Vlasenkof782f522007-01-01 23:51:30 +00002455 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002456 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002457 break;
2458#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002459 case F_co:
2460 case F_ex:
2461 case F_lg:
2462 case F_si:
2463 case F_sq:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002464 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002465 break;
2466#endif
Denis Vlasenkof782f522007-01-01 23:51:30 +00002467 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002468 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002469 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002470 srand(seed);
2471 break;
2472
Denis Vlasenkof782f522007-01-01 23:51:30 +00002473 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002474 R.d = time(NULL);
2475 break;
2476
Denis Vlasenkof782f522007-01-01 23:51:30 +00002477 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002478 if (!op1)
2479 L.s = getvar_s(intvar[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002480 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002481 break;
2482
Denis Vlasenkof782f522007-01-01 23:51:30 +00002483 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002484 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002485 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2486 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002487 break;
2488
Denis Vlasenkof782f522007-01-01 23:51:30 +00002489 case F_ff:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002490 if (!op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002491 fflush(stdout);
2492 else {
2493 if (L.s && *L.s) {
2494 X.rsm = newfile(L.s);
2495 fflush(X.rsm->F);
2496 } else {
2497 fflush(NULL);
2498 }
2499 }
2500 break;
2501
Denis Vlasenkof782f522007-01-01 23:51:30 +00002502 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002503 X.rsm = (rstream *)hash_search(fdhash, L.s);
2504 if (X.rsm) {
2505 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002506 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002507 hash_remove(fdhash, L.s);
2508 }
2509 if (R.i != 0)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002510 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002511 R.d = (double)R.i;
2512 break;
2513 }
2514 setvar_i(res, R.d);
2515 break;
2516
Denis Vlasenkof782f522007-01-01 23:51:30 +00002517 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002518 res = exec_builtin(op, res);
2519 break;
2520
Denis Vlasenkof782f522007-01-01 23:51:30 +00002521 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002522 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002523 break;
2524
Denis Vlasenkof782f522007-01-01 23:51:30 +00002525 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002526 X.v = R.v;
2527 L.d = R.d = getvar_i(R.v);
2528 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002529 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002530 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002531 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002532 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002533 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002534 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002535 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002536 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002537 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002538 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002539 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002540 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002541 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002542 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002543 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002544 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002545 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002546 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002547 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002548 setvar_i(X.v, R.d);
2549 }
2550 setvar_i(res, L.d);
2551 break;
2552
Denis Vlasenkof782f522007-01-01 23:51:30 +00002553 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002554 R.i = (int)getvar_i(R.v);
2555 if (R.i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002556 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002557 } else {
2558 split_f0();
2559 if (R.i > nfields)
2560 fsrealloc(R.i);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002561 res = &Fields[R.i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002562 }
2563 break;
2564
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002565 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002566 case XC( OC_CONCAT ):
2567 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002568 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002569 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002570 strcpy(X.s, L.s);
2571 if ((opinfo & OPCLSMASK) == OC_COMMA) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002572 L.s = getvar_s(intvar[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002573 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002574 strcat(X.s, L.s);
2575 }
2576 strcat(X.s, R.s);
2577 setvar_p(res, X.s);
2578 break;
2579
Denis Vlasenkof782f522007-01-01 23:51:30 +00002580 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002581 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2582 break;
2583
Denis Vlasenkof782f522007-01-01 23:51:30 +00002584 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002585 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2586 break;
2587
Denis Vlasenkof782f522007-01-01 23:51:30 +00002588 case XC( OC_BINARY ):
2589 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002590 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002591 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002592 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002593 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002594 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002595 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002596 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002597 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002598 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002599 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002600 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002601 case '/':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002602 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002603 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002604 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002605 case '&':
2606#if ENABLE_FEATURE_AWK_MATH
Mike Frysingerde2b9382005-09-27 03:18:00 +00002607 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002608#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002609 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002610#endif
2611 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002612 case '%':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002613 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002614 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002615 break;
2616 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002617 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002618 break;
2619
Denis Vlasenkof782f522007-01-01 23:51:30 +00002620 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002621 if (is_numeric(L.v) && is_numeric(R.v)) {
2622 L.d = getvar_i(L.v) - getvar_i(R.v);
2623 } else {
2624 L.s = getvar_s(L.v);
2625 R.s = getvar_s(R.v);
2626 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2627 }
2628 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002629 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002630 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002631 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002632 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002633 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002634 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002635 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002636 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002637 break;
2638 }
2639 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2640 break;
2641
Denis Vlasenkof782f522007-01-01 23:51:30 +00002642 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002643 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002644 }
2645 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2646 op = op->a.n;
2647 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2648 break;
2649 if (nextrec)
2650 break;
2651 }
2652 nvfree(v1);
2653 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002654#undef fnargs
2655#undef seed
2656#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002657}
2658
2659
2660/* -------- main & co. -------- */
2661
Mike Frysinger10a11e22005-09-27 02:23:02 +00002662static int awk_exit(int r)
2663{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002664 var tv;
2665 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002666 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002667
Denis Vlasenkof782f522007-01-01 23:51:30 +00002668 zero_out_var(&tv);
2669
2670 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002671 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002672 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002673 evaluate(endseq.first, &tv);
2674 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002675
2676 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002677 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002678 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002679 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002680 if (hi->data.rs.F && hi->data.rs.is_pipe)
2681 pclose(hi->data.rs.F);
2682 hi = hi->next;
2683 }
2684 }
2685
2686 exit(r);
2687}
2688
2689/* if expr looks like "var=value", perform assignment and return 1,
2690 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002691static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002692{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002693 char *exprc, *s, *s0, *s1;
2694
Rob Landleyd921b2e2006-08-03 15:41:12 +00002695 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002696 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2697 free(exprc);
2698 return FALSE;
2699 }
2700
2701 *(s++) = '\0';
2702 s0 = s1 = s;
2703 while (*s)
2704 *(s1++) = nextchar(&s);
2705
2706 *s1 = '\0';
2707 setvar_u(newvar(exprc), s0);
2708 free(exprc);
2709 return TRUE;
2710}
2711
2712/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002713static rstream *next_input_file(void)
2714{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002715#define rsm (G.next_input_file__rsm)
2716#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002717
Glenn L McGrath545106f2002-11-11 06:21:00 +00002718 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002719 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002720
2721 if (rsm.F) fclose(rsm.F);
2722 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002723 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002724
2725 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002726 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002727 if (files_happen)
2728 return NULL;
2729 fname = "-";
2730 F = stdin;
2731 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002732 ind = getvar_s(incvar(intvar[ARGIND]));
2733 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002734 if (fname && *fname && !is_assignment(fname))
2735 F = afopen(fname, "r");
2736 }
2737 } while (!F);
2738
2739 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002740 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002741 rsm.F = F;
2742 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002743#undef rsm
2744#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002745}
2746
Denis Vlasenko06af2162007-02-03 17:28:39 +00002747int awk_main(int argc, char **argv);
Rob Landleydfba7412006-03-06 20:47:33 +00002748int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002749{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002750 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002751 char *opt_F, *opt_W;
2752 llist_t *opt_v = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002753 int i, j, flen;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002754 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002755 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002756 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002757 char *vnames = (char *)vNames; /* cheat */
2758 char *vvalues = (char *)vValues;
2759
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002760 INIT_G();
2761
Denis Vlasenko150f4022007-01-13 21:06:21 +00002762 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002763 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2764 if (ENABLE_LOCALE_SUPPORT)
2765 setlocale(LC_NUMERIC, "C");
2766
Denis Vlasenkof782f522007-01-01 23:51:30 +00002767 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002768
2769 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002770 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002771
2772 vhash = hash_init();
2773 ahash = hash_init();
2774 fdhash = hash_init();
2775 fnhash = hash_init();
2776
2777 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002778 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002779 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00002780 if (*vvalues != '\377')
2781 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002782 else
2783 setvar_i(v, 0);
2784
Denis Vlasenkof782f522007-01-01 23:51:30 +00002785 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002786 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002787 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002788 }
2789 }
2790
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002791 handle_special(intvar[FS]);
2792 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002793
Denis Vlasenkof782f522007-01-01 23:51:30 +00002794 newfile("/dev/stdin")->F = stdin;
2795 newfile("/dev/stdout")->F = stdout;
2796 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002797
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002798 /* Huh, people report that sometimes environ is NULL. Oh well. */
2799 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002800 char *s = xstrdup(*envp);
2801 char *s1 = strchr(s, '=');
2802 if (s1) {
2803 *s1++ = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002804 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1);
Eric Andersen67776be2004-07-30 23:52:08 +00002805 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002806 free(s);
2807 }
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002808 opt_complementary = "v::";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002809 opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &g_progname, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002810 argv += optind;
2811 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002812 if (opt & 0x1)
2813 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002814 while (opt_v) { /* -v */
2815 if (!is_assignment(llist_pop(&opt_v)))
2816 bb_show_usage();
2817 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002818 if (opt & 0x4) { // -f
Denis Vlasenkof782f522007-01-01 23:51:30 +00002819 char *s = s; /* die, gcc, die */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002820 FILE *from_file = afopen(g_progname, "r");
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002821 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002822 if (fseek(from_file, 0, SEEK_END) == 0) {
2823 flen = ftell(from_file);
2824 s = xmalloc(flen + 4);
2825 fseek(from_file, 0, SEEK_SET);
2826 i = 1 + fread(s + 1, 1, flen, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002827 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002828 for (i = j = 1; j > 0; i += j) {
2829 s = xrealloc(s, i + 4096);
2830 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002831 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002832 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002833 s[i] = '\0';
Denis Vlasenkof782f522007-01-01 23:51:30 +00002834 fclose(from_file);
2835 parse_program(s + 1);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002836 free(s);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002837 } else { // no -f: take program from 1st parameter
2838 if (!argc)
2839 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002840 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00002841 parse_program(*argv++);
2842 argc--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002843 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002844 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002845 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002846
Glenn L McGrath545106f2002-11-11 06:21:00 +00002847 /* fill in ARGV array */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002848 setvar_i(intvar[ARGC], argc + 1);
2849 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002850 i = 0;
2851 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002852 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002853
2854 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002855 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002856 awk_exit(EXIT_SUCCESS);
2857
2858 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002859 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002860
2861 /* passing through input files */
2862 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002863 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002864 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002865
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002866 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002867 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002868 incvar(intvar[NR]);
2869 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002870 evaluate(mainseq.first, &tv);
2871
2872 if (nextfile)
2873 break;
2874 }
2875
Denis Vlasenkof782f522007-01-01 23:51:30 +00002876 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002877 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002878
2879 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002880 }
2881
Glenn L McGrath545106f2002-11-11 06:21:00 +00002882 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002883 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002884}