blob: 4ec3d4652d8c1e125d56129bbac15b4adb4e6064 [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 Vlasenko6ca409e2007-08-12 20:58:27 +0000266static const char tokenlist[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000267 "\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 Vlasenko6ca409e2007-08-12 20:58:27 +0000376static const char vNames[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000377 "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 Vlasenko6ca409e2007-08-12 20:58:27 +0000384static const char vValues[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000385 "%.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 */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000391#define FIRST_PRIME 61
392static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000393
Glenn L McGrath545106f2002-11-11 06:21:00 +0000394
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000395/* Globals. Split in two parts so that first one is addressed
396 * with (mostly short) negative offsets */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000397struct globals {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000398 chain beginseq, mainseq, endseq, *seq;
399 node *break_ptr, *continue_ptr;
400 rstream *iF;
401 xhash *vhash, *ahash, *fdhash, *fnhash;
402 const char *g_progname;
403 int g_lineno;
404 int nfields;
405 int maxfields; /* used in fsrealloc() only */
406 var *Fields;
407 nvblock *g_cb;
408 char *g_pos;
409 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000410 smallint icase;
411 smallint exiting;
412 smallint nextrec;
413 smallint nextfile;
414 smallint is_f0_split;
415};
416struct globals2 {
417 uint32_t t_info; /* often used */
418 uint32_t t_tclass;
419 char *t_string;
420 int t_lineno;
421 int t_rollback;
422
423 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000424
425 /* former statics from various functions */
426 char *split_f0__fstrings;
427
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000428 uint32_t next_token__save_tclass;
429 uint32_t next_token__save_info;
430 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000431 smallint next_token__concat_inserted;
432
433 smallint next_input_file__files_happen;
434 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000435
436 var *evaluate__fnargs;
437 unsigned evaluate__seed;
438 regex_t evaluate__sreg;
439
440 var ptest__v;
441
442 tsplitter exec_builtin__tspl;
443
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000444 /* biggest and least used members go last */
445 double t_double;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000446 tsplitter fsplitter, rsplitter;
447};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000448#define G1 (ptr_to_globals[-1])
449#define G (*(struct globals2 *const)ptr_to_globals)
450/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
451/* char G1size[sizeof(G1)]; - 0x6c */
452/* char Gsize[sizeof(G)]; - 0x1cc */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000453/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000454/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
455#define beginseq (G1.beginseq )
456#define mainseq (G1.mainseq )
457#define endseq (G1.endseq )
458#define seq (G1.seq )
459#define break_ptr (G1.break_ptr )
460#define continue_ptr (G1.continue_ptr)
461#define iF (G1.iF )
462#define vhash (G1.vhash )
463#define ahash (G1.ahash )
464#define fdhash (G1.fdhash )
465#define fnhash (G1.fnhash )
466#define g_progname (G1.g_progname )
467#define g_lineno (G1.g_lineno )
468#define nfields (G1.nfields )
469#define maxfields (G1.maxfields )
470#define Fields (G1.Fields )
471#define g_cb (G1.g_cb )
472#define g_pos (G1.g_pos )
473#define g_buf (G1.g_buf )
474#define icase (G1.icase )
475#define exiting (G1.exiting )
476#define nextrec (G1.nextrec )
477#define nextfile (G1.nextfile )
478#define is_f0_split (G1.is_f0_split )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000479#define t_info (G.t_info )
480#define t_tclass (G.t_tclass )
481#define t_string (G.t_string )
482#define t_double (G.t_double )
483#define t_lineno (G.t_lineno )
484#define t_rollback (G.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000485#define intvar (G.intvar )
486#define fsplitter (G.fsplitter )
487#define rsplitter (G.rsplitter )
488#define INIT_G() do { \
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000489 PTR_TO_GLOBALS = xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000490 G.next_token__ltclass = TC_OPTERM; \
491 G.evaluate__seed = 1; \
492} while (0)
493
Glenn L McGrath545106f2002-11-11 06:21:00 +0000494
495/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000496static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000497static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000498static void chain_group(void);
499static var *evaluate(node *, var *);
500static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000501static int fmt_num(char *, int, const char *, double, int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000502static int awk_exit(int) ATTRIBUTE_NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000503
504/* ---- error handling ---- */
505
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000506static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
507static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
508static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
509static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
510static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
511static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
512static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
513static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
514static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
Denis Vlasenkof782f522007-01-01 23:51:30 +0000515#if !ENABLE_FEATURE_AWK_MATH
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000516static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000517#endif
518
Denis Vlasenkof782f522007-01-01 23:51:30 +0000519static void zero_out_var(var * vp)
520{
521 memset(vp, 0, sizeof(*vp));
522}
523
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000524static void syntax_error(const char *const message) ATTRIBUTE_NORETURN;
525static void syntax_error(const char *const message)
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000526{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000527 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000528}
529
Glenn L McGrath545106f2002-11-11 06:21:00 +0000530/* ---- hash stuff ---- */
531
Denis Vlasenkof782f522007-01-01 23:51:30 +0000532static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000533{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000534 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000535
Denis Vlasenkof782f522007-01-01 23:51:30 +0000536 while (*name) idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000537 return idx;
538}
539
540/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000541static xhash *hash_init(void)
542{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000543 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000544
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000545 newhash = xzalloc(sizeof(xhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000546 newhash->csize = FIRST_PRIME;
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000547 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000548
549 return newhash;
550}
551
552/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000553static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000554{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000555 hash_item *hi;
556
557 hi = hash->items [ hashidx(name) % hash->csize ];
558 while (hi) {
559 if (strcmp(hi->name, name) == 0)
560 return &(hi->data);
561 hi = hi->next;
562 }
563 return NULL;
564}
565
566/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000567static void hash_rebuild(xhash *hash)
568{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000569 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000570 hash_item **newitems, *hi, *thi;
571
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000572 if (hash->nprime == ARRAY_SIZE(PRIMES))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000573 return;
574
575 newsize = PRIMES[hash->nprime++];
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000576 newitems = xzalloc(newsize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000577
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000578 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000579 hi = hash->items[i];
580 while (hi) {
581 thi = hi;
582 hi = thi->next;
583 idx = hashidx(thi->name) % newsize;
584 thi->next = newitems[idx];
585 newitems[idx] = thi;
586 }
587 }
588
589 free(hash->items);
590 hash->csize = newsize;
591 hash->items = newitems;
592}
593
594/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000595static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000596{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000597 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000598 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000599 int l;
600
601 hi = hash_search(hash, name);
Denis Vlasenkob78c7822007-07-18 18:31:11 +0000602 if (!hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000603 if (++hash->nel / hash->csize > 10)
604 hash_rebuild(hash);
605
Rob Landleya3896512006-05-07 20:20:34 +0000606 l = strlen(name) + 1;
Rob Landley9ffd4232006-05-21 18:30:35 +0000607 hi = xzalloc(sizeof(hash_item) + l);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000608 memcpy(hi->name, name, l);
609
610 idx = hashidx(name) % hash->csize;
611 hi->next = hash->items[idx];
612 hash->items[idx] = hi;
613 hash->glen += l;
614 }
615 return &(hi->data);
616}
617
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000618#define findvar(hash, name) ((var*) hash_find((hash), (name)))
619#define newvar(name) ((var*) hash_find(vhash, (name)))
620#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
621#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000622
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000623static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000624{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000625 hash_item *hi, **phi;
626
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000627 phi = &(hash->items[hashidx(name) % hash->csize]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000628 while (*phi) {
629 hi = *phi;
630 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000631 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000632 hash->nel--;
633 *phi = hi->next;
634 free(hi);
635 break;
636 }
637 phi = &(hi->next);
638 }
639}
640
641/* ------ some useful functions ------ */
642
Mike Frysinger10a11e22005-09-27 02:23:02 +0000643static void skip_spaces(char **s)
644{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000645 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000646
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000647 while (1) {
648 if (*p == '\\' && p[1] == '\n') {
649 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000650 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000651 } else if (*p != ' ' && *p != '\t') {
652 break;
653 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000654 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000655 }
656 *s = p;
657}
658
Mike Frysinger10a11e22005-09-27 02:23:02 +0000659static char *nextword(char **s)
660{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000661 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000662
Denis Vlasenkof782f522007-01-01 23:51:30 +0000663 while (*(*s)++) /* */;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000664
665 return p;
666}
667
Mike Frysinger10a11e22005-09-27 02:23:02 +0000668static char nextchar(char **s)
669{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000670 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000671
672 c = *((*s)++);
673 pps = *s;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000674 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000675 if (c == '\\' && *s == pps) c = *((*s)++);
676 return c;
677}
678
Denis Vlasenko3ad5d0c2007-06-12 20:54:54 +0000679static int ALWAYS_INLINE isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000680{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000681 return (isalnum(c) || c == '_');
682}
683
Mike Frysinger10a11e22005-09-27 02:23:02 +0000684static FILE *afopen(const char *path, const char *mode)
685{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000686 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000687}
688
689/* -------- working with variables (set/get/copy/etc) -------- */
690
Mike Frysinger10a11e22005-09-27 02:23:02 +0000691static xhash *iamarray(var *v)
692{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000693 var *a = v;
694
695 while (a->type & VF_CHILD)
696 a = a->x.parent;
697
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000698 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000699 a->type |= VF_ARRAY;
700 a->x.array = hash_init();
701 }
702 return a->x.array;
703}
704
Mike Frysinger10a11e22005-09-27 02:23:02 +0000705static void clear_array(xhash *array)
706{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000707 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000708 hash_item *hi, *thi;
709
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000710 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000711 hi = array->items[i];
712 while (hi) {
713 thi = hi;
714 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000715 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000716 free(thi);
717 }
718 array->items[i] = NULL;
719 }
720 array->glen = array->nel = 0;
721}
722
723/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000724static var *clrvar(var *v)
725{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000726 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000727 free(v->string);
728
729 v->type &= VF_DONTTOUCH;
730 v->type |= VF_DIRTY;
731 v->string = NULL;
732 return v;
733}
734
735/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000736static var *setvar_p(var *v, char *value)
737{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000738 clrvar(v);
739 v->string = value;
740 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000741 return v;
742}
743
744/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000745static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000746{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000747 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000748}
749
750/* same as setvar_s but set USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000751static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000752{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000753 setvar_s(v, value);
754 v->type |= VF_USER;
755 return v;
756}
757
758/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000759static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000760{
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000761 char sidx[sizeof(int)*3 + 1];
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000762 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000763
764 sprintf(sidx, "%d", idx);
765 v = findvar(iamarray(a), sidx);
766 setvar_u(v, s);
767}
768
769/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000770static var *setvar_i(var *v, double value)
771{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000772 clrvar(v);
773 v->type |= VF_NUMBER;
774 v->number = value;
775 handle_special(v);
776 return v;
777}
778
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000779static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000780{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000781 /* if v is numeric and has no cached string, convert it to string */
782 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000783 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
784 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000785 v->type |= VF_CACHED;
786 }
787 return (v->string == NULL) ? "" : v->string;
788}
789
Mike Frysinger10a11e22005-09-27 02:23:02 +0000790static double getvar_i(var *v)
791{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000792 char *s;
793
794 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
795 v->number = 0;
796 s = v->string;
797 if (s && *s) {
798 v->number = strtod(s, &s);
799 if (v->type & VF_USER) {
800 skip_spaces(&s);
801 if (*s != '\0')
802 v->type &= ~VF_USER;
803 }
804 } else {
805 v->type &= ~VF_USER;
806 }
807 v->type |= VF_CACHED;
808 }
809 return v->number;
810}
811
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000812static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000813{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000814 if (dest != src) {
815 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000816 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000817 dest->number = src->number;
818 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000819 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000820 }
821 handle_special(dest);
822 return dest;
823}
824
Mike Frysinger10a11e22005-09-27 02:23:02 +0000825static var *incvar(var *v)
826{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000827 return setvar_i(v, getvar_i(v) + 1.);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000828}
829
830/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000831static int is_numeric(var *v)
832{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000833 getvar_i(v);
834 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
835}
836
837/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000838static int istrue(var *v)
839{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000840 if (is_numeric(v))
841 return (v->number == 0) ? 0 : 1;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000842 return (v->string && *(v->string)) ? 1 : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000843}
844
Eric Andersenaff114c2004-04-14 17:51:38 +0000845/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000846static var *nvalloc(int n)
847{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000848 nvblock *pb = NULL;
849 var *v, *r;
850 int size;
851
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000852 while (g_cb) {
853 pb = g_cb;
854 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break;
855 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000856 }
857
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000858 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000859 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000860 g_cb = xmalloc(sizeof(nvblock) + size * sizeof(var));
861 g_cb->size = size;
862 g_cb->pos = g_cb->nv;
863 g_cb->prev = pb;
864 g_cb->next = NULL;
865 if (pb) pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000866 }
867
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000868 v = r = g_cb->pos;
869 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000870
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000871 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000872 v->type = 0;
873 v->string = NULL;
874 v++;
875 }
876
877 return r;
878}
879
Mike Frysinger10a11e22005-09-27 02:23:02 +0000880static void nvfree(var *v)
881{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000882 var *p;
883
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000884 if (v < g_cb->nv || v >= g_cb->pos)
885 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000886
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000887 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000888 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000889 clear_array(iamarray(p));
890 free(p->x.array->items);
891 free(p->x.array);
892 }
893 if (p->type & VF_WALK)
894 free(p->x.walker);
895
896 clrvar(p);
897 }
898
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000899 g_cb->pos = v;
900 while (g_cb->prev && g_cb->pos == g_cb->nv) {
901 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000902 }
903}
904
905/* ------- awk program text parsing ------- */
906
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000907/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000908 * If token isn't expected, give away. Return token class
909 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000910static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000911{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000912#define concat_inserted (G.next_token__concat_inserted)
913#define save_tclass (G.next_token__save_tclass)
914#define save_info (G.next_token__save_info)
915/* Initialized to TC_OPTERM: */
916#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000917
Denis Vlasenkof782f522007-01-01 23:51:30 +0000918 char *p, *pp, *s;
919 const char *tl;
920 uint32_t tc;
921 const uint32_t *ti;
922 int l;
923
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000924 if (t_rollback) {
925 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000926
927 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000928 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000929 t_tclass = save_tclass;
930 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000931
932 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000933 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000934 readnext:
Glenn L McGrath545106f2002-11-11 06:21:00 +0000935 skip_spaces(&p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000936 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000937 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000938 while (*p != '\n' && *p != '\0')
939 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000940
941 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000942 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000943
944 if (*p == '\0') {
945 tc = TC_EOF;
946
947 } else if (*p == '\"') {
948 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000949 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000950 while (*p != '\"') {
951 if (*p == '\0' || *p == '\n')
952 syntax_error(EMSG_UNEXP_EOS);
953 *(s++) = nextchar(&p);
954 }
955 p++;
956 *s = '\0';
957 tc = TC_STRING;
958
959 } else if ((expected & TC_REGEXP) && *p == '/') {
960 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000961 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000962 while (*p != '/') {
963 if (*p == '\0' || *p == '\n')
964 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +0000965 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000966 if (*s++ == '\\') {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000967 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000968 *(s-1) = bb_process_escape_sequence((const char **)&p);
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000969 if (*pp == '\\')
970 *s++ = '\\';
971 if (p == pp)
972 *s++ = *p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000973 }
974 }
975 p++;
976 *s = '\0';
977 tc = TC_REGEXP;
978
979 } else if (*p == '.' || isdigit(*p)) {
980 /* it's a number */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000981 t_double = strtod(p, &p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000982 if (*p == '.')
983 syntax_error(EMSG_UNEXP_TOKEN);
984 tc = TC_NUMBER;
985
986 } else {
987 /* search for something known */
988 tl = tokenlist;
989 tc = 0x00000001;
990 ti = tokeninfo;
991 while (*tl) {
992 l = *(tl++);
993 if (l == NTCC) {
994 tc <<= 1;
995 continue;
996 }
997 /* if token class is expected, token
998 * matches and it's not a longer word,
999 * then this is what we are looking for
1000 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001001 if ((tc & (expected | TC_WORD | TC_NEWLINE))
1002 && *tl == *p && strncmp(p, tl, l) == 0
1003 && !((tc & TC_WORD) && isalnum_(p[l]))
1004 ) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001005 t_info = *ti;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001006 p += l;
1007 break;
1008 }
1009 ti++;
1010 tl += l;
1011 }
1012
Denis Vlasenkof782f522007-01-01 23:51:30 +00001013 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001014 /* it's a name (var/array/function),
1015 * otherwise it's something wrong
1016 */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001017 if (!isalnum_(*p))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001018 syntax_error(EMSG_UNEXP_TOKEN);
1019
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001020 t_string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001021 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001022 *(p-1) = *p;
1023 }
1024 *(p-1) = '\0';
1025 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +00001026 /* also consume whitespace between functionname and bracket */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001027 if (!(expected & TC_VARIABLE))
1028 skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001029 if (*p == '(') {
1030 tc = TC_FUNCTION;
1031 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001032 if (*p == '[') {
1033 p++;
1034 tc = TC_ARRAY;
1035 }
1036 }
1037 }
1038 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001039 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001040
1041 /* skipping newlines in some cases */
1042 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1043 goto readnext;
1044
1045 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001046 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001047 concat_inserted = TRUE;
1048 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001049 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001050 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001051 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001052 }
1053
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001054 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001055 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001056 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001057
1058 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001059 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001060 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001061 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001062
1063 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001064#undef concat_inserted
1065#undef save_tclass
1066#undef save_info
1067#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001068}
1069
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001070static void rollback_token(void)
1071{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001072 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001073}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001074
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001075static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001076{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001077 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001078
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001079 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001080 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001081 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001082 return n;
1083}
1084
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001085static node *mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001086{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001087 n->info = OC_REGEXP;
1088 n->l.re = re;
1089 n->r.ire = re + 1;
1090 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001091 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001092
1093 return n;
1094}
1095
Mike Frysinger10a11e22005-09-27 02:23:02 +00001096static node *condition(void)
1097{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001098 next_token(TC_SEQSTART);
1099 return parse_expr(TC_SEQTERM);
1100}
1101
1102/* parse expression terminated by given argument, return ptr
1103 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001104static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001105{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001106 node sn;
1107 node *cn = &sn;
1108 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001109 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001110 var *v;
1111
1112 sn.info = PRIMASK;
1113 sn.r.n = glptr = NULL;
1114 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1115
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001116 while (!((tc = next_token(xtc)) & iexp)) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001117 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001118 /* input redirection (<) attached to glptr node */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001119 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001120 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001121 xtc = TC_OPERAND | TC_UOPPRE;
1122 glptr = NULL;
1123
1124 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1125 /* for binary and postfix-unary operators, jump back over
1126 * previous operators with higher priority */
1127 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001128 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1129 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) )
Glenn L McGrath545106f2002-11-11 06:21:00 +00001130 vn = vn->a.n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001131 if ((t_info & OPCLSMASK) == OC_TERNARY)
1132 t_info += P(6);
1133 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001134 cn->a.n = vn->a.n;
1135 if (tc & TC_BINOP) {
1136 cn->l.n = vn;
1137 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001138 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001139 /* it's a pipe */
1140 next_token(TC_GETLINE);
1141 /* give maximum priority to this pipe */
1142 cn->info &= ~PRIMASK;
1143 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1144 }
1145 } else {
1146 cn->r.n = vn;
1147 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1148 }
1149 vn->a.n = cn;
1150
1151 } else {
1152 /* for operands and prefix-unary operators, attach them
1153 * to last node */
1154 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001155 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001156 cn->a.n = vn;
1157 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1158 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001159 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001160 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001161 * only simple tclasses should be used! */
1162 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001163 case TC_VARIABLE:
1164 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001165 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001166 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001167 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001168 cn->info = OC_FNARG;
1169 cn->l.i = v->x.aidx;
1170 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001171 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001172 }
1173 if (tc & TC_ARRAY) {
1174 cn->info |= xS;
1175 cn->r.n = parse_expr(TC_ARRTERM);
1176 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001177 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001178
Denis Vlasenkof782f522007-01-01 23:51:30 +00001179 case TC_NUMBER:
1180 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001181 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001182 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001183 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001184 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001185 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001186 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001187 break;
1188
Denis Vlasenkof782f522007-01-01 23:51:30 +00001189 case TC_REGEXP:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001190 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001191 break;
1192
Denis Vlasenkof782f522007-01-01 23:51:30 +00001193 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001194 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001195 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001196 cn->l.n = condition();
1197 break;
1198
Denis Vlasenkof782f522007-01-01 23:51:30 +00001199 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001200 cn = vn->r.n = parse_expr(TC_SEQTERM);
1201 cn->a.n = vn;
1202 break;
1203
Denis Vlasenkof782f522007-01-01 23:51:30 +00001204 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001205 glptr = cn;
1206 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1207 break;
1208
Denis Vlasenkof782f522007-01-01 23:51:30 +00001209 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001210 cn->l.n = condition();
1211 break;
1212 }
1213 }
1214 }
1215 }
1216 return sn.r.n;
1217}
1218
1219/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001220static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001221{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001222 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001223
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001224 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001225 seq->first = seq->last = new_node(0);
1226
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001227 if (seq->programname != g_progname) {
1228 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001229 n = chain_node(OC_NEWSOURCE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001230 n->l.s = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001231 }
1232
1233 n = seq->last;
1234 n->info = info;
1235 seq->last = n->a.n = new_node(OC_DONE);
1236
1237 return n;
1238}
1239
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001240static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001241{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001242 node *n;
1243
1244 n = chain_node(info);
1245 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001246 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001247 rollback_token();
1248}
1249
Mike Frysinger10a11e22005-09-27 02:23:02 +00001250static node *chain_loop(node *nn)
1251{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001252 node *n, *n2, *save_brk, *save_cont;
1253
1254 save_brk = break_ptr;
1255 save_cont = continue_ptr;
1256
1257 n = chain_node(OC_BR | Vx);
1258 continue_ptr = new_node(OC_EXEC);
1259 break_ptr = new_node(OC_EXEC);
1260 chain_group();
1261 n2 = chain_node(OC_EXEC | Vx);
1262 n2->l.n = nn;
1263 n2->a.n = n;
1264 continue_ptr->a.n = n2;
1265 break_ptr->a.n = n->r.n = seq->last;
1266
1267 continue_ptr = save_cont;
1268 break_ptr = save_brk;
1269
1270 return n;
1271}
1272
1273/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001274static void chain_group(void)
1275{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001276 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001277 node *n, *n2, *n3;
1278
1279 do {
1280 c = next_token(TC_GRPSEQ);
1281 } while (c & TC_NEWLINE);
1282
1283 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001284 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001285 if (t_tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001286 rollback_token();
1287 chain_group();
1288 }
1289 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1290 rollback_token();
1291 chain_expr(OC_EXEC | Vx);
1292 } else { /* TC_STATEMNT */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001293 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001294 case ST_IF:
1295 n = chain_node(OC_BR | Vx);
1296 n->l.n = condition();
1297 chain_group();
1298 n2 = chain_node(OC_EXEC);
1299 n->r.n = seq->last;
1300 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001301 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001302 n2->a.n = seq->last;
1303 } else {
1304 rollback_token();
1305 }
1306 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001307
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001308 case ST_WHILE:
1309 n2 = condition();
1310 n = chain_loop(NULL);
1311 n->l.n = n2;
1312 break;
1313
1314 case ST_DO:
1315 n2 = chain_node(OC_EXEC);
1316 n = chain_loop(NULL);
1317 n2->a.n = n->a.n;
1318 next_token(TC_WHILE);
1319 n->l.n = condition();
1320 break;
1321
1322 case ST_FOR:
1323 next_token(TC_SEQSTART);
1324 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001325 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001326 if ((n2->info & OPCLSMASK) != OC_IN)
1327 syntax_error(EMSG_UNEXP_TOKEN);
1328 n = chain_node(OC_WALKINIT | VV);
1329 n->l.n = n2->l.n;
1330 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001331 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001332 n->info = OC_WALKNEXT | Vx;
1333 n->l.n = n2->l.n;
1334 } else { /* for (;;) */
1335 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001336 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001337 n2 = parse_expr(TC_SEMICOL);
1338 n3 = parse_expr(TC_SEQTERM);
1339 n = chain_loop(n3);
1340 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001341 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001342 n->info = OC_EXEC;
1343 }
1344 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001345
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001346 case OC_PRINT:
1347 case OC_PRINTF:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001348 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001349 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001350 if (t_tclass & TC_OUTRDR) {
1351 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001352 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1353 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001354 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001355 rollback_token();
1356 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001357
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001358 case OC_BREAK:
1359 n = chain_node(OC_EXEC);
1360 n->a.n = break_ptr;
1361 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001362
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001363 case OC_CONTINUE:
1364 n = chain_node(OC_EXEC);
1365 n->a.n = continue_ptr;
1366 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001367
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001368 /* delete, next, nextfile, return, exit */
1369 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001370 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001371 }
1372 }
1373}
1374
Mike Frysinger10a11e22005-09-27 02:23:02 +00001375static void parse_program(char *p)
1376{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001377 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001378 node *cn;
1379 func *f;
1380 var *v;
1381
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001382 g_pos = p;
1383 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001384 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001385 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001386
1387 if (tclass & TC_OPTERM)
1388 continue;
1389
1390 seq = &mainseq;
1391 if (tclass & TC_BEGIN) {
1392 seq = &beginseq;
1393 chain_group();
1394
1395 } else if (tclass & TC_END) {
1396 seq = &endseq;
1397 chain_group();
1398
1399 } else if (tclass & TC_FUNCDECL) {
1400 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001401 g_pos++;
1402 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001403 f->body.first = NULL;
1404 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001405 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001406 v = findvar(ahash, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001407 v->x.aidx = (f->nargs)++;
1408
1409 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1410 break;
1411 }
1412 seq = &(f->body);
1413 chain_group();
1414 clear_array(ahash);
1415
1416 } else if (tclass & TC_OPSEQ) {
1417 rollback_token();
1418 cn = chain_node(OC_TEST);
1419 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001420 if (t_tclass & TC_GRPSTART) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001421 rollback_token();
1422 chain_group();
1423 } else {
1424 chain_node(OC_PRINT);
1425 }
1426 cn->r.n = mainseq.last;
1427
1428 } else /* if (tclass & TC_GRPSTART) */ {
1429 rollback_token();
1430 chain_group();
1431 }
1432 }
1433}
1434
1435
1436/* -------- program execution part -------- */
1437
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001438static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001439{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001440 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001441 node *n;
1442
1443 re = &spl->re[0];
1444 ire = &spl->re[1];
1445 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001446 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001447 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001448 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001449 }
Rob Landleya3896512006-05-07 20:20:34 +00001450 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001451 mk_re_node(s, n, re);
1452 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001453 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001454 }
1455
1456 return n;
1457}
1458
1459/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001460 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001461 * be later regfree'd manually
1462 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001463static regex_t *as_regex(node *op, regex_t *preg)
1464{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001465 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001466 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001467
1468 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1469 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001470 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001471 v = nvalloc(1);
1472 s = getvar_s(evaluate(op, v));
1473 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1474 nvfree(v);
1475 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001476}
1477
1478/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001479static void qrealloc(char **b, int n, int *size)
1480{
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001481 if (!*b || n >= *size)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001482 *b = xrealloc(*b, *size = n + (n>>1) + 80);
1483}
1484
1485/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001486static void fsrealloc(int size)
1487{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001488 int i;
1489
1490 if (size >= maxfields) {
1491 i = maxfields;
1492 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001493 Fields = xrealloc(Fields, maxfields * sizeof(var));
1494 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001495 Fields[i].type = VF_SPECIAL;
1496 Fields[i].string = NULL;
1497 }
1498 }
1499
1500 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001501 for (i = size; i < nfields; i++) {
1502 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001503 }
1504 }
1505 nfields = size;
1506}
1507
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001508static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001509{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001510 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001511 char c[4];
1512 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001513 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001514
1515 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001516 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1517 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001518
1519 c[0] = c[1] = (char)spl->info;
1520 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001521 if (*getvar_s(intvar[RS]) == '\0')
1522 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001523
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001524 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1525 if (!*s)
1526 return n; /* "": zero fields */
1527 n++; /* at least one field will be there */
1528 do {
1529 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001530 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1531 && pmatch[0].rm_so <= l
1532 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001533 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001534 if (pmatch[0].rm_eo == 0) {
1535 l++;
1536 pmatch[0].rm_eo++;
1537 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001538 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001539 } else {
1540 pmatch[0].rm_eo = l;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001541 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001542 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001543 memcpy(s1, s, l);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001544 s1[l] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001545 nextword(&s1);
1546 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001547 } while (*s);
1548 return n;
1549 }
1550 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001551 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001552 *s1++ = *s++;
1553 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001554 n++;
1555 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001556 return n;
1557 }
1558 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001559 if (icase) {
1560 c[0] = toupper(c[0]);
1561 c[1] = tolower(c[1]);
1562 }
1563 if (*s1) n++;
1564 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001565 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001566 n++;
1567 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001568 return n;
1569 }
1570 /* space split */
1571 while (*s) {
1572 s = skip_whitespace(s);
1573 if (!*s) break;
1574 n++;
1575 while (*s && !isspace(*s))
1576 *s1++ = *s++;
1577 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001578 }
1579 return n;
1580}
1581
Mike Frysinger10a11e22005-09-27 02:23:02 +00001582static void split_f0(void)
1583{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001584/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001585#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001586
Glenn L McGrath545106f2002-11-11 06:21:00 +00001587 int i, n;
1588 char *s;
1589
1590 if (is_f0_split)
1591 return;
1592
1593 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001594 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001595 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001596 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001597 fsrealloc(n);
1598 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001599 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001600 Fields[i].string = nextword(&s);
1601 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1602 }
1603
1604 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001605 clrvar(intvar[NF]);
1606 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1607 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001608#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001609}
1610
1611/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001612static void handle_special(var *v)
1613{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001614 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001615 char *b;
1616 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001617 int sl, l, len, i, bsize;
1618
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001619 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001620 return;
1621
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001622 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001623 n = (int)getvar_i(v);
1624 fsrealloc(n);
1625
1626 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001627 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001628 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001629 b = NULL;
1630 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001631 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001632 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001633 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001634 if (b) {
1635 memcpy(b+len, sep, sl);
1636 len += sl;
1637 }
1638 qrealloc(&b, len+l+sl, &bsize);
1639 memcpy(b+len, s, l);
1640 len += l;
1641 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001642 if (b)
1643 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001644 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001645 is_f0_split = TRUE;
1646
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001647 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001648 is_f0_split = FALSE;
1649
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001650 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001651 mk_splitter(getvar_s(v), &fsplitter);
1652
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001653 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001654 mk_splitter(getvar_s(v), &rsplitter);
1655
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001656 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001657 icase = istrue(v);
1658
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001659 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001660 n = getvar_i(intvar[NF]);
1661 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001662 /* right here v is invalid. Just to note... */
1663 }
1664}
1665
1666/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001667static node *nextarg(node **pn)
1668{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001669 node *n;
1670
1671 n = *pn;
1672 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1673 *pn = n->r.n;
1674 n = n->l.n;
1675 } else {
1676 *pn = NULL;
1677 }
1678 return n;
1679}
1680
Mike Frysinger10a11e22005-09-27 02:23:02 +00001681static void hashwalk_init(var *v, xhash *array)
1682{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001683 char **w;
1684 hash_item *hi;
1685 int i;
1686
1687 if (v->type & VF_WALK)
1688 free(v->x.walker);
1689
1690 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001691 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001692 w[0] = w[1] = (char *)(w + 2);
1693 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001694 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001695 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001696 strcpy(*w, hi->name);
1697 nextword(w);
1698 hi = hi->next;
1699 }
1700 }
1701}
1702
Mike Frysinger10a11e22005-09-27 02:23:02 +00001703static int hashwalk_next(var *v)
1704{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001705 char **w;
1706
1707 w = v->x.walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001708 if (w[1] == w[0])
Glenn L McGrath545106f2002-11-11 06:21:00 +00001709 return FALSE;
1710
1711 setvar_s(v, nextword(w+1));
1712 return TRUE;
1713}
1714
1715/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001716static int ptest(node *pattern)
1717{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001718 /* ptest__v is "static": to save stack space? */
1719 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001720}
1721
1722/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001723static int awk_getline(rstream *rsm, var *v)
1724{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001725 char *b;
1726 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001727 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001728 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001729 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001730
1731 /* we're using our own buffer since we need access to accumulating
1732 * characters
1733 */
1734 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001735 m = rsm->buffer;
1736 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001737 p = rsm->pos;
1738 size = rsm->size;
1739 c = (char) rsplitter.n.info;
1740 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001741
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001742 if (!m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001743 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001744 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001745 so = eo = p;
1746 r = 1;
1747 if (p > 0) {
1748 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1749 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001750 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001751 so = pmatch[0].rm_so;
1752 eo = pmatch[0].rm_eo;
1753 if (b[eo] != '\0')
1754 break;
1755 }
1756 } else if (c != '\0') {
1757 s = strchr(b+pp, c);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001758 if (!s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001759 if (s) {
1760 so = eo = s-b;
1761 eo++;
1762 break;
1763 }
1764 } else {
1765 while (b[rp] == '\n')
1766 rp++;
1767 s = strstr(b+rp, "\n\n");
1768 if (s) {
1769 so = eo = s-b;
1770 while (b[eo] == '\n') eo++;
1771 if (b[eo] != '\0')
1772 break;
1773 }
1774 }
1775 }
1776
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001777 if (a > 0) {
1778 memmove(m, (const void *)(m+a), p+1);
1779 b = m;
1780 a = 0;
1781 }
1782
1783 qrealloc(&m, a+p+128, &size);
1784 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001785 pp = p;
1786 p += safe_read(fd, b+p, size-p-1);
1787 if (p < pp) {
1788 p = 0;
1789 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001790 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001791 }
1792 b[p] = '\0';
1793
1794 } while (p > pp);
1795
1796 if (p == 0) {
1797 r--;
1798 } else {
1799 c = b[so]; b[so] = '\0';
1800 setvar_s(v, b+rp);
1801 v->type |= VF_USER;
1802 b[so] = c;
1803 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001804 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001805 b[eo] = c;
1806 }
1807
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001808 rsm->buffer = m;
1809 rsm->adv = a + eo;
1810 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001811 rsm->size = size;
1812
1813 return r;
1814}
1815
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001816static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001817{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001818 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001819 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001820 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001821
1822 if (int_as_int && n == (int)n) {
1823 r = snprintf(b, size, "%d", (int)n);
1824 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001825 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001826 if (strchr("diouxX", c)) {
1827 r = snprintf(b, size, format, (int)n);
1828 } else if (strchr("eEfgG", c)) {
1829 r = snprintf(b, size, format, n);
1830 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001831 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001832 }
1833 }
1834 return r;
1835}
1836
1837
1838/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001839static char *awk_printf(node *n)
1840{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001841 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001842 char *fmt, *s, *f;
1843 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001844 int i, j, incr, bsize;
1845 char c, c1;
1846 var *v, *arg;
1847
1848 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001849 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001850
1851 i = 0;
1852 while (*f) {
1853 s = f;
1854 while (*f && (*f != '%' || *(++f) == '%'))
1855 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001856 while (*f && !isalpha(*f)) {
1857 if (*f == '*')
1858 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001859 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001860 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001861
1862 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001863 qrealloc(&b, incr + i, &bsize);
1864 c = *f;
1865 if (c != '\0') f++;
1866 c1 = *f;
1867 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001868 arg = evaluate(nextarg(&n), v);
1869
1870 j = i;
1871 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001872 i += sprintf(b+i, s, is_numeric(arg) ?
1873 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001874 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001875 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001876 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001877 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001878 } else {
1879 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1880 }
1881 *f = c1;
1882
1883 /* if there was an error while sprintf, return value is negative */
1884 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001885 }
1886
Denis Vlasenkof782f522007-01-01 23:51:30 +00001887 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001888 free(fmt);
1889 nvfree(v);
1890 b[i] = '\0';
1891 return b;
1892}
1893
1894/* common substitution routine
1895 * replace (nm) substring of (src) that match (n) with (repl), store
1896 * result into (dest), return number of substitutions. If nm=0, replace
1897 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1898 * subexpression matching (\1-\9)
1899 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001900static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001901{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001902 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001903 const char *s;
1904 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001905 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1906 regmatch_t pmatch[10];
1907 regex_t sreg, *re;
1908
1909 re = as_regex(rn, &sreg);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001910 if (!src) src = intvar[F0];
1911 if (!dest) dest = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001912
1913 i = di = 0;
1914 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001915 rl = strlen(repl);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001916 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001917 so = pmatch[0].rm_so;
1918 eo = pmatch[0].rm_eo;
1919
1920 qrealloc(&ds, di + eo + rl, &dssize);
1921 memcpy(ds + di, sp, eo);
1922 di += eo;
1923 if (++i >= nm) {
1924 /* replace */
1925 di -= (eo - so);
1926 nbs = 0;
1927 for (s = repl; *s; s++) {
1928 ds[di++] = c = *s;
1929 if (c == '\\') {
1930 nbs++;
1931 continue;
1932 }
1933 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1934 di -= ((nbs + 3) >> 1);
1935 j = 0;
1936 if (c != '&') {
1937 j = c - '0';
1938 nbs++;
1939 }
1940 if (nbs % 2) {
1941 ds[di++] = c;
1942 } else {
1943 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1944 qrealloc(&ds, di + rl + n, &dssize);
1945 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1946 di += n;
1947 }
1948 }
1949 nbs = 0;
1950 }
1951 }
1952
1953 sp += eo;
1954 if (i == nm) break;
1955 if (eo == so) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001956 ds[di] = *sp++;
1957 if (!ds[di++]) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001958 }
1959 }
1960
1961 qrealloc(&ds, di + strlen(sp), &dssize);
1962 strcpy(ds + di, sp);
1963 setvar_p(dest, ds);
1964 if (re == &sreg) regfree(re);
1965 return i;
1966}
1967
Mike Frysinger10a11e22005-09-27 02:23:02 +00001968static var *exec_builtin(node *op, var *res)
1969{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001970#define tspl (G.exec_builtin__tspl)
1971
Glenn L McGrath545106f2002-11-11 06:21:00 +00001972 int (*to_xxx)(int);
1973 var *tv;
1974 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001975 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001976 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001977 regmatch_t pmatch[2];
1978 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001979 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001980 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001981 int nargs;
1982 time_t tt;
1983 char *s, *s1;
1984 int i, l, ll, n;
1985
1986 tv = nvalloc(4);
1987 isr = info = op->info;
1988 op = op->l.n;
1989
1990 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001991 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001992 an[i] = nextarg(&op);
1993 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
1994 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
1995 isr >>= 1;
1996 }
1997
1998 nargs = i;
1999 if (nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002000 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002001
2002 switch (info & OPNMASK) {
2003
Denis Vlasenkof782f522007-01-01 23:51:30 +00002004 case B_a2:
2005#if ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +00002006 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
2007#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002008 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002009#endif
2010 break;
2011
Denis Vlasenkof782f522007-01-01 23:51:30 +00002012 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002013 if (nargs > 2) {
2014 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2015 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2016 } else {
2017 spl = &fsplitter.n;
2018 }
2019
2020 n = awk_split(as[0], spl, &s);
2021 s1 = s;
2022 clear_array(iamarray(av[1]));
2023 for (i=1; i<=n; i++)
2024 setari_u(av[1], i, nextword(&s1));
2025 free(s);
2026 setvar_i(res, n);
2027 break;
2028
Denis Vlasenkof782f522007-01-01 23:51:30 +00002029 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00002030 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002031 i = getvar_i(av[1]) - 1;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002032 if (i > l) i = l;
2033 if (i < 0) i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002034 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002035 if (n < 0) n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002036 s = xmalloc(n+1);
2037 strncpy(s, as[0]+i, n);
2038 s[n] = '\0';
2039 setvar_p(res, s);
2040 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002041
Denis Vlasenkof782f522007-01-01 23:51:30 +00002042 case B_an:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002043 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
2044 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002045
Denis Vlasenkof782f522007-01-01 23:51:30 +00002046 case B_co:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002047 setvar_i(res, ~(long)getvar_i(av[0]));
2048 break;
2049
Denis Vlasenkof782f522007-01-01 23:51:30 +00002050 case B_ls:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002051 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
2052 break;
2053
Denis Vlasenkof782f522007-01-01 23:51:30 +00002054 case B_or:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002055 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
2056 break;
2057
Denis Vlasenkof782f522007-01-01 23:51:30 +00002058 case B_rs:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002059 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
2060 break;
2061
Denis Vlasenkof782f522007-01-01 23:51:30 +00002062 case B_xo:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002063 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
2064 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002065
Denis Vlasenkof782f522007-01-01 23:51:30 +00002066 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002067 to_xxx = tolower;
2068 goto lo_cont;
2069
Denis Vlasenkof782f522007-01-01 23:51:30 +00002070 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002071 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002072 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00002073 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002074 while (*s1) {
2075 *s1 = (*to_xxx)(*s1);
2076 s1++;
2077 }
2078 setvar_p(res, s);
2079 break;
2080
Denis Vlasenkof782f522007-01-01 23:51:30 +00002081 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002082 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002083 ll = strlen(as[1]);
2084 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002085 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002086 if (!icase) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002087 s = strstr(as[0], as[1]);
2088 if (s) n = (s - as[0]) + 1;
2089 } else {
2090 /* this piece of code is terribly slow and
2091 * really should be rewritten
2092 */
2093 for (i=0; i<=l; i++) {
2094 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2095 n = i+1;
2096 break;
2097 }
2098 }
2099 }
2100 }
2101 setvar_i(res, n);
2102 break;
2103
Denis Vlasenkof782f522007-01-01 23:51:30 +00002104 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002105 if (nargs > 1)
2106 tt = getvar_i(av[1]);
2107 else
2108 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002109 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002110 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002111 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2112 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002113 g_buf[i] = '\0';
2114 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002115 break;
2116
Denis Vlasenkof782f522007-01-01 23:51:30 +00002117 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002118 re = as_regex(an[1], &sreg);
2119 n = regexec(re, as[0], 1, pmatch, 0);
2120 if (n == 0) {
2121 pmatch[0].rm_so++;
2122 pmatch[0].rm_eo++;
2123 } else {
2124 pmatch[0].rm_so = 0;
2125 pmatch[0].rm_eo = -1;
2126 }
2127 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2128 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2129 setvar_i(res, pmatch[0].rm_so);
2130 if (re == &sreg) regfree(re);
2131 break;
2132
Denis Vlasenkof782f522007-01-01 23:51:30 +00002133 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002134 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2135 break;
2136
Denis Vlasenkof782f522007-01-01 23:51:30 +00002137 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002138 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2139 break;
2140
Denis Vlasenkof782f522007-01-01 23:51:30 +00002141 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002142 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2143 break;
2144 }
2145
2146 nvfree(tv);
2147 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002148#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002149}
2150
2151/*
2152 * Evaluate node - the heart of the program. Supplied with subtree
2153 * and place where to store result. returns ptr to result.
2154 */
2155#define XC(n) ((n) >> 8)
2156
Mike Frysinger10a11e22005-09-27 02:23:02 +00002157static var *evaluate(node *op, var *res)
2158{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002159/* This procedure is recursive so we should count every byte */
2160#define fnargs (G.evaluate__fnargs)
2161/* seed is initialized to 1 */
2162#define seed (G.evaluate__seed)
2163#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002164
Glenn L McGrath545106f2002-11-11 06:21:00 +00002165 node *op1;
2166 var *v1;
2167 union {
2168 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002169 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002170 double d;
2171 int i;
2172 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002173 uint32_t opinfo;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002174 int opn;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002175 union {
2176 char *s;
2177 rstream *rsm;
2178 FILE *F;
2179 var *v;
2180 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002181 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002182 } X;
2183
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002184 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002185 return setvar_s(res, NULL);
2186
2187 v1 = nvalloc(2);
2188
2189 while (op) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002190 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002191 opn = (opinfo & OPNMASK);
2192 g_lineno = op->lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002193
Mike Frysingerde2b9382005-09-27 03:18:00 +00002194 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002195 op1 = op->l.n;
2196 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2197 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2198 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2199 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2200 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2201
2202 switch (XC(opinfo & OPCLSMASK)) {
2203
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002204 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002205
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002206 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002207 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002208 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2209 /* it's range pattern */
2210 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2211 op->info |= OF_CHECKED;
2212 if (ptest(op1->r.n))
2213 op->info &= ~OF_CHECKED;
2214
2215 op = op->a.n;
2216 } else {
2217 op = op->r.n;
2218 }
2219 } else {
2220 op = (ptest(op1)) ? op->a.n : op->r.n;
2221 }
2222 break;
2223
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002224 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002225 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002226 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002227
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002228 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002229 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002230 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002231 break;
2232
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002233 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002234 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002235 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002236 break;
2237
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002238 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002239 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002240 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2241 break;
2242
Denis Vlasenkof782f522007-01-01 23:51:30 +00002243 case XC( OC_PRINT ):
2244 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002245 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002246 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002247 X.rsm = newfile(R.s);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002248 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002249 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002250 X.rsm->F = popen(R.s, "w");
2251 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002252 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002253 X.rsm->is_pipe = 1;
2254 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002255 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002256 }
2257 }
2258 X.F = X.rsm->F;
2259 }
2260
2261 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002262 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002263 fputs(getvar_s(intvar[F0]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002264 } else {
2265 while (op1) {
2266 L.v = evaluate(nextarg(&op1), v1);
2267 if (L.v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002268 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002269 getvar_i(L.v), TRUE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002270 fputs(g_buf, X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002271 } else {
2272 fputs(getvar_s(L.v), X.F);
2273 }
2274
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002275 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002276 }
2277 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002278 fputs(getvar_s(intvar[ORS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002279
2280 } else { /* OC_PRINTF */
2281 L.s = awk_printf(op1);
2282 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002283 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002284 }
2285 fflush(X.F);
2286 break;
2287
Denis Vlasenkof782f522007-01-01 23:51:30 +00002288 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002289 X.info = op1->info & OPCLSMASK;
2290 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002291 R.v = op1->l.v;
2292 } else if (X.info == OC_FNARG) {
2293 R.v = &fnargs[op1->l.i];
2294 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002295 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002296 }
2297
Mike Frysingerde2b9382005-09-27 03:18:00 +00002298 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002299 clrvar(L.v);
2300 L.s = getvar_s(evaluate(op1->r.n, v1));
2301 hash_remove(iamarray(R.v), L.s);
2302 } else {
2303 clear_array(iamarray(R.v));
2304 }
2305 break;
2306
Denis Vlasenkof782f522007-01-01 23:51:30 +00002307 case XC( OC_NEWSOURCE ):
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002308 g_progname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002309 break;
2310
Denis Vlasenkof782f522007-01-01 23:51:30 +00002311 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002312 copyvar(res, L.v);
2313 break;
2314
Denis Vlasenkof782f522007-01-01 23:51:30 +00002315 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002316 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002317 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002318 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002319 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002320 clrvar(res);
2321 break;
2322
Denis Vlasenkof782f522007-01-01 23:51:30 +00002323 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002324 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002325
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002326 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002327
Denis Vlasenkof782f522007-01-01 23:51:30 +00002328 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002329 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002330 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002331 split_f0();
2332 goto v_cont;
2333
Denis Vlasenkof782f522007-01-01 23:51:30 +00002334 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002335 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002336 v_cont:
2337 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002338 break;
2339
Denis Vlasenkof782f522007-01-01 23:51:30 +00002340 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002341 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2342 break;
2343
Denis Vlasenkof782f522007-01-01 23:51:30 +00002344 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002345 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002346 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002347 goto re_cont;
2348
Denis Vlasenkof782f522007-01-01 23:51:30 +00002349 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002350 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002351 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002352 X.re = as_regex(op1, &sreg);
2353 R.i = regexec(X.re, L.s, 0, NULL, 0);
2354 if (X.re == &sreg) regfree(X.re);
2355 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2356 break;
2357
Denis Vlasenkof782f522007-01-01 23:51:30 +00002358 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002359 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002360 if (R.v == v1+1 && R.v->string) {
2361 res = setvar_p(L.v, R.v->string);
2362 R.v->string = NULL;
2363 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002364 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002365 }
2366 break;
2367
Denis Vlasenkof782f522007-01-01 23:51:30 +00002368 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002369 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002370 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002371 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2372 break;
2373
Denis Vlasenkof782f522007-01-01 23:51:30 +00002374 case XC( OC_FUNC ):
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002375 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002376 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002377
2378 X.v = R.v = nvalloc(op->r.f->nargs+1);
2379 while (op1) {
2380 L.v = evaluate(nextarg(&op1), v1);
2381 copyvar(R.v, L.v);
2382 R.v->type |= VF_CHILD;
2383 R.v->x.parent = L.v;
2384 if (++R.v - X.v >= op->r.f->nargs)
2385 break;
2386 }
2387
2388 R.v = fnargs;
2389 fnargs = X.v;
2390
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002391 L.s = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002392 res = evaluate(op->r.f->body.first, res);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002393 g_progname = L.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002394
2395 nvfree(fnargs);
2396 fnargs = R.v;
2397 break;
2398
Denis Vlasenkof782f522007-01-01 23:51:30 +00002399 case XC( OC_GETLINE ):
2400 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002401 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002402 X.rsm = newfile(L.s);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002403 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002404 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2405 X.rsm->F = popen(L.s, "r");
2406 X.rsm->is_pipe = TRUE;
2407 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002408 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002409 }
2410 }
2411 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002412 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002413 X.rsm = iF;
2414 }
2415
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002416 if (!X.rsm->F) {
2417 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002418 setvar_i(res, -1);
2419 break;
2420 }
2421
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002422 if (!op->r.n)
2423 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002424
2425 L.i = awk_getline(X.rsm, R.v);
2426 if (L.i > 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002427 if (!op1) {
2428 incvar(intvar[FNR]);
2429 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002430 }
2431 }
2432 setvar_i(res, L.i);
2433 break;
2434
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002435 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002436 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002437 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002438
Denis Vlasenkof782f522007-01-01 23:51:30 +00002439 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002440 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002441 break;
2442
Denis Vlasenkof782f522007-01-01 23:51:30 +00002443 case F_rn:
2444 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002445 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002446#if ENABLE_FEATURE_AWK_MATH
2447 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002448 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002449 break;
2450
Denis Vlasenkof782f522007-01-01 23:51:30 +00002451 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002452 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002453 break;
2454
Denis Vlasenkof782f522007-01-01 23:51:30 +00002455 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002456 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002457 break;
2458
Denis Vlasenkof782f522007-01-01 23:51:30 +00002459 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002460 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002461 break;
2462
Denis Vlasenkof782f522007-01-01 23:51:30 +00002463 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002464 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002465 break;
2466#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002467 case F_co:
2468 case F_ex:
2469 case F_lg:
2470 case F_si:
2471 case F_sq:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002472 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002473 break;
2474#endif
Denis Vlasenkof782f522007-01-01 23:51:30 +00002475 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002476 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002477 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002478 srand(seed);
2479 break;
2480
Denis Vlasenkof782f522007-01-01 23:51:30 +00002481 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002482 R.d = time(NULL);
2483 break;
2484
Denis Vlasenkof782f522007-01-01 23:51:30 +00002485 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002486 if (!op1)
2487 L.s = getvar_s(intvar[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002488 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002489 break;
2490
Denis Vlasenkof782f522007-01-01 23:51:30 +00002491 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002492 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002493 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2494 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002495 break;
2496
Denis Vlasenkof782f522007-01-01 23:51:30 +00002497 case F_ff:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002498 if (!op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002499 fflush(stdout);
2500 else {
2501 if (L.s && *L.s) {
2502 X.rsm = newfile(L.s);
2503 fflush(X.rsm->F);
2504 } else {
2505 fflush(NULL);
2506 }
2507 }
2508 break;
2509
Denis Vlasenkof782f522007-01-01 23:51:30 +00002510 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002511 X.rsm = (rstream *)hash_search(fdhash, L.s);
2512 if (X.rsm) {
2513 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002514 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002515 hash_remove(fdhash, L.s);
2516 }
2517 if (R.i != 0)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002518 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002519 R.d = (double)R.i;
2520 break;
2521 }
2522 setvar_i(res, R.d);
2523 break;
2524
Denis Vlasenkof782f522007-01-01 23:51:30 +00002525 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002526 res = exec_builtin(op, res);
2527 break;
2528
Denis Vlasenkof782f522007-01-01 23:51:30 +00002529 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002530 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002531 break;
2532
Denis Vlasenkof782f522007-01-01 23:51:30 +00002533 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002534 X.v = R.v;
2535 L.d = R.d = getvar_i(R.v);
2536 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002537 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002538 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002539 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002540 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002541 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002542 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002543 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002544 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002545 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002546 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002547 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002548 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002549 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002550 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002551 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002552 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002553 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002554 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002555 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002556 setvar_i(X.v, R.d);
2557 }
2558 setvar_i(res, L.d);
2559 break;
2560
Denis Vlasenkof782f522007-01-01 23:51:30 +00002561 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002562 R.i = (int)getvar_i(R.v);
2563 if (R.i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002564 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002565 } else {
2566 split_f0();
2567 if (R.i > nfields)
2568 fsrealloc(R.i);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002569 res = &Fields[R.i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002570 }
2571 break;
2572
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002573 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002574 case XC( OC_CONCAT ):
2575 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002576 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002577 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002578 strcpy(X.s, L.s);
2579 if ((opinfo & OPCLSMASK) == OC_COMMA) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002580 L.s = getvar_s(intvar[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002581 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002582 strcat(X.s, L.s);
2583 }
2584 strcat(X.s, R.s);
2585 setvar_p(res, X.s);
2586 break;
2587
Denis Vlasenkof782f522007-01-01 23:51:30 +00002588 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002589 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2590 break;
2591
Denis Vlasenkof782f522007-01-01 23:51:30 +00002592 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002593 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2594 break;
2595
Denis Vlasenkof782f522007-01-01 23:51:30 +00002596 case XC( OC_BINARY ):
2597 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002598 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002599 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002600 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002601 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002602 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002603 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002604 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002605 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002606 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002607 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002608 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002609 case '/':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002610 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002611 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002612 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002613 case '&':
2614#if ENABLE_FEATURE_AWK_MATH
Mike Frysingerde2b9382005-09-27 03:18:00 +00002615 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002616#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002617 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002618#endif
2619 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002620 case '%':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002621 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002622 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002623 break;
2624 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002625 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002626 break;
2627
Denis Vlasenkof782f522007-01-01 23:51:30 +00002628 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002629 if (is_numeric(L.v) && is_numeric(R.v)) {
2630 L.d = getvar_i(L.v) - getvar_i(R.v);
2631 } else {
2632 L.s = getvar_s(L.v);
2633 R.s = getvar_s(R.v);
2634 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2635 }
2636 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002637 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002638 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002639 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002640 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002641 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002642 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002643 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002644 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002645 break;
2646 }
2647 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2648 break;
2649
Denis Vlasenkof782f522007-01-01 23:51:30 +00002650 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002651 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002652 }
2653 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2654 op = op->a.n;
2655 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2656 break;
2657 if (nextrec)
2658 break;
2659 }
2660 nvfree(v1);
2661 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002662#undef fnargs
2663#undef seed
2664#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002665}
2666
2667
2668/* -------- main & co. -------- */
2669
Mike Frysinger10a11e22005-09-27 02:23:02 +00002670static int awk_exit(int r)
2671{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002672 var tv;
2673 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002674 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002675
Denis Vlasenkof782f522007-01-01 23:51:30 +00002676 zero_out_var(&tv);
2677
2678 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002679 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002680 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002681 evaluate(endseq.first, &tv);
2682 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002683
2684 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002685 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002686 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002687 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002688 if (hi->data.rs.F && hi->data.rs.is_pipe)
2689 pclose(hi->data.rs.F);
2690 hi = hi->next;
2691 }
2692 }
2693
2694 exit(r);
2695}
2696
2697/* if expr looks like "var=value", perform assignment and return 1,
2698 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002699static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002700{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002701 char *exprc, *s, *s0, *s1;
2702
Rob Landleyd921b2e2006-08-03 15:41:12 +00002703 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002704 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2705 free(exprc);
2706 return FALSE;
2707 }
2708
2709 *(s++) = '\0';
2710 s0 = s1 = s;
2711 while (*s)
2712 *(s1++) = nextchar(&s);
2713
2714 *s1 = '\0';
2715 setvar_u(newvar(exprc), s0);
2716 free(exprc);
2717 return TRUE;
2718}
2719
2720/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002721static rstream *next_input_file(void)
2722{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002723#define rsm (G.next_input_file__rsm)
2724#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002725
Glenn L McGrath545106f2002-11-11 06:21:00 +00002726 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002727 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002728
2729 if (rsm.F) fclose(rsm.F);
2730 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002731 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002732
2733 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002734 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002735 if (files_happen)
2736 return NULL;
2737 fname = "-";
2738 F = stdin;
2739 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002740 ind = getvar_s(incvar(intvar[ARGIND]));
2741 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002742 if (fname && *fname && !is_assignment(fname))
2743 F = afopen(fname, "r");
2744 }
2745 } while (!F);
2746
2747 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002748 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002749 rsm.F = F;
2750 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002751#undef rsm
2752#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002753}
2754
Denis Vlasenko06af2162007-02-03 17:28:39 +00002755int awk_main(int argc, char **argv);
Rob Landleydfba7412006-03-06 20:47:33 +00002756int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002757{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002758 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002759 char *opt_F, *opt_W;
2760 llist_t *opt_v = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002761 int i, j, flen;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002762 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002763 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002764 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002765 char *vnames = (char *)vNames; /* cheat */
2766 char *vvalues = (char *)vValues;
2767
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002768 INIT_G();
2769
Denis Vlasenko150f4022007-01-13 21:06:21 +00002770 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002771 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2772 if (ENABLE_LOCALE_SUPPORT)
2773 setlocale(LC_NUMERIC, "C");
2774
Denis Vlasenkof782f522007-01-01 23:51:30 +00002775 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002776
2777 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002778 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002779
2780 vhash = hash_init();
2781 ahash = hash_init();
2782 fdhash = hash_init();
2783 fnhash = hash_init();
2784
2785 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002786 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002787 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00002788 if (*vvalues != '\377')
2789 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002790 else
2791 setvar_i(v, 0);
2792
Denis Vlasenkof782f522007-01-01 23:51:30 +00002793 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002794 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002795 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002796 }
2797 }
2798
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002799 handle_special(intvar[FS]);
2800 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002801
Denis Vlasenkof782f522007-01-01 23:51:30 +00002802 newfile("/dev/stdin")->F = stdin;
2803 newfile("/dev/stdout")->F = stdout;
2804 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002805
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002806 /* Huh, people report that sometimes environ is NULL. Oh well. */
2807 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002808 /* environ is writable, thus we don't strdup it needlessly */
2809 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002810 char *s1 = strchr(s, '=');
2811 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002812 *s1 = '\0';
2813 /* Both findvar and setvar_u take const char*
2814 * as 2nd arg -> environment is not trashed */
2815 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
2816 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00002817 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002818 }
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002819 opt_complementary = "v::";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002820 opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &g_progname, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002821 argv += optind;
2822 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002823 if (opt & 0x1)
2824 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002825 while (opt_v) { /* -v */
2826 if (!is_assignment(llist_pop(&opt_v)))
2827 bb_show_usage();
2828 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002829 if (opt & 0x4) { // -f
Denis Vlasenkof782f522007-01-01 23:51:30 +00002830 char *s = s; /* die, gcc, die */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002831 FILE *from_file = afopen(g_progname, "r");
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002832 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002833 if (fseek(from_file, 0, SEEK_END) == 0) {
2834 flen = ftell(from_file);
2835 s = xmalloc(flen + 4);
2836 fseek(from_file, 0, SEEK_SET);
2837 i = 1 + fread(s + 1, 1, flen, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002838 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002839 for (i = j = 1; j > 0; i += j) {
2840 s = xrealloc(s, i + 4096);
2841 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002842 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002843 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002844 s[i] = '\0';
Denis Vlasenkof782f522007-01-01 23:51:30 +00002845 fclose(from_file);
2846 parse_program(s + 1);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002847 free(s);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002848 } else { // no -f: take program from 1st parameter
2849 if (!argc)
2850 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002851 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00002852 parse_program(*argv++);
2853 argc--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002854 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002855 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002856 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002857
Glenn L McGrath545106f2002-11-11 06:21:00 +00002858 /* fill in ARGV array */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002859 setvar_i(intvar[ARGC], argc + 1);
2860 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002861 i = 0;
2862 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002863 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002864
2865 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002866 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002867 awk_exit(EXIT_SUCCESS);
2868
2869 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002870 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002871
2872 /* passing through input files */
2873 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002874 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002875 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002876
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002877 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002878 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002879 incvar(intvar[NR]);
2880 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002881 evaluate(mainseq.first, &tv);
2882
2883 if (nextfile)
2884 break;
2885 }
2886
Denis Vlasenkof782f522007-01-01 23:51:30 +00002887 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002888 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002889
2890 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002891 }
2892
Glenn L McGrath545106f2002-11-11 06:21:00 +00002893 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002894 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002895}