blob: 752c73e7eaa672bfa498c156c39ac43049aed906 [file] [log] [blame]
Glenn L McGrath545106f2002-11-11 06:21:00 +00001/* vi: set sw=4 ts=4: */
2/*
3 * awk implementation for busybox
4 *
5 * Copyright (C) 2002 by Dmitry Zakharov <dmit@crp.bank.gov.ua>
6 *
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00007 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Glenn L McGrath545106f2002-11-11 06:21:00 +00008 */
9
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000010#include "libbb.h"
Rob Landleyd921b2e2006-08-03 15:41:12 +000011#include "xregex.h"
12#include <math.h>
Denis Vlasenko5b340832007-05-17 23:02:14 +000013extern char **environ;
Glenn L McGrath545106f2002-11-11 06:21:00 +000014
Denis Vlasenko99912ca2007-04-10 15:43:37 +000015/* This is a NOEXEC applet. Be very careful! */
16
Glenn L McGrath545106f2002-11-11 06:21:00 +000017
Denis Vlasenko629563b2007-02-24 17:05:52 +000018#define MAXVARFMT 240
19#define MINNVBLOCK 64
Glenn L McGrath545106f2002-11-11 06:21:00 +000020
21/* variable flags */
Denis Vlasenko629563b2007-02-24 17:05:52 +000022#define VF_NUMBER 0x0001 /* 1 = primary type is number */
23#define VF_ARRAY 0x0002 /* 1 = it's an array */
Glenn L McGrath545106f2002-11-11 06:21:00 +000024
Denis Vlasenko629563b2007-02-24 17:05:52 +000025#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
26#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
27#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
28#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
29#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
30#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
31#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
Glenn L McGrath545106f2002-11-11 06:21:00 +000032
33/* these flags are static, don't change them when value is changed */
Denis Vlasenko629563b2007-02-24 17:05:52 +000034#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
Glenn L McGrath545106f2002-11-11 06:21:00 +000035
36/* Variable */
37typedef struct var_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000038 unsigned type; /* flags */
Glenn L McGrath545106f2002-11-11 06:21:00 +000039 double number;
40 char *string;
41 union {
Denis Vlasenko629563b2007-02-24 17:05:52 +000042 int aidx; /* func arg idx (for compilation stage) */
43 struct xhash_s *array; /* array ptr */
44 struct var_s *parent; /* for func args, ptr to actual parameter */
45 char **walker; /* list of array elements (for..in) */
Glenn L McGrath545106f2002-11-11 06:21:00 +000046 } x;
47} var;
48
49/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
50typedef struct chain_s {
51 struct node_s *first;
52 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +000053 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +000054} chain;
55
56/* Function */
57typedef struct func_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000058 unsigned nargs;
Glenn L McGrath545106f2002-11-11 06:21:00 +000059 struct chain_s body;
60} func;
61
62/* I/O stream */
63typedef struct rstream_s {
64 FILE *F;
65 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +000066 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +000067 int size;
68 int pos;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000069 smallint is_pipe;
Glenn L McGrath545106f2002-11-11 06:21:00 +000070} rstream;
71
72typedef struct hash_item_s {
73 union {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000074 struct var_s v; /* variable/array hash */
75 struct rstream_s rs; /* redirect streams hash */
76 struct func_s f; /* functions hash */
Glenn L McGrath545106f2002-11-11 06:21:00 +000077 } data;
Denis Vlasenkoffba9412007-05-17 23:03:35 +000078 struct hash_item_s *next; /* next in chain */
79 char name[1]; /* really it's longer */
Glenn L McGrath545106f2002-11-11 06:21:00 +000080} hash_item;
81
82typedef struct xhash_s {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000083 unsigned nel; /* num of elements */
84 unsigned csize; /* current hash size */
85 unsigned nprime; /* next hash size in PRIMES[] */
86 unsigned glen; /* summary length of item names */
Glenn L McGrath545106f2002-11-11 06:21:00 +000087 struct hash_item_s **items;
88} xhash;
89
90/* Tree node */
91typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +000092 uint32_t info;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +000093 unsigned lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +000094 union {
95 struct node_s *n;
96 var *v;
97 int i;
98 char *s;
99 regex_t *re;
100 } l;
101 union {
102 struct node_s *n;
103 regex_t *ire;
104 func *f;
105 int argno;
106 } r;
107 union {
108 struct node_s *n;
109 } a;
110} node;
111
112/* Block of temporary variables */
113typedef struct nvblock_s {
114 int size;
115 var *pos;
116 struct nvblock_s *prev;
117 struct nvblock_s *next;
118 var nv[0];
119} nvblock;
120
121typedef struct tsplitter_s {
122 node n;
123 regex_t re[2];
124} tsplitter;
125
126/* simple token classes */
127/* Order and hex values are very important!!! See next_token() */
128#define TC_SEQSTART 1 /* ( */
129#define TC_SEQTERM (1 << 1) /* ) */
130#define TC_REGEXP (1 << 2) /* /.../ */
131#define TC_OUTRDR (1 << 3) /* | > >> */
132#define TC_UOPPOST (1 << 4) /* unary postfix operator */
133#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
134#define TC_BINOPX (1 << 6) /* two-opnd operator */
135#define TC_IN (1 << 7)
136#define TC_COMMA (1 << 8)
137#define TC_PIPE (1 << 9) /* input redirection pipe */
138#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
139#define TC_ARRTERM (1 << 11) /* ] */
140#define TC_GRPSTART (1 << 12) /* { */
141#define TC_GRPTERM (1 << 13) /* } */
142#define TC_SEMICOL (1 << 14)
143#define TC_NEWLINE (1 << 15)
144#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
145#define TC_WHILE (1 << 17)
146#define TC_ELSE (1 << 18)
147#define TC_BUILTIN (1 << 19)
148#define TC_GETLINE (1 << 20)
149#define TC_FUNCDECL (1 << 21) /* `function' `func' */
150#define TC_BEGIN (1 << 22)
151#define TC_END (1 << 23)
152#define TC_EOF (1 << 24)
153#define TC_VARIABLE (1 << 25)
154#define TC_ARRAY (1 << 26)
155#define TC_FUNCTION (1 << 27)
156#define TC_STRING (1 << 28)
157#define TC_NUMBER (1 << 29)
158
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000159#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000160
161/* combined token classes */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000162#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
163#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
164#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
165 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000166
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000167#define TC_STATEMNT (TC_STATX | TC_WHILE)
168#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000169
170/* word tokens, cannot mean something else if not expected */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000171#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
172 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000173
174/* discard newlines after these */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000175#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
176 | TC_BINOP | TC_OPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000177
178/* what can expression begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000179#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000180/* what can group begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000181#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000182
183/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
184/* operator is inserted between them */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000185#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
186 | TC_STRING | TC_NUMBER | TC_UOPPOST)
187#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000188
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000189#define OF_RES1 0x010000
190#define OF_RES2 0x020000
191#define OF_STR1 0x040000
192#define OF_STR2 0x080000
193#define OF_NUM1 0x100000
194#define OF_CHECKED 0x200000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000195
196/* combined operator flags */
197#define xx 0
198#define xV OF_RES2
199#define xS (OF_RES2 | OF_STR2)
200#define Vx OF_RES1
201#define VV (OF_RES1 | OF_RES2)
202#define Nx (OF_RES1 | OF_NUM1)
203#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
204#define Sx (OF_RES1 | OF_STR1)
205#define SV (OF_RES1 | OF_STR1 | OF_RES2)
206#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
207
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000208#define OPCLSMASK 0xFF00
209#define OPNMASK 0x007F
Glenn L McGrath545106f2002-11-11 06:21:00 +0000210
211/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
212 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
213 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
214 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000215#define P(x) (x << 24)
216#define PRIMASK 0x7F000000
217#define PRIMASK2 0x7E000000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000218
219/* Operation classes */
220
221#define SHIFT_TIL_THIS 0x0600
222#define RECUR_FROM_THIS 0x1000
223
224enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000225 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
226 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000227
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000228 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
229 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
230 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000231
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000232 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
233 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
234 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
235 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
236 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
237 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
238 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
239 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
240 OC_DONE = 0x2800,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000241
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000242 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
243 ST_WHILE = 0x3300
Glenn L McGrath545106f2002-11-11 06:21:00 +0000244};
245
246/* simple builtins */
247enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000248 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000249 F_ti, F_le, F_sy, F_ff, F_cl
250};
251
252/* builtins */
253enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000254 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up,
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000255 B_ge, B_gs, B_su,
256 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000257};
258
259/* tokens and their corresponding info values */
260
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000261#define NTC "\377" /* switch to next token class (tc<<1) */
262#define NTCC '\377'
Glenn L McGrath545106f2002-11-11 06:21:00 +0000263
264#define OC_B OC_BUILTIN
265
Denis Vlasenkof782f522007-01-01 23:51:30 +0000266static const char tokenlist[] =
267 "\1(" NTC
268 "\1)" NTC
269 "\1/" NTC /* REGEXP */
270 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
271 "\2++" "\2--" NTC /* UOPPOST */
272 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
273 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
274 "\2*=" "\2/=" "\2%=" "\2^="
275 "\1+" "\1-" "\3**=" "\2**"
276 "\1/" "\1%" "\1^" "\1*"
277 "\2!=" "\2>=" "\2<=" "\1>"
278 "\1<" "\2!~" "\1~" "\2&&"
279 "\2||" "\1?" "\1:" NTC
280 "\2in" NTC
281 "\1," NTC
282 "\1|" NTC
283 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
284 "\1]" NTC
285 "\1{" NTC
286 "\1}" NTC
287 "\1;" NTC
288 "\1\n" NTC
289 "\2if" "\2do" "\3for" "\5break" /* STATX */
290 "\10continue" "\6delete" "\5print"
291 "\6printf" "\4next" "\10nextfile"
292 "\6return" "\4exit" NTC
293 "\5while" NTC
294 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000295
Denis Vlasenkof782f522007-01-01 23:51:30 +0000296 "\3and" "\5compl" "\6lshift" "\2or"
297 "\6rshift" "\3xor"
298 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
299 "\3cos" "\3exp" "\3int" "\3log"
300 "\4rand" "\3sin" "\4sqrt" "\5srand"
301 "\6gensub" "\4gsub" "\5index" "\6length"
302 "\5match" "\5split" "\7sprintf" "\3sub"
303 "\6substr" "\7systime" "\10strftime"
304 "\7tolower" "\7toupper" NTC
305 "\7getline" NTC
306 "\4func" "\10function" NTC
307 "\5BEGIN" NTC
308 "\3END" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000309 ;
310
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000311static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000312 0,
313 0,
314 OC_REGEXP,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000315 xS|'a', xS|'w', xS|'|',
316 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
317 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M',
318 OC_FIELD|xV|P(5),
319 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74),
320 OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
321 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/',
322 OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
323 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-',
324 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
325 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%',
326 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
327 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
328 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
329 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
330 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
331 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
332 OC_COLON|xx|P(67)|':',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000333 OC_IN|SV|P(49),
334 OC_COMMA|SS|P(80),
335 OC_PGETLINE|SV|P(37),
Denis Vlasenkof782f522007-01-01 23:51:30 +0000336 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',
337 OC_UNARY|xV|P(19)|'!',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000338 0,
339 0,
340 0,
341 0,
342 0,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000343 ST_IF, ST_DO, ST_FOR, OC_BREAK,
344 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
345 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
346 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000347 ST_WHILE,
348 0,
349
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000350 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
351 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000352 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
353 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
354 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
355 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
356 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
357 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b),
358 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
359 OC_GETLINE|SV|P(0),
360 0, 0,
361 0,
362 0
363};
364
365/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000366/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000367enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000368 CONVFMT, OFMT, FS, OFS,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000369 ORS, RS, RT, FILENAME,
370 SUBSEP, ARGIND, ARGC, ARGV,
371 ERRNO, FNR,
372 NR, NF, IGNORECASE,
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000373 ENVIRON, F0, NUM_INTERNAL_VARS
Glenn L McGrath545106f2002-11-11 06:21:00 +0000374};
375
Denis Vlasenkof782f522007-01-01 23:51:30 +0000376static const char vNames[] =
377 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
378 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
379 "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0"
380 "ERRNO\0" "FNR\0"
381 "NR\0" "NF\0*" "IGNORECASE\0*"
382 "ENVIRON\0" "$\0*" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000383
Denis Vlasenkof782f522007-01-01 23:51:30 +0000384static const char vValues[] =
385 "%.6g\0" "%.6g\0" " \0" " \0"
386 "\n\0" "\n\0" "\0" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000387 "\034\0"
388 "\377";
389
390/* hash size may grow to these values */
391#define FIRST_PRIME 61;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000392static const unsigned PRIMES[] = { 251, 1021, 4093, 16381, 65521 };
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000393
Glenn L McGrath545106f2002-11-11 06:21:00 +0000394
Glenn L McGrath545106f2002-11-11 06:21:00 +0000395
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000396/* Globals. Split in two parts so that first one is addressed
397 * with (mostly short) negative offsets */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000398struct globals {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000399 chain beginseq, mainseq, endseq, *seq;
400 node *break_ptr, *continue_ptr;
401 rstream *iF;
402 xhash *vhash, *ahash, *fdhash, *fnhash;
403 const char *g_progname;
404 int g_lineno;
405 int nfields;
406 int maxfields; /* used in fsrealloc() only */
407 var *Fields;
408 nvblock *g_cb;
409 char *g_pos;
410 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000411 smallint icase;
412 smallint exiting;
413 smallint nextrec;
414 smallint nextfile;
415 smallint is_f0_split;
416};
417struct globals2 {
418 uint32_t t_info; /* often used */
419 uint32_t t_tclass;
420 char *t_string;
421 int t_lineno;
422 int t_rollback;
423
424 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000425
426 /* former statics from various functions */
427 char *split_f0__fstrings;
428
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000429 uint32_t next_token__save_tclass;
430 uint32_t next_token__save_info;
431 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000432 smallint next_token__concat_inserted;
433
434 smallint next_input_file__files_happen;
435 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000436
437 var *evaluate__fnargs;
438 unsigned evaluate__seed;
439 regex_t evaluate__sreg;
440
441 var ptest__v;
442
443 tsplitter exec_builtin__tspl;
444
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000445 /* biggest and least used members go last */
446 double t_double;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000447 tsplitter fsplitter, rsplitter;
448};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000449#define G1 (ptr_to_globals[-1])
450#define G (*(struct globals2 *const)ptr_to_globals)
451/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
452/* char G1size[sizeof(G1)]; - 0x6c */
453/* char Gsize[sizeof(G)]; - 0x1cc */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000454/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000455/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
456#define beginseq (G1.beginseq )
457#define mainseq (G1.mainseq )
458#define endseq (G1.endseq )
459#define seq (G1.seq )
460#define break_ptr (G1.break_ptr )
461#define continue_ptr (G1.continue_ptr)
462#define iF (G1.iF )
463#define vhash (G1.vhash )
464#define ahash (G1.ahash )
465#define fdhash (G1.fdhash )
466#define fnhash (G1.fnhash )
467#define g_progname (G1.g_progname )
468#define g_lineno (G1.g_lineno )
469#define nfields (G1.nfields )
470#define maxfields (G1.maxfields )
471#define Fields (G1.Fields )
472#define g_cb (G1.g_cb )
473#define g_pos (G1.g_pos )
474#define g_buf (G1.g_buf )
475#define icase (G1.icase )
476#define exiting (G1.exiting )
477#define nextrec (G1.nextrec )
478#define nextfile (G1.nextfile )
479#define is_f0_split (G1.is_f0_split )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000480#define t_info (G.t_info )
481#define t_tclass (G.t_tclass )
482#define t_string (G.t_string )
483#define t_double (G.t_double )
484#define t_lineno (G.t_lineno )
485#define t_rollback (G.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000486#define intvar (G.intvar )
487#define fsplitter (G.fsplitter )
488#define rsplitter (G.rsplitter )
489#define INIT_G() do { \
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000490 PTR_TO_GLOBALS = xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000491 G.next_token__ltclass = TC_OPTERM; \
492 G.evaluate__seed = 1; \
493} while (0)
494
Glenn L McGrath545106f2002-11-11 06:21:00 +0000495
496/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000497static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000498static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000499static void chain_group(void);
500static var *evaluate(node *, var *);
501static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000502static int fmt_num(char *, int, const char *, double, int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000503static int awk_exit(int) ATTRIBUTE_NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000504
505/* ---- error handling ---- */
506
507static const char EMSG_INTERNAL_ERROR[] = "Internal error";
508static const char EMSG_UNEXP_EOS[] = "Unexpected end of string";
509static const char EMSG_UNEXP_TOKEN[] = "Unexpected token";
510static const char EMSG_DIV_BY_ZERO[] = "Division by zero";
511static const char EMSG_INV_FMT[] = "Invalid format specifier";
512static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin";
513static const char EMSG_NOT_ARRAY[] = "Not an array";
514static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error";
515static const char EMSG_UNDEF_FUNC[] = "Call to undefined function";
Denis Vlasenkof782f522007-01-01 23:51:30 +0000516#if !ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +0000517static const char EMSG_NO_MATH[] = "Math support is not compiled in";
518#endif
519
Denis Vlasenkof782f522007-01-01 23:51:30 +0000520static void zero_out_var(var * vp)
521{
522 memset(vp, 0, sizeof(*vp));
523}
524
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000525static void syntax_error(const char * const message) ATTRIBUTE_NORETURN;
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000526static void syntax_error(const char * const message)
527{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000528 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000529}
530
Glenn L McGrath545106f2002-11-11 06:21:00 +0000531/* ---- hash stuff ---- */
532
Denis Vlasenkof782f522007-01-01 23:51:30 +0000533static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000534{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000535 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000536
Denis Vlasenkof782f522007-01-01 23:51:30 +0000537 while (*name) idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000538 return idx;
539}
540
541/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000542static xhash *hash_init(void)
543{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000544 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000545
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000546 newhash = xzalloc(sizeof(xhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000547 newhash->csize = FIRST_PRIME;
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000548 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000549
550 return newhash;
551}
552
553/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000554static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000555{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000556 hash_item *hi;
557
558 hi = hash->items [ hashidx(name) % hash->csize ];
559 while (hi) {
560 if (strcmp(hi->name, name) == 0)
561 return &(hi->data);
562 hi = hi->next;
563 }
564 return NULL;
565}
566
567/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000568static void hash_rebuild(xhash *hash)
569{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000570 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000571 hash_item **newitems, *hi, *thi;
572
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000573 if (hash->nprime == ARRAY_SIZE(PRIMES))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000574 return;
575
576 newsize = PRIMES[hash->nprime++];
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000577 newitems = xzalloc(newsize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000578
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000579 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000580 hi = hash->items[i];
581 while (hi) {
582 thi = hi;
583 hi = thi->next;
584 idx = hashidx(thi->name) % newsize;
585 thi->next = newitems[idx];
586 newitems[idx] = thi;
587 }
588 }
589
590 free(hash->items);
591 hash->csize = newsize;
592 hash->items = newitems;
593}
594
595/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000596static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000597{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000598 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000599 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000600 int l;
601
602 hi = hash_search(hash, name);
Denis Vlasenkob78c7822007-07-18 18:31:11 +0000603 if (!hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000604 if (++hash->nel / hash->csize > 10)
605 hash_rebuild(hash);
606
Rob Landleya3896512006-05-07 20:20:34 +0000607 l = strlen(name) + 1;
Rob Landley9ffd4232006-05-21 18:30:35 +0000608 hi = xzalloc(sizeof(hash_item) + l);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000609 memcpy(hi->name, name, l);
610
611 idx = hashidx(name) % hash->csize;
612 hi->next = hash->items[idx];
613 hash->items[idx] = hi;
614 hash->glen += l;
615 }
616 return &(hi->data);
617}
618
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000619#define findvar(hash, name) ((var*) hash_find((hash), (name)))
620#define newvar(name) ((var*) hash_find(vhash, (name)))
621#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
622#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000623
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000624static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000625{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000626 hash_item *hi, **phi;
627
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000628 phi = &(hash->items[hashidx(name) % hash->csize]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000629 while (*phi) {
630 hi = *phi;
631 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000632 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000633 hash->nel--;
634 *phi = hi->next;
635 free(hi);
636 break;
637 }
638 phi = &(hi->next);
639 }
640}
641
642/* ------ some useful functions ------ */
643
Mike Frysinger10a11e22005-09-27 02:23:02 +0000644static void skip_spaces(char **s)
645{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000646 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000647
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000648 while (1) {
649 if (*p == '\\' && p[1] == '\n') {
650 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000651 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000652 } else if (*p != ' ' && *p != '\t') {
653 break;
654 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000655 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000656 }
657 *s = p;
658}
659
Mike Frysinger10a11e22005-09-27 02:23:02 +0000660static char *nextword(char **s)
661{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000662 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000663
Denis Vlasenkof782f522007-01-01 23:51:30 +0000664 while (*(*s)++) /* */;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000665
666 return p;
667}
668
Mike Frysinger10a11e22005-09-27 02:23:02 +0000669static char nextchar(char **s)
670{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000671 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000672
673 c = *((*s)++);
674 pps = *s;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000675 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000676 if (c == '\\' && *s == pps) c = *((*s)++);
677 return c;
678}
679
Denis Vlasenko3ad5d0c2007-06-12 20:54:54 +0000680static int ALWAYS_INLINE isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000681{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000682 return (isalnum(c) || c == '_');
683}
684
Mike Frysinger10a11e22005-09-27 02:23:02 +0000685static FILE *afopen(const char *path, const char *mode)
686{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000687 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000688}
689
690/* -------- working with variables (set/get/copy/etc) -------- */
691
Mike Frysinger10a11e22005-09-27 02:23:02 +0000692static xhash *iamarray(var *v)
693{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000694 var *a = v;
695
696 while (a->type & VF_CHILD)
697 a = a->x.parent;
698
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000699 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000700 a->type |= VF_ARRAY;
701 a->x.array = hash_init();
702 }
703 return a->x.array;
704}
705
Mike Frysinger10a11e22005-09-27 02:23:02 +0000706static void clear_array(xhash *array)
707{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000708 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000709 hash_item *hi, *thi;
710
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000711 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000712 hi = array->items[i];
713 while (hi) {
714 thi = hi;
715 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000716 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000717 free(thi);
718 }
719 array->items[i] = NULL;
720 }
721 array->glen = array->nel = 0;
722}
723
724/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000725static var *clrvar(var *v)
726{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000727 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000728 free(v->string);
729
730 v->type &= VF_DONTTOUCH;
731 v->type |= VF_DIRTY;
732 v->string = NULL;
733 return v;
734}
735
736/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000737static var *setvar_p(var *v, char *value)
738{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000739 clrvar(v);
740 v->string = value;
741 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000742 return v;
743}
744
745/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000746static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000747{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000748 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000749}
750
751/* same as setvar_s but set USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000752static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000753{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000754 setvar_s(v, value);
755 v->type |= VF_USER;
756 return v;
757}
758
759/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000760static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000761{
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000762 char sidx[sizeof(int)*3 + 1];
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000763 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000764
765 sprintf(sidx, "%d", idx);
766 v = findvar(iamarray(a), sidx);
767 setvar_u(v, s);
768}
769
770/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000771static var *setvar_i(var *v, double value)
772{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000773 clrvar(v);
774 v->type |= VF_NUMBER;
775 v->number = value;
776 handle_special(v);
777 return v;
778}
779
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000780static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000781{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000782 /* if v is numeric and has no cached string, convert it to string */
783 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000784 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
785 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000786 v->type |= VF_CACHED;
787 }
788 return (v->string == NULL) ? "" : v->string;
789}
790
Mike Frysinger10a11e22005-09-27 02:23:02 +0000791static double getvar_i(var *v)
792{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000793 char *s;
794
795 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
796 v->number = 0;
797 s = v->string;
798 if (s && *s) {
799 v->number = strtod(s, &s);
800 if (v->type & VF_USER) {
801 skip_spaces(&s);
802 if (*s != '\0')
803 v->type &= ~VF_USER;
804 }
805 } else {
806 v->type &= ~VF_USER;
807 }
808 v->type |= VF_CACHED;
809 }
810 return v->number;
811}
812
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000813static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000814{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000815 if (dest != src) {
816 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000817 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000818 dest->number = src->number;
819 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000820 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000821 }
822 handle_special(dest);
823 return dest;
824}
825
Mike Frysinger10a11e22005-09-27 02:23:02 +0000826static var *incvar(var *v)
827{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000828 return setvar_i(v, getvar_i(v)+1.);
829}
830
831/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000832static int is_numeric(var *v)
833{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000834 getvar_i(v);
835 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
836}
837
838/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000839static int istrue(var *v)
840{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000841 if (is_numeric(v))
842 return (v->number == 0) ? 0 : 1;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000843 return (v->string && *(v->string)) ? 1 : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000844}
845
Eric Andersenaff114c2004-04-14 17:51:38 +0000846/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000847static var *nvalloc(int n)
848{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000849 nvblock *pb = NULL;
850 var *v, *r;
851 int size;
852
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000853 while (g_cb) {
854 pb = g_cb;
855 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break;
856 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000857 }
858
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000859 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000860 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000861 g_cb = xmalloc(sizeof(nvblock) + size * sizeof(var));
862 g_cb->size = size;
863 g_cb->pos = g_cb->nv;
864 g_cb->prev = pb;
865 g_cb->next = NULL;
866 if (pb) pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000867 }
868
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000869 v = r = g_cb->pos;
870 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000871
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000872 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000873 v->type = 0;
874 v->string = NULL;
875 v++;
876 }
877
878 return r;
879}
880
Mike Frysinger10a11e22005-09-27 02:23:02 +0000881static void nvfree(var *v)
882{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000883 var *p;
884
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000885 if (v < g_cb->nv || v >= g_cb->pos)
886 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000887
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000888 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000889 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000890 clear_array(iamarray(p));
891 free(p->x.array->items);
892 free(p->x.array);
893 }
894 if (p->type & VF_WALK)
895 free(p->x.walker);
896
897 clrvar(p);
898 }
899
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000900 g_cb->pos = v;
901 while (g_cb->prev && g_cb->pos == g_cb->nv) {
902 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000903 }
904}
905
906/* ------- awk program text parsing ------- */
907
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000908/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000909 * If token isn't expected, give away. Return token class
910 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000911static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000912{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000913#define concat_inserted (G.next_token__concat_inserted)
914#define save_tclass (G.next_token__save_tclass)
915#define save_info (G.next_token__save_info)
916/* Initialized to TC_OPTERM: */
917#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000918
Denis Vlasenkof782f522007-01-01 23:51:30 +0000919 char *p, *pp, *s;
920 const char *tl;
921 uint32_t tc;
922 const uint32_t *ti;
923 int l;
924
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000925 if (t_rollback) {
926 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000927
928 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000929 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000930 t_tclass = save_tclass;
931 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000932
933 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000934 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000935 readnext:
Glenn L McGrath545106f2002-11-11 06:21:00 +0000936 skip_spaces(&p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000937 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000938 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000939 while (*p != '\n' && *p != '\0')
940 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000941
942 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000943 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000944
945 if (*p == '\0') {
946 tc = TC_EOF;
947
948 } else if (*p == '\"') {
949 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000950 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000951 while (*p != '\"') {
952 if (*p == '\0' || *p == '\n')
953 syntax_error(EMSG_UNEXP_EOS);
954 *(s++) = nextchar(&p);
955 }
956 p++;
957 *s = '\0';
958 tc = TC_STRING;
959
960 } else if ((expected & TC_REGEXP) && *p == '/') {
961 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000962 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000963 while (*p != '/') {
964 if (*p == '\0' || *p == '\n')
965 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +0000966 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000967 if (*s++ == '\\') {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000968 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000969 *(s-1) = bb_process_escape_sequence((const char **)&p);
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000970 if (*pp == '\\')
971 *s++ = '\\';
972 if (p == pp)
973 *s++ = *p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000974 }
975 }
976 p++;
977 *s = '\0';
978 tc = TC_REGEXP;
979
980 } else if (*p == '.' || isdigit(*p)) {
981 /* it's a number */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000982 t_double = strtod(p, &p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000983 if (*p == '.')
984 syntax_error(EMSG_UNEXP_TOKEN);
985 tc = TC_NUMBER;
986
987 } else {
988 /* search for something known */
989 tl = tokenlist;
990 tc = 0x00000001;
991 ti = tokeninfo;
992 while (*tl) {
993 l = *(tl++);
994 if (l == NTCC) {
995 tc <<= 1;
996 continue;
997 }
998 /* if token class is expected, token
999 * matches and it's not a longer word,
1000 * then this is what we are looking for
1001 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001002 if ((tc & (expected | TC_WORD | TC_NEWLINE))
1003 && *tl == *p && strncmp(p, tl, l) == 0
1004 && !((tc & TC_WORD) && isalnum_(p[l]))
1005 ) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001006 t_info = *ti;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001007 p += l;
1008 break;
1009 }
1010 ti++;
1011 tl += l;
1012 }
1013
Denis Vlasenkof782f522007-01-01 23:51:30 +00001014 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001015 /* it's a name (var/array/function),
1016 * otherwise it's something wrong
1017 */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001018 if (!isalnum_(*p))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001019 syntax_error(EMSG_UNEXP_TOKEN);
1020
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001021 t_string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001022 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001023 *(p-1) = *p;
1024 }
1025 *(p-1) = '\0';
1026 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +00001027 /* also consume whitespace between functionname and bracket */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001028 if (!(expected & TC_VARIABLE))
1029 skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001030 if (*p == '(') {
1031 tc = TC_FUNCTION;
1032 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001033 if (*p == '[') {
1034 p++;
1035 tc = TC_ARRAY;
1036 }
1037 }
1038 }
1039 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001040 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001041
1042 /* skipping newlines in some cases */
1043 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1044 goto readnext;
1045
1046 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001047 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001048 concat_inserted = TRUE;
1049 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001050 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001051 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001052 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001053 }
1054
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001055 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001056 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001057 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001058
1059 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001060 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001061 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001062 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001063
1064 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001065#undef concat_inserted
1066#undef save_tclass
1067#undef save_info
1068#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001069}
1070
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001071static void rollback_token(void)
1072{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001073 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001074}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001075
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001076static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001077{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001078 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001079
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001080 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001081 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001082 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001083 return n;
1084}
1085
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001086static node *mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001087{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001088 n->info = OC_REGEXP;
1089 n->l.re = re;
1090 n->r.ire = re + 1;
1091 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001092 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001093
1094 return n;
1095}
1096
Mike Frysinger10a11e22005-09-27 02:23:02 +00001097static node *condition(void)
1098{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001099 next_token(TC_SEQSTART);
1100 return parse_expr(TC_SEQTERM);
1101}
1102
1103/* parse expression terminated by given argument, return ptr
1104 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001105static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001106{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001107 node sn;
1108 node *cn = &sn;
1109 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001110 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001111 var *v;
1112
1113 sn.info = PRIMASK;
1114 sn.r.n = glptr = NULL;
1115 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1116
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001117 while (!((tc = next_token(xtc)) & iexp)) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001118 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001119 /* input redirection (<) attached to glptr node */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001120 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001121 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001122 xtc = TC_OPERAND | TC_UOPPRE;
1123 glptr = NULL;
1124
1125 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1126 /* for binary and postfix-unary operators, jump back over
1127 * previous operators with higher priority */
1128 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001129 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1130 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) )
Glenn L McGrath545106f2002-11-11 06:21:00 +00001131 vn = vn->a.n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001132 if ((t_info & OPCLSMASK) == OC_TERNARY)
1133 t_info += P(6);
1134 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001135 cn->a.n = vn->a.n;
1136 if (tc & TC_BINOP) {
1137 cn->l.n = vn;
1138 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001139 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001140 /* it's a pipe */
1141 next_token(TC_GETLINE);
1142 /* give maximum priority to this pipe */
1143 cn->info &= ~PRIMASK;
1144 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1145 }
1146 } else {
1147 cn->r.n = vn;
1148 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1149 }
1150 vn->a.n = cn;
1151
1152 } else {
1153 /* for operands and prefix-unary operators, attach them
1154 * to last node */
1155 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001156 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001157 cn->a.n = vn;
1158 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1159 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001160 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001161 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001162 * only simple tclasses should be used! */
1163 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001164 case TC_VARIABLE:
1165 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001166 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001167 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001168 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001169 cn->info = OC_FNARG;
1170 cn->l.i = v->x.aidx;
1171 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001172 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001173 }
1174 if (tc & TC_ARRAY) {
1175 cn->info |= xS;
1176 cn->r.n = parse_expr(TC_ARRTERM);
1177 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001178 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001179
Denis Vlasenkof782f522007-01-01 23:51:30 +00001180 case TC_NUMBER:
1181 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001182 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001183 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001184 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001185 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001186 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001187 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001188 break;
1189
Denis Vlasenkof782f522007-01-01 23:51:30 +00001190 case TC_REGEXP:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001191 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001192 break;
1193
Denis Vlasenkof782f522007-01-01 23:51:30 +00001194 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001195 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001196 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001197 cn->l.n = condition();
1198 break;
1199
Denis Vlasenkof782f522007-01-01 23:51:30 +00001200 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001201 cn = vn->r.n = parse_expr(TC_SEQTERM);
1202 cn->a.n = vn;
1203 break;
1204
Denis Vlasenkof782f522007-01-01 23:51:30 +00001205 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001206 glptr = cn;
1207 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1208 break;
1209
Denis Vlasenkof782f522007-01-01 23:51:30 +00001210 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001211 cn->l.n = condition();
1212 break;
1213 }
1214 }
1215 }
1216 }
1217 return sn.r.n;
1218}
1219
1220/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001221static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001222{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001223 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001224
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001225 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001226 seq->first = seq->last = new_node(0);
1227
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001228 if (seq->programname != g_progname) {
1229 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001230 n = chain_node(OC_NEWSOURCE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001231 n->l.s = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001232 }
1233
1234 n = seq->last;
1235 n->info = info;
1236 seq->last = n->a.n = new_node(OC_DONE);
1237
1238 return n;
1239}
1240
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001241static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001242{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001243 node *n;
1244
1245 n = chain_node(info);
1246 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001247 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001248 rollback_token();
1249}
1250
Mike Frysinger10a11e22005-09-27 02:23:02 +00001251static node *chain_loop(node *nn)
1252{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001253 node *n, *n2, *save_brk, *save_cont;
1254
1255 save_brk = break_ptr;
1256 save_cont = continue_ptr;
1257
1258 n = chain_node(OC_BR | Vx);
1259 continue_ptr = new_node(OC_EXEC);
1260 break_ptr = new_node(OC_EXEC);
1261 chain_group();
1262 n2 = chain_node(OC_EXEC | Vx);
1263 n2->l.n = nn;
1264 n2->a.n = n;
1265 continue_ptr->a.n = n2;
1266 break_ptr->a.n = n->r.n = seq->last;
1267
1268 continue_ptr = save_cont;
1269 break_ptr = save_brk;
1270
1271 return n;
1272}
1273
1274/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001275static void chain_group(void)
1276{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001277 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001278 node *n, *n2, *n3;
1279
1280 do {
1281 c = next_token(TC_GRPSEQ);
1282 } while (c & TC_NEWLINE);
1283
1284 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001285 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001286 if (t_tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001287 rollback_token();
1288 chain_group();
1289 }
1290 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1291 rollback_token();
1292 chain_expr(OC_EXEC | Vx);
1293 } else { /* TC_STATEMNT */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001294 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001295 case ST_IF:
1296 n = chain_node(OC_BR | Vx);
1297 n->l.n = condition();
1298 chain_group();
1299 n2 = chain_node(OC_EXEC);
1300 n->r.n = seq->last;
1301 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001302 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001303 n2->a.n = seq->last;
1304 } else {
1305 rollback_token();
1306 }
1307 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001308
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001309 case ST_WHILE:
1310 n2 = condition();
1311 n = chain_loop(NULL);
1312 n->l.n = n2;
1313 break;
1314
1315 case ST_DO:
1316 n2 = chain_node(OC_EXEC);
1317 n = chain_loop(NULL);
1318 n2->a.n = n->a.n;
1319 next_token(TC_WHILE);
1320 n->l.n = condition();
1321 break;
1322
1323 case ST_FOR:
1324 next_token(TC_SEQSTART);
1325 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001326 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001327 if ((n2->info & OPCLSMASK) != OC_IN)
1328 syntax_error(EMSG_UNEXP_TOKEN);
1329 n = chain_node(OC_WALKINIT | VV);
1330 n->l.n = n2->l.n;
1331 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001332 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001333 n->info = OC_WALKNEXT | Vx;
1334 n->l.n = n2->l.n;
1335 } else { /* for (;;) */
1336 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001337 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001338 n2 = parse_expr(TC_SEMICOL);
1339 n3 = parse_expr(TC_SEQTERM);
1340 n = chain_loop(n3);
1341 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001342 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001343 n->info = OC_EXEC;
1344 }
1345 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001346
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001347 case OC_PRINT:
1348 case OC_PRINTF:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001349 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001350 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001351 if (t_tclass & TC_OUTRDR) {
1352 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001353 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1354 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001355 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001356 rollback_token();
1357 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001358
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001359 case OC_BREAK:
1360 n = chain_node(OC_EXEC);
1361 n->a.n = break_ptr;
1362 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001363
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001364 case OC_CONTINUE:
1365 n = chain_node(OC_EXEC);
1366 n->a.n = continue_ptr;
1367 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001368
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001369 /* delete, next, nextfile, return, exit */
1370 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001371 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001372 }
1373 }
1374}
1375
Mike Frysinger10a11e22005-09-27 02:23:02 +00001376static void parse_program(char *p)
1377{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001378 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001379 node *cn;
1380 func *f;
1381 var *v;
1382
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001383 g_pos = p;
1384 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001385 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001386 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001387
1388 if (tclass & TC_OPTERM)
1389 continue;
1390
1391 seq = &mainseq;
1392 if (tclass & TC_BEGIN) {
1393 seq = &beginseq;
1394 chain_group();
1395
1396 } else if (tclass & TC_END) {
1397 seq = &endseq;
1398 chain_group();
1399
1400 } else if (tclass & TC_FUNCDECL) {
1401 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001402 g_pos++;
1403 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001404 f->body.first = NULL;
1405 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001406 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001407 v = findvar(ahash, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001408 v->x.aidx = (f->nargs)++;
1409
1410 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1411 break;
1412 }
1413 seq = &(f->body);
1414 chain_group();
1415 clear_array(ahash);
1416
1417 } else if (tclass & TC_OPSEQ) {
1418 rollback_token();
1419 cn = chain_node(OC_TEST);
1420 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001421 if (t_tclass & TC_GRPSTART) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001422 rollback_token();
1423 chain_group();
1424 } else {
1425 chain_node(OC_PRINT);
1426 }
1427 cn->r.n = mainseq.last;
1428
1429 } else /* if (tclass & TC_GRPSTART) */ {
1430 rollback_token();
1431 chain_group();
1432 }
1433 }
1434}
1435
1436
1437/* -------- program execution part -------- */
1438
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001439static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001440{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001441 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001442 node *n;
1443
1444 re = &spl->re[0];
1445 ire = &spl->re[1];
1446 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001447 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001448 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001449 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001450 }
Rob Landleya3896512006-05-07 20:20:34 +00001451 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001452 mk_re_node(s, n, re);
1453 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001454 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001455 }
1456
1457 return n;
1458}
1459
1460/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001461 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001462 * be later regfree'd manually
1463 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001464static regex_t *as_regex(node *op, regex_t *preg)
1465{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001466 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001467 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001468
1469 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1470 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001471 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001472 v = nvalloc(1);
1473 s = getvar_s(evaluate(op, v));
1474 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1475 nvfree(v);
1476 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001477}
1478
1479/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001480static void qrealloc(char **b, int n, int *size)
1481{
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001482 if (!*b || n >= *size)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001483 *b = xrealloc(*b, *size = n + (n>>1) + 80);
1484}
1485
1486/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001487static void fsrealloc(int size)
1488{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001489 int i;
1490
1491 if (size >= maxfields) {
1492 i = maxfields;
1493 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001494 Fields = xrealloc(Fields, maxfields * sizeof(var));
1495 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001496 Fields[i].type = VF_SPECIAL;
1497 Fields[i].string = NULL;
1498 }
1499 }
1500
1501 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001502 for (i = size; i < nfields; i++) {
1503 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001504 }
1505 }
1506 nfields = size;
1507}
1508
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001509static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001510{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001511 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001512 char c[4];
1513 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001514 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001515
1516 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001517 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1518 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001519
1520 c[0] = c[1] = (char)spl->info;
1521 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001522 if (*getvar_s(intvar[RS]) == '\0')
1523 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001524
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001525 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1526 if (!*s)
1527 return n; /* "": zero fields */
1528 n++; /* at least one field will be there */
1529 do {
1530 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001531 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1532 && pmatch[0].rm_so <= l
1533 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001534 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001535 if (pmatch[0].rm_eo == 0) {
1536 l++;
1537 pmatch[0].rm_eo++;
1538 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001539 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001540 } else {
1541 pmatch[0].rm_eo = l;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001542 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001543 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001544 memcpy(s1, s, l);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001545 s1[l] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001546 nextword(&s1);
1547 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001548 } while (*s);
1549 return n;
1550 }
1551 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001552 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001553 *s1++ = *s++;
1554 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001555 n++;
1556 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001557 return n;
1558 }
1559 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001560 if (icase) {
1561 c[0] = toupper(c[0]);
1562 c[1] = tolower(c[1]);
1563 }
1564 if (*s1) n++;
1565 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001566 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001567 n++;
1568 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001569 return n;
1570 }
1571 /* space split */
1572 while (*s) {
1573 s = skip_whitespace(s);
1574 if (!*s) break;
1575 n++;
1576 while (*s && !isspace(*s))
1577 *s1++ = *s++;
1578 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001579 }
1580 return n;
1581}
1582
Mike Frysinger10a11e22005-09-27 02:23:02 +00001583static void split_f0(void)
1584{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001585/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001586#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001587
Glenn L McGrath545106f2002-11-11 06:21:00 +00001588 int i, n;
1589 char *s;
1590
1591 if (is_f0_split)
1592 return;
1593
1594 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001595 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001596 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001597 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001598 fsrealloc(n);
1599 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001600 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001601 Fields[i].string = nextword(&s);
1602 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1603 }
1604
1605 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001606 clrvar(intvar[NF]);
1607 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1608 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001609#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001610}
1611
1612/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001613static void handle_special(var *v)
1614{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001615 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001616 char *b;
1617 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001618 int sl, l, len, i, bsize;
1619
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001620 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001621 return;
1622
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001623 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001624 n = (int)getvar_i(v);
1625 fsrealloc(n);
1626
1627 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001628 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001629 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001630 b = NULL;
1631 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001632 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001633 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001634 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001635 if (b) {
1636 memcpy(b+len, sep, sl);
1637 len += sl;
1638 }
1639 qrealloc(&b, len+l+sl, &bsize);
1640 memcpy(b+len, s, l);
1641 len += l;
1642 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001643 if (b)
1644 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001645 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001646 is_f0_split = TRUE;
1647
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001648 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001649 is_f0_split = FALSE;
1650
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001651 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001652 mk_splitter(getvar_s(v), &fsplitter);
1653
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001654 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001655 mk_splitter(getvar_s(v), &rsplitter);
1656
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001657 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001658 icase = istrue(v);
1659
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001660 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001661 n = getvar_i(intvar[NF]);
1662 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001663 /* right here v is invalid. Just to note... */
1664 }
1665}
1666
1667/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001668static node *nextarg(node **pn)
1669{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001670 node *n;
1671
1672 n = *pn;
1673 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1674 *pn = n->r.n;
1675 n = n->l.n;
1676 } else {
1677 *pn = NULL;
1678 }
1679 return n;
1680}
1681
Mike Frysinger10a11e22005-09-27 02:23:02 +00001682static void hashwalk_init(var *v, xhash *array)
1683{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001684 char **w;
1685 hash_item *hi;
1686 int i;
1687
1688 if (v->type & VF_WALK)
1689 free(v->x.walker);
1690
1691 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001692 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001693 w[0] = w[1] = (char *)(w + 2);
1694 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001695 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001696 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001697 strcpy(*w, hi->name);
1698 nextword(w);
1699 hi = hi->next;
1700 }
1701 }
1702}
1703
Mike Frysinger10a11e22005-09-27 02:23:02 +00001704static int hashwalk_next(var *v)
1705{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001706 char **w;
1707
1708 w = v->x.walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001709 if (w[1] == w[0])
Glenn L McGrath545106f2002-11-11 06:21:00 +00001710 return FALSE;
1711
1712 setvar_s(v, nextword(w+1));
1713 return TRUE;
1714}
1715
1716/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001717static int ptest(node *pattern)
1718{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001719 /* ptest__v is "static": to save stack space? */
1720 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001721}
1722
1723/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001724static int awk_getline(rstream *rsm, var *v)
1725{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001726 char *b;
1727 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001728 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001729 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001730 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001731
1732 /* we're using our own buffer since we need access to accumulating
1733 * characters
1734 */
1735 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001736 m = rsm->buffer;
1737 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001738 p = rsm->pos;
1739 size = rsm->size;
1740 c = (char) rsplitter.n.info;
1741 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001742
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001743 if (!m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001744 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001745 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001746 so = eo = p;
1747 r = 1;
1748 if (p > 0) {
1749 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1750 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001751 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001752 so = pmatch[0].rm_so;
1753 eo = pmatch[0].rm_eo;
1754 if (b[eo] != '\0')
1755 break;
1756 }
1757 } else if (c != '\0') {
1758 s = strchr(b+pp, c);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001759 if (!s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001760 if (s) {
1761 so = eo = s-b;
1762 eo++;
1763 break;
1764 }
1765 } else {
1766 while (b[rp] == '\n')
1767 rp++;
1768 s = strstr(b+rp, "\n\n");
1769 if (s) {
1770 so = eo = s-b;
1771 while (b[eo] == '\n') eo++;
1772 if (b[eo] != '\0')
1773 break;
1774 }
1775 }
1776 }
1777
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001778 if (a > 0) {
1779 memmove(m, (const void *)(m+a), p+1);
1780 b = m;
1781 a = 0;
1782 }
1783
1784 qrealloc(&m, a+p+128, &size);
1785 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001786 pp = p;
1787 p += safe_read(fd, b+p, size-p-1);
1788 if (p < pp) {
1789 p = 0;
1790 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001791 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001792 }
1793 b[p] = '\0';
1794
1795 } while (p > pp);
1796
1797 if (p == 0) {
1798 r--;
1799 } else {
1800 c = b[so]; b[so] = '\0';
1801 setvar_s(v, b+rp);
1802 v->type |= VF_USER;
1803 b[so] = c;
1804 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001805 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001806 b[eo] = c;
1807 }
1808
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001809 rsm->buffer = m;
1810 rsm->adv = a + eo;
1811 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001812 rsm->size = size;
1813
1814 return r;
1815}
1816
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001817static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001818{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001819 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001820 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001821 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001822
1823 if (int_as_int && n == (int)n) {
1824 r = snprintf(b, size, "%d", (int)n);
1825 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001826 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001827 if (strchr("diouxX", c)) {
1828 r = snprintf(b, size, format, (int)n);
1829 } else if (strchr("eEfgG", c)) {
1830 r = snprintf(b, size, format, n);
1831 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001832 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001833 }
1834 }
1835 return r;
1836}
1837
1838
1839/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001840static char *awk_printf(node *n)
1841{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001842 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001843 char *fmt, *s, *f;
1844 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001845 int i, j, incr, bsize;
1846 char c, c1;
1847 var *v, *arg;
1848
1849 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001850 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001851
1852 i = 0;
1853 while (*f) {
1854 s = f;
1855 while (*f && (*f != '%' || *(++f) == '%'))
1856 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001857 while (*f && !isalpha(*f)) {
1858 if (*f == '*')
1859 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001860 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001861 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001862
1863 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001864 qrealloc(&b, incr + i, &bsize);
1865 c = *f;
1866 if (c != '\0') f++;
1867 c1 = *f;
1868 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001869 arg = evaluate(nextarg(&n), v);
1870
1871 j = i;
1872 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001873 i += sprintf(b+i, s, is_numeric(arg) ?
1874 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001875 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001876 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001877 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001878 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001879 } else {
1880 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1881 }
1882 *f = c1;
1883
1884 /* if there was an error while sprintf, return value is negative */
1885 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001886 }
1887
Denis Vlasenkof782f522007-01-01 23:51:30 +00001888 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001889 free(fmt);
1890 nvfree(v);
1891 b[i] = '\0';
1892 return b;
1893}
1894
1895/* common substitution routine
1896 * replace (nm) substring of (src) that match (n) with (repl), store
1897 * result into (dest), return number of substitutions. If nm=0, replace
1898 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1899 * subexpression matching (\1-\9)
1900 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001901static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001902{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001903 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001904 const char *s;
1905 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001906 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1907 regmatch_t pmatch[10];
1908 regex_t sreg, *re;
1909
1910 re = as_regex(rn, &sreg);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001911 if (!src) src = intvar[F0];
1912 if (!dest) dest = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001913
1914 i = di = 0;
1915 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001916 rl = strlen(repl);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001917 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001918 so = pmatch[0].rm_so;
1919 eo = pmatch[0].rm_eo;
1920
1921 qrealloc(&ds, di + eo + rl, &dssize);
1922 memcpy(ds + di, sp, eo);
1923 di += eo;
1924 if (++i >= nm) {
1925 /* replace */
1926 di -= (eo - so);
1927 nbs = 0;
1928 for (s = repl; *s; s++) {
1929 ds[di++] = c = *s;
1930 if (c == '\\') {
1931 nbs++;
1932 continue;
1933 }
1934 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1935 di -= ((nbs + 3) >> 1);
1936 j = 0;
1937 if (c != '&') {
1938 j = c - '0';
1939 nbs++;
1940 }
1941 if (nbs % 2) {
1942 ds[di++] = c;
1943 } else {
1944 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1945 qrealloc(&ds, di + rl + n, &dssize);
1946 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1947 di += n;
1948 }
1949 }
1950 nbs = 0;
1951 }
1952 }
1953
1954 sp += eo;
1955 if (i == nm) break;
1956 if (eo == so) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001957 ds[di] = *sp++;
1958 if (!ds[di++]) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001959 }
1960 }
1961
1962 qrealloc(&ds, di + strlen(sp), &dssize);
1963 strcpy(ds + di, sp);
1964 setvar_p(dest, ds);
1965 if (re == &sreg) regfree(re);
1966 return i;
1967}
1968
Mike Frysinger10a11e22005-09-27 02:23:02 +00001969static var *exec_builtin(node *op, var *res)
1970{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001971#define tspl (G.exec_builtin__tspl)
1972
Glenn L McGrath545106f2002-11-11 06:21:00 +00001973 int (*to_xxx)(int);
1974 var *tv;
1975 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001976 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001977 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001978 regmatch_t pmatch[2];
1979 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001980 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001981 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001982 int nargs;
1983 time_t tt;
1984 char *s, *s1;
1985 int i, l, ll, n;
1986
1987 tv = nvalloc(4);
1988 isr = info = op->info;
1989 op = op->l.n;
1990
1991 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001992 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001993 an[i] = nextarg(&op);
1994 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
1995 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
1996 isr >>= 1;
1997 }
1998
1999 nargs = i;
2000 if (nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002001 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002002
2003 switch (info & OPNMASK) {
2004
Denis Vlasenkof782f522007-01-01 23:51:30 +00002005 case B_a2:
2006#if ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +00002007 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
2008#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002009 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002010#endif
2011 break;
2012
Denis Vlasenkof782f522007-01-01 23:51:30 +00002013 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002014 if (nargs > 2) {
2015 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2016 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2017 } else {
2018 spl = &fsplitter.n;
2019 }
2020
2021 n = awk_split(as[0], spl, &s);
2022 s1 = s;
2023 clear_array(iamarray(av[1]));
2024 for (i=1; i<=n; i++)
2025 setari_u(av[1], i, nextword(&s1));
2026 free(s);
2027 setvar_i(res, n);
2028 break;
2029
Denis Vlasenkof782f522007-01-01 23:51:30 +00002030 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00002031 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002032 i = getvar_i(av[1]) - 1;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002033 if (i > l) i = l;
2034 if (i < 0) i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002035 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002036 if (n < 0) n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002037 s = xmalloc(n+1);
2038 strncpy(s, as[0]+i, n);
2039 s[n] = '\0';
2040 setvar_p(res, s);
2041 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002042
Denis Vlasenkof782f522007-01-01 23:51:30 +00002043 case B_an:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002044 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
2045 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002046
Denis Vlasenkof782f522007-01-01 23:51:30 +00002047 case B_co:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002048 setvar_i(res, ~(long)getvar_i(av[0]));
2049 break;
2050
Denis Vlasenkof782f522007-01-01 23:51:30 +00002051 case B_ls:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002052 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
2053 break;
2054
Denis Vlasenkof782f522007-01-01 23:51:30 +00002055 case B_or:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002056 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
2057 break;
2058
Denis Vlasenkof782f522007-01-01 23:51:30 +00002059 case B_rs:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002060 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
2061 break;
2062
Denis Vlasenkof782f522007-01-01 23:51:30 +00002063 case B_xo:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002064 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
2065 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002066
Denis Vlasenkof782f522007-01-01 23:51:30 +00002067 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002068 to_xxx = tolower;
2069 goto lo_cont;
2070
Denis Vlasenkof782f522007-01-01 23:51:30 +00002071 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002072 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002073 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00002074 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002075 while (*s1) {
2076 *s1 = (*to_xxx)(*s1);
2077 s1++;
2078 }
2079 setvar_p(res, s);
2080 break;
2081
Denis Vlasenkof782f522007-01-01 23:51:30 +00002082 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002083 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002084 ll = strlen(as[1]);
2085 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002086 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002087 if (!icase) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002088 s = strstr(as[0], as[1]);
2089 if (s) n = (s - as[0]) + 1;
2090 } else {
2091 /* this piece of code is terribly slow and
2092 * really should be rewritten
2093 */
2094 for (i=0; i<=l; i++) {
2095 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2096 n = i+1;
2097 break;
2098 }
2099 }
2100 }
2101 }
2102 setvar_i(res, n);
2103 break;
2104
Denis Vlasenkof782f522007-01-01 23:51:30 +00002105 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002106 if (nargs > 1)
2107 tt = getvar_i(av[1]);
2108 else
2109 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002110 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002111 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002112 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2113 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002114 g_buf[i] = '\0';
2115 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002116 break;
2117
Denis Vlasenkof782f522007-01-01 23:51:30 +00002118 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002119 re = as_regex(an[1], &sreg);
2120 n = regexec(re, as[0], 1, pmatch, 0);
2121 if (n == 0) {
2122 pmatch[0].rm_so++;
2123 pmatch[0].rm_eo++;
2124 } else {
2125 pmatch[0].rm_so = 0;
2126 pmatch[0].rm_eo = -1;
2127 }
2128 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2129 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2130 setvar_i(res, pmatch[0].rm_so);
2131 if (re == &sreg) regfree(re);
2132 break;
2133
Denis Vlasenkof782f522007-01-01 23:51:30 +00002134 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002135 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2136 break;
2137
Denis Vlasenkof782f522007-01-01 23:51:30 +00002138 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002139 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2140 break;
2141
Denis Vlasenkof782f522007-01-01 23:51:30 +00002142 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002143 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2144 break;
2145 }
2146
2147 nvfree(tv);
2148 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002149#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002150}
2151
2152/*
2153 * Evaluate node - the heart of the program. Supplied with subtree
2154 * and place where to store result. returns ptr to result.
2155 */
2156#define XC(n) ((n) >> 8)
2157
Mike Frysinger10a11e22005-09-27 02:23:02 +00002158static var *evaluate(node *op, var *res)
2159{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002160/* This procedure is recursive so we should count every byte */
2161#define fnargs (G.evaluate__fnargs)
2162/* seed is initialized to 1 */
2163#define seed (G.evaluate__seed)
2164#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002165
Glenn L McGrath545106f2002-11-11 06:21:00 +00002166 node *op1;
2167 var *v1;
2168 union {
2169 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002170 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002171 double d;
2172 int i;
2173 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002174 uint32_t opinfo;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002175 int opn;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002176 union {
2177 char *s;
2178 rstream *rsm;
2179 FILE *F;
2180 var *v;
2181 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002182 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002183 } X;
2184
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002185 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002186 return setvar_s(res, NULL);
2187
2188 v1 = nvalloc(2);
2189
2190 while (op) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002191 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002192 opn = (opinfo & OPNMASK);
2193 g_lineno = op->lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002194
Mike Frysingerde2b9382005-09-27 03:18:00 +00002195 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002196 op1 = op->l.n;
2197 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2198 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2199 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2200 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2201 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2202
2203 switch (XC(opinfo & OPCLSMASK)) {
2204
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002205 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002206
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002207 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002208 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002209 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2210 /* it's range pattern */
2211 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2212 op->info |= OF_CHECKED;
2213 if (ptest(op1->r.n))
2214 op->info &= ~OF_CHECKED;
2215
2216 op = op->a.n;
2217 } else {
2218 op = op->r.n;
2219 }
2220 } else {
2221 op = (ptest(op1)) ? op->a.n : op->r.n;
2222 }
2223 break;
2224
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002225 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002226 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002227 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002228
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002229 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002230 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002231 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002232 break;
2233
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002234 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002235 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002236 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002237 break;
2238
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002239 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002240 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002241 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2242 break;
2243
Denis Vlasenkof782f522007-01-01 23:51:30 +00002244 case XC( OC_PRINT ):
2245 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002246 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002247 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002248 X.rsm = newfile(R.s);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002249 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002250 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002251 X.rsm->F = popen(R.s, "w");
2252 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002253 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002254 X.rsm->is_pipe = 1;
2255 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002256 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002257 }
2258 }
2259 X.F = X.rsm->F;
2260 }
2261
2262 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002263 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002264 fputs(getvar_s(intvar[F0]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002265 } else {
2266 while (op1) {
2267 L.v = evaluate(nextarg(&op1), v1);
2268 if (L.v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002269 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002270 getvar_i(L.v), TRUE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002271 fputs(g_buf, X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002272 } else {
2273 fputs(getvar_s(L.v), X.F);
2274 }
2275
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002276 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002277 }
2278 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002279 fputs(getvar_s(intvar[ORS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002280
2281 } else { /* OC_PRINTF */
2282 L.s = awk_printf(op1);
2283 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002284 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002285 }
2286 fflush(X.F);
2287 break;
2288
Denis Vlasenkof782f522007-01-01 23:51:30 +00002289 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002290 X.info = op1->info & OPCLSMASK;
2291 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002292 R.v = op1->l.v;
2293 } else if (X.info == OC_FNARG) {
2294 R.v = &fnargs[op1->l.i];
2295 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002296 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002297 }
2298
Mike Frysingerde2b9382005-09-27 03:18:00 +00002299 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002300 clrvar(L.v);
2301 L.s = getvar_s(evaluate(op1->r.n, v1));
2302 hash_remove(iamarray(R.v), L.s);
2303 } else {
2304 clear_array(iamarray(R.v));
2305 }
2306 break;
2307
Denis Vlasenkof782f522007-01-01 23:51:30 +00002308 case XC( OC_NEWSOURCE ):
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002309 g_progname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002310 break;
2311
Denis Vlasenkof782f522007-01-01 23:51:30 +00002312 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002313 copyvar(res, L.v);
2314 break;
2315
Denis Vlasenkof782f522007-01-01 23:51:30 +00002316 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002317 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002318 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002319 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002320 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002321 clrvar(res);
2322 break;
2323
Denis Vlasenkof782f522007-01-01 23:51:30 +00002324 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002325 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002326
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002327 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002328
Denis Vlasenkof782f522007-01-01 23:51:30 +00002329 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002330 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002331 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002332 split_f0();
2333 goto v_cont;
2334
Denis Vlasenkof782f522007-01-01 23:51:30 +00002335 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002336 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002337 v_cont:
2338 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002339 break;
2340
Denis Vlasenkof782f522007-01-01 23:51:30 +00002341 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002342 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2343 break;
2344
Denis Vlasenkof782f522007-01-01 23:51:30 +00002345 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002346 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002347 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002348 goto re_cont;
2349
Denis Vlasenkof782f522007-01-01 23:51:30 +00002350 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002351 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002352 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002353 X.re = as_regex(op1, &sreg);
2354 R.i = regexec(X.re, L.s, 0, NULL, 0);
2355 if (X.re == &sreg) regfree(X.re);
2356 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2357 break;
2358
Denis Vlasenkof782f522007-01-01 23:51:30 +00002359 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002360 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002361 if (R.v == v1+1 && R.v->string) {
2362 res = setvar_p(L.v, R.v->string);
2363 R.v->string = NULL;
2364 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002365 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002366 }
2367 break;
2368
Denis Vlasenkof782f522007-01-01 23:51:30 +00002369 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002370 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002371 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002372 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2373 break;
2374
Denis Vlasenkof782f522007-01-01 23:51:30 +00002375 case XC( OC_FUNC ):
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002376 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002377 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002378
2379 X.v = R.v = nvalloc(op->r.f->nargs+1);
2380 while (op1) {
2381 L.v = evaluate(nextarg(&op1), v1);
2382 copyvar(R.v, L.v);
2383 R.v->type |= VF_CHILD;
2384 R.v->x.parent = L.v;
2385 if (++R.v - X.v >= op->r.f->nargs)
2386 break;
2387 }
2388
2389 R.v = fnargs;
2390 fnargs = X.v;
2391
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002392 L.s = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002393 res = evaluate(op->r.f->body.first, res);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002394 g_progname = L.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002395
2396 nvfree(fnargs);
2397 fnargs = R.v;
2398 break;
2399
Denis Vlasenkof782f522007-01-01 23:51:30 +00002400 case XC( OC_GETLINE ):
2401 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002402 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002403 X.rsm = newfile(L.s);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002404 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002405 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2406 X.rsm->F = popen(L.s, "r");
2407 X.rsm->is_pipe = TRUE;
2408 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002409 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002410 }
2411 }
2412 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002413 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002414 X.rsm = iF;
2415 }
2416
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002417 if (!X.rsm->F) {
2418 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002419 setvar_i(res, -1);
2420 break;
2421 }
2422
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002423 if (!op->r.n)
2424 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002425
2426 L.i = awk_getline(X.rsm, R.v);
2427 if (L.i > 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002428 if (!op1) {
2429 incvar(intvar[FNR]);
2430 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002431 }
2432 }
2433 setvar_i(res, L.i);
2434 break;
2435
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002436 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002437 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002438 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002439
Denis Vlasenkof782f522007-01-01 23:51:30 +00002440 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002441 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002442 break;
2443
Denis Vlasenkof782f522007-01-01 23:51:30 +00002444 case F_rn:
2445 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002446 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002447#if ENABLE_FEATURE_AWK_MATH
2448 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002449 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002450 break;
2451
Denis Vlasenkof782f522007-01-01 23:51:30 +00002452 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002453 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002454 break;
2455
Denis Vlasenkof782f522007-01-01 23:51:30 +00002456 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002457 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002458 break;
2459
Denis Vlasenkof782f522007-01-01 23:51:30 +00002460 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002461 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002462 break;
2463
Denis Vlasenkof782f522007-01-01 23:51:30 +00002464 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002465 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002466 break;
2467#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002468 case F_co:
2469 case F_ex:
2470 case F_lg:
2471 case F_si:
2472 case F_sq:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002473 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002474 break;
2475#endif
Denis Vlasenkof782f522007-01-01 23:51:30 +00002476 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002477 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002478 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002479 srand(seed);
2480 break;
2481
Denis Vlasenkof782f522007-01-01 23:51:30 +00002482 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002483 R.d = time(NULL);
2484 break;
2485
Denis Vlasenkof782f522007-01-01 23:51:30 +00002486 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002487 if (!op1)
2488 L.s = getvar_s(intvar[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002489 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002490 break;
2491
Denis Vlasenkof782f522007-01-01 23:51:30 +00002492 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002493 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002494 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2495 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002496 break;
2497
Denis Vlasenkof782f522007-01-01 23:51:30 +00002498 case F_ff:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002499 if (!op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002500 fflush(stdout);
2501 else {
2502 if (L.s && *L.s) {
2503 X.rsm = newfile(L.s);
2504 fflush(X.rsm->F);
2505 } else {
2506 fflush(NULL);
2507 }
2508 }
2509 break;
2510
Denis Vlasenkof782f522007-01-01 23:51:30 +00002511 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002512 X.rsm = (rstream *)hash_search(fdhash, L.s);
2513 if (X.rsm) {
2514 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002515 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002516 hash_remove(fdhash, L.s);
2517 }
2518 if (R.i != 0)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002519 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002520 R.d = (double)R.i;
2521 break;
2522 }
2523 setvar_i(res, R.d);
2524 break;
2525
Denis Vlasenkof782f522007-01-01 23:51:30 +00002526 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002527 res = exec_builtin(op, res);
2528 break;
2529
Denis Vlasenkof782f522007-01-01 23:51:30 +00002530 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002531 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002532 break;
2533
Denis Vlasenkof782f522007-01-01 23:51:30 +00002534 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002535 X.v = R.v;
2536 L.d = R.d = getvar_i(R.v);
2537 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002538 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002539 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002540 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002541 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002542 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002543 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002544 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002545 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002546 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002547 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002548 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002549 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002550 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002551 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002552 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002553 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002554 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002555 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002556 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002557 setvar_i(X.v, R.d);
2558 }
2559 setvar_i(res, L.d);
2560 break;
2561
Denis Vlasenkof782f522007-01-01 23:51:30 +00002562 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002563 R.i = (int)getvar_i(R.v);
2564 if (R.i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002565 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002566 } else {
2567 split_f0();
2568 if (R.i > nfields)
2569 fsrealloc(R.i);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002570 res = &Fields[R.i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002571 }
2572 break;
2573
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002574 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002575 case XC( OC_CONCAT ):
2576 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002577 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002578 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002579 strcpy(X.s, L.s);
2580 if ((opinfo & OPCLSMASK) == OC_COMMA) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002581 L.s = getvar_s(intvar[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002582 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002583 strcat(X.s, L.s);
2584 }
2585 strcat(X.s, R.s);
2586 setvar_p(res, X.s);
2587 break;
2588
Denis Vlasenkof782f522007-01-01 23:51:30 +00002589 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002590 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2591 break;
2592
Denis Vlasenkof782f522007-01-01 23:51:30 +00002593 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002594 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2595 break;
2596
Denis Vlasenkof782f522007-01-01 23:51:30 +00002597 case XC( OC_BINARY ):
2598 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002599 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002600 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002601 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002602 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002603 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002604 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002605 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002606 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002607 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002608 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002609 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002610 case '/':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002611 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002612 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002613 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002614 case '&':
2615#if ENABLE_FEATURE_AWK_MATH
Mike Frysingerde2b9382005-09-27 03:18:00 +00002616 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002617#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002618 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002619#endif
2620 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002621 case '%':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002622 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002623 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002624 break;
2625 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002626 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002627 break;
2628
Denis Vlasenkof782f522007-01-01 23:51:30 +00002629 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002630 if (is_numeric(L.v) && is_numeric(R.v)) {
2631 L.d = getvar_i(L.v) - getvar_i(R.v);
2632 } else {
2633 L.s = getvar_s(L.v);
2634 R.s = getvar_s(R.v);
2635 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2636 }
2637 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002638 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002639 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002640 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002641 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002642 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002643 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002644 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002645 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002646 break;
2647 }
2648 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2649 break;
2650
Denis Vlasenkof782f522007-01-01 23:51:30 +00002651 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002652 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002653 }
2654 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2655 op = op->a.n;
2656 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2657 break;
2658 if (nextrec)
2659 break;
2660 }
2661 nvfree(v1);
2662 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002663#undef fnargs
2664#undef seed
2665#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002666}
2667
2668
2669/* -------- main & co. -------- */
2670
Mike Frysinger10a11e22005-09-27 02:23:02 +00002671static int awk_exit(int r)
2672{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002673 var tv;
2674 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002675 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002676
Denis Vlasenkof782f522007-01-01 23:51:30 +00002677 zero_out_var(&tv);
2678
2679 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002680 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002681 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002682 evaluate(endseq.first, &tv);
2683 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002684
2685 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002686 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002687 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002688 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002689 if (hi->data.rs.F && hi->data.rs.is_pipe)
2690 pclose(hi->data.rs.F);
2691 hi = hi->next;
2692 }
2693 }
2694
2695 exit(r);
2696}
2697
2698/* if expr looks like "var=value", perform assignment and return 1,
2699 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002700static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002701{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002702 char *exprc, *s, *s0, *s1;
2703
Rob Landleyd921b2e2006-08-03 15:41:12 +00002704 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002705 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2706 free(exprc);
2707 return FALSE;
2708 }
2709
2710 *(s++) = '\0';
2711 s0 = s1 = s;
2712 while (*s)
2713 *(s1++) = nextchar(&s);
2714
2715 *s1 = '\0';
2716 setvar_u(newvar(exprc), s0);
2717 free(exprc);
2718 return TRUE;
2719}
2720
2721/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002722static rstream *next_input_file(void)
2723{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002724#define rsm (G.next_input_file__rsm)
2725#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002726
Glenn L McGrath545106f2002-11-11 06:21:00 +00002727 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002728 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002729
2730 if (rsm.F) fclose(rsm.F);
2731 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002732 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002733
2734 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002735 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002736 if (files_happen)
2737 return NULL;
2738 fname = "-";
2739 F = stdin;
2740 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002741 ind = getvar_s(incvar(intvar[ARGIND]));
2742 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002743 if (fname && *fname && !is_assignment(fname))
2744 F = afopen(fname, "r");
2745 }
2746 } while (!F);
2747
2748 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002749 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002750 rsm.F = F;
2751 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002752#undef rsm
2753#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002754}
2755
Denis Vlasenko06af2162007-02-03 17:28:39 +00002756int awk_main(int argc, char **argv);
Rob Landleydfba7412006-03-06 20:47:33 +00002757int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002758{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002759 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002760 char *opt_F, *opt_W;
2761 llist_t *opt_v = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002762 int i, j, flen;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002763 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002764 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002765 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002766 char *vnames = (char *)vNames; /* cheat */
2767 char *vvalues = (char *)vValues;
2768
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002769 INIT_G();
2770
Denis Vlasenko150f4022007-01-13 21:06:21 +00002771 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002772 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2773 if (ENABLE_LOCALE_SUPPORT)
2774 setlocale(LC_NUMERIC, "C");
2775
Denis Vlasenkof782f522007-01-01 23:51:30 +00002776 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002777
2778 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002779 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002780
2781 vhash = hash_init();
2782 ahash = hash_init();
2783 fdhash = hash_init();
2784 fnhash = hash_init();
2785
2786 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002787 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002788 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00002789 if (*vvalues != '\377')
2790 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002791 else
2792 setvar_i(v, 0);
2793
Denis Vlasenkof782f522007-01-01 23:51:30 +00002794 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002795 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002796 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002797 }
2798 }
2799
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002800 handle_special(intvar[FS]);
2801 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002802
Denis Vlasenkof782f522007-01-01 23:51:30 +00002803 newfile("/dev/stdin")->F = stdin;
2804 newfile("/dev/stdout")->F = stdout;
2805 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002806
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002807 /* Huh, people report that sometimes environ is NULL. Oh well. */
2808 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002809 /* environ is writable, thus we don't strdup it needlessly */
2810 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002811 char *s1 = strchr(s, '=');
2812 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002813 *s1 = '\0';
2814 /* Both findvar and setvar_u take const char*
2815 * as 2nd arg -> environment is not trashed */
2816 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
2817 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00002818 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002819 }
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002820 opt_complementary = "v::";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002821 opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &g_progname, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002822 argv += optind;
2823 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002824 if (opt & 0x1)
2825 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002826 while (opt_v) { /* -v */
2827 if (!is_assignment(llist_pop(&opt_v)))
2828 bb_show_usage();
2829 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002830 if (opt & 0x4) { // -f
Denis Vlasenkof782f522007-01-01 23:51:30 +00002831 char *s = s; /* die, gcc, die */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002832 FILE *from_file = afopen(g_progname, "r");
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002833 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002834 if (fseek(from_file, 0, SEEK_END) == 0) {
2835 flen = ftell(from_file);
2836 s = xmalloc(flen + 4);
2837 fseek(from_file, 0, SEEK_SET);
2838 i = 1 + fread(s + 1, 1, flen, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002839 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002840 for (i = j = 1; j > 0; i += j) {
2841 s = xrealloc(s, i + 4096);
2842 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002843 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002844 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002845 s[i] = '\0';
Denis Vlasenkof782f522007-01-01 23:51:30 +00002846 fclose(from_file);
2847 parse_program(s + 1);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002848 free(s);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002849 } else { // no -f: take program from 1st parameter
2850 if (!argc)
2851 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002852 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00002853 parse_program(*argv++);
2854 argc--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002855 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002856 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002857 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002858
Glenn L McGrath545106f2002-11-11 06:21:00 +00002859 /* fill in ARGV array */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002860 setvar_i(intvar[ARGC], argc + 1);
2861 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002862 i = 0;
2863 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002864 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002865
2866 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002867 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002868 awk_exit(EXIT_SUCCESS);
2869
2870 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002871 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002872
2873 /* passing through input files */
2874 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002875 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002876 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002877
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002878 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002879 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002880 incvar(intvar[NR]);
2881 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002882 evaluate(mainseq.first, &tv);
2883
2884 if (nextfile)
2885 break;
2886 }
2887
Denis Vlasenkof782f522007-01-01 23:51:30 +00002888 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002889 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002890
2891 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002892 }
2893
Glenn L McGrath545106f2002-11-11 06:21:00 +00002894 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002895 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002896}