blob: 983b3111642f3d1684746c17d4eb994809d4e1fa [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>
Glenn L McGrath545106f2002-11-11 06:21:00 +000013
Denis Vlasenko99912ca2007-04-10 15:43:37 +000014/* This is a NOEXEC applet. Be very careful! */
15
Glenn L McGrath545106f2002-11-11 06:21:00 +000016
Denis Vlasenko629563b2007-02-24 17:05:52 +000017#define MAXVARFMT 240
18#define MINNVBLOCK 64
Glenn L McGrath545106f2002-11-11 06:21:00 +000019
20/* variable flags */
Denis Vlasenko629563b2007-02-24 17:05:52 +000021#define VF_NUMBER 0x0001 /* 1 = primary type is number */
22#define VF_ARRAY 0x0002 /* 1 = it's an array */
Glenn L McGrath545106f2002-11-11 06:21:00 +000023
Denis Vlasenko629563b2007-02-24 17:05:52 +000024#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
25#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
26#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
27#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
28#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
29#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
30#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
Glenn L McGrath545106f2002-11-11 06:21:00 +000031
32/* these flags are static, don't change them when value is changed */
Denis Vlasenko629563b2007-02-24 17:05:52 +000033#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
Glenn L McGrath545106f2002-11-11 06:21:00 +000034
35/* Variable */
36typedef struct var_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000037 unsigned type; /* flags */
Glenn L McGrath545106f2002-11-11 06:21:00 +000038 double number;
39 char *string;
40 union {
Denis Vlasenko629563b2007-02-24 17:05:52 +000041 int aidx; /* func arg idx (for compilation stage) */
42 struct xhash_s *array; /* array ptr */
43 struct var_s *parent; /* for func args, ptr to actual parameter */
44 char **walker; /* list of array elements (for..in) */
Glenn L McGrath545106f2002-11-11 06:21:00 +000045 } x;
46} var;
47
48/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
49typedef struct chain_s {
50 struct node_s *first;
51 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +000052 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +000053} chain;
54
55/* Function */
56typedef struct func_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000057 unsigned nargs;
Glenn L McGrath545106f2002-11-11 06:21:00 +000058 struct chain_s body;
59} func;
60
61/* I/O stream */
62typedef struct rstream_s {
63 FILE *F;
64 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +000065 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +000066 int size;
67 int pos;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000068 smallint is_pipe;
Glenn L McGrath545106f2002-11-11 06:21:00 +000069} rstream;
70
71typedef struct hash_item_s {
72 union {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000073 struct var_s v; /* variable/array hash */
74 struct rstream_s rs; /* redirect streams hash */
75 struct func_s f; /* functions hash */
Glenn L McGrath545106f2002-11-11 06:21:00 +000076 } data;
Denis Vlasenkoffba9412007-05-17 23:03:35 +000077 struct hash_item_s *next; /* next in chain */
78 char name[1]; /* really it's longer */
Glenn L McGrath545106f2002-11-11 06:21:00 +000079} hash_item;
80
81typedef struct xhash_s {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000082 unsigned nel; /* num of elements */
83 unsigned csize; /* current hash size */
84 unsigned nprime; /* next hash size in PRIMES[] */
85 unsigned glen; /* summary length of item names */
Glenn L McGrath545106f2002-11-11 06:21:00 +000086 struct hash_item_s **items;
87} xhash;
88
89/* Tree node */
90typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +000091 uint32_t info;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +000092 unsigned lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +000093 union {
94 struct node_s *n;
95 var *v;
96 int i;
97 char *s;
98 regex_t *re;
99 } l;
100 union {
101 struct node_s *n;
102 regex_t *ire;
103 func *f;
104 int argno;
105 } r;
106 union {
107 struct node_s *n;
108 } a;
109} node;
110
111/* Block of temporary variables */
112typedef struct nvblock_s {
113 int size;
114 var *pos;
115 struct nvblock_s *prev;
116 struct nvblock_s *next;
117 var nv[0];
118} nvblock;
119
120typedef struct tsplitter_s {
121 node n;
122 regex_t re[2];
123} tsplitter;
124
125/* simple token classes */
126/* Order and hex values are very important!!! See next_token() */
127#define TC_SEQSTART 1 /* ( */
128#define TC_SEQTERM (1 << 1) /* ) */
129#define TC_REGEXP (1 << 2) /* /.../ */
130#define TC_OUTRDR (1 << 3) /* | > >> */
131#define TC_UOPPOST (1 << 4) /* unary postfix operator */
132#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
133#define TC_BINOPX (1 << 6) /* two-opnd operator */
134#define TC_IN (1 << 7)
135#define TC_COMMA (1 << 8)
136#define TC_PIPE (1 << 9) /* input redirection pipe */
137#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
138#define TC_ARRTERM (1 << 11) /* ] */
139#define TC_GRPSTART (1 << 12) /* { */
140#define TC_GRPTERM (1 << 13) /* } */
141#define TC_SEMICOL (1 << 14)
142#define TC_NEWLINE (1 << 15)
143#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
144#define TC_WHILE (1 << 17)
145#define TC_ELSE (1 << 18)
146#define TC_BUILTIN (1 << 19)
147#define TC_GETLINE (1 << 20)
148#define TC_FUNCDECL (1 << 21) /* `function' `func' */
149#define TC_BEGIN (1 << 22)
150#define TC_END (1 << 23)
151#define TC_EOF (1 << 24)
152#define TC_VARIABLE (1 << 25)
153#define TC_ARRAY (1 << 26)
154#define TC_FUNCTION (1 << 27)
155#define TC_STRING (1 << 28)
156#define TC_NUMBER (1 << 29)
157
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000158#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000159
160/* combined token classes */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000161#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
162#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
163#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
164 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000165
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000166#define TC_STATEMNT (TC_STATX | TC_WHILE)
167#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000168
169/* word tokens, cannot mean something else if not expected */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000170#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
171 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000172
173/* discard newlines after these */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000174#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
175 | TC_BINOP | TC_OPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000176
177/* what can expression begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000178#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000179/* what can group begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000180#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000181
182/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
183/* operator is inserted between them */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000184#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
185 | TC_STRING | TC_NUMBER | TC_UOPPOST)
186#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000187
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000188#define OF_RES1 0x010000
189#define OF_RES2 0x020000
190#define OF_STR1 0x040000
191#define OF_STR2 0x080000
192#define OF_NUM1 0x100000
193#define OF_CHECKED 0x200000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000194
195/* combined operator flags */
196#define xx 0
197#define xV OF_RES2
198#define xS (OF_RES2 | OF_STR2)
199#define Vx OF_RES1
200#define VV (OF_RES1 | OF_RES2)
201#define Nx (OF_RES1 | OF_NUM1)
202#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
203#define Sx (OF_RES1 | OF_STR1)
204#define SV (OF_RES1 | OF_STR1 | OF_RES2)
205#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
206
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000207#define OPCLSMASK 0xFF00
208#define OPNMASK 0x007F
Glenn L McGrath545106f2002-11-11 06:21:00 +0000209
210/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
211 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
212 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
213 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000214#define P(x) (x << 24)
215#define PRIMASK 0x7F000000
216#define PRIMASK2 0x7E000000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000217
218/* Operation classes */
219
220#define SHIFT_TIL_THIS 0x0600
221#define RECUR_FROM_THIS 0x1000
222
223enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000224 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
225 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000226
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000227 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
228 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
229 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000230
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000231 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
232 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
233 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
234 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
235 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
236 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
237 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
238 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
239 OC_DONE = 0x2800,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000240
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000241 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
242 ST_WHILE = 0x3300
Glenn L McGrath545106f2002-11-11 06:21:00 +0000243};
244
245/* simple builtins */
246enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000247 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000248 F_ti, F_le, F_sy, F_ff, F_cl
249};
250
251/* builtins */
252enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000253 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up,
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000254 B_ge, B_gs, B_su,
255 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000256};
257
258/* tokens and their corresponding info values */
259
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000260#define NTC "\377" /* switch to next token class (tc<<1) */
261#define NTCC '\377'
Glenn L McGrath545106f2002-11-11 06:21:00 +0000262
263#define OC_B OC_BUILTIN
264
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000265static const char tokenlist[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000266 "\1(" NTC
267 "\1)" NTC
268 "\1/" NTC /* REGEXP */
269 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
270 "\2++" "\2--" NTC /* UOPPOST */
271 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
272 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
273 "\2*=" "\2/=" "\2%=" "\2^="
274 "\1+" "\1-" "\3**=" "\2**"
275 "\1/" "\1%" "\1^" "\1*"
276 "\2!=" "\2>=" "\2<=" "\1>"
277 "\1<" "\2!~" "\1~" "\2&&"
278 "\2||" "\1?" "\1:" NTC
279 "\2in" NTC
280 "\1," NTC
281 "\1|" NTC
282 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
283 "\1]" NTC
284 "\1{" NTC
285 "\1}" NTC
286 "\1;" NTC
287 "\1\n" NTC
288 "\2if" "\2do" "\3for" "\5break" /* STATX */
289 "\10continue" "\6delete" "\5print"
290 "\6printf" "\4next" "\10nextfile"
291 "\6return" "\4exit" NTC
292 "\5while" NTC
293 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000294
Denis Vlasenkof782f522007-01-01 23:51:30 +0000295 "\3and" "\5compl" "\6lshift" "\2or"
296 "\6rshift" "\3xor"
297 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
298 "\3cos" "\3exp" "\3int" "\3log"
299 "\4rand" "\3sin" "\4sqrt" "\5srand"
300 "\6gensub" "\4gsub" "\5index" "\6length"
301 "\5match" "\5split" "\7sprintf" "\3sub"
302 "\6substr" "\7systime" "\10strftime"
303 "\7tolower" "\7toupper" NTC
304 "\7getline" NTC
305 "\4func" "\10function" NTC
306 "\5BEGIN" NTC
307 "\3END" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000308 ;
309
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000310static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000311 0,
312 0,
313 OC_REGEXP,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000314 xS|'a', xS|'w', xS|'|',
315 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
316 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M',
317 OC_FIELD|xV|P(5),
318 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74),
319 OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|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_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-',
323 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
324 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%',
325 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
326 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
327 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
328 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
329 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
330 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
331 OC_COLON|xx|P(67)|':',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000332 OC_IN|SV|P(49),
333 OC_COMMA|SS|P(80),
334 OC_PGETLINE|SV|P(37),
Denis Vlasenkof782f522007-01-01 23:51:30 +0000335 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',
336 OC_UNARY|xV|P(19)|'!',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000337 0,
338 0,
339 0,
340 0,
341 0,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000342 ST_IF, ST_DO, ST_FOR, OC_BREAK,
343 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
344 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
345 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000346 ST_WHILE,
347 0,
348
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000349 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
350 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000351 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
352 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
353 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
354 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
355 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
356 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b),
357 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
358 OC_GETLINE|SV|P(0),
359 0, 0,
360 0,
361 0
362};
363
364/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000365/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000366enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000367 CONVFMT, OFMT, FS, OFS,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000368 ORS, RS, RT, FILENAME,
369 SUBSEP, ARGIND, ARGC, ARGV,
370 ERRNO, FNR,
371 NR, NF, IGNORECASE,
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000372 ENVIRON, F0, NUM_INTERNAL_VARS
Glenn L McGrath545106f2002-11-11 06:21:00 +0000373};
374
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000375static const char vNames[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000376 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
377 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
378 "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0"
379 "ERRNO\0" "FNR\0"
380 "NR\0" "NF\0*" "IGNORECASE\0*"
381 "ENVIRON\0" "$\0*" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000382
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000383static const char vValues[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000384 "%.6g\0" "%.6g\0" " \0" " \0"
385 "\n\0" "\n\0" "\0" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000386 "\034\0"
387 "\377";
388
389/* hash size may grow to these values */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000390#define FIRST_PRIME 61
391static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000392
Glenn L McGrath545106f2002-11-11 06:21:00 +0000393
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000394/* Globals. Split in two parts so that first one is addressed
395 * with (mostly short) negative offsets */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000396struct globals {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000397 chain beginseq, mainseq, endseq, *seq;
398 node *break_ptr, *continue_ptr;
399 rstream *iF;
400 xhash *vhash, *ahash, *fdhash, *fnhash;
401 const char *g_progname;
402 int g_lineno;
403 int nfields;
404 int maxfields; /* used in fsrealloc() only */
405 var *Fields;
406 nvblock *g_cb;
407 char *g_pos;
408 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000409 smallint icase;
410 smallint exiting;
411 smallint nextrec;
412 smallint nextfile;
413 smallint is_f0_split;
414};
415struct globals2 {
416 uint32_t t_info; /* often used */
417 uint32_t t_tclass;
418 char *t_string;
419 int t_lineno;
420 int t_rollback;
421
422 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000423
424 /* former statics from various functions */
425 char *split_f0__fstrings;
426
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000427 uint32_t next_token__save_tclass;
428 uint32_t next_token__save_info;
429 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000430 smallint next_token__concat_inserted;
431
432 smallint next_input_file__files_happen;
433 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000434
435 var *evaluate__fnargs;
436 unsigned evaluate__seed;
437 regex_t evaluate__sreg;
438
439 var ptest__v;
440
441 tsplitter exec_builtin__tspl;
442
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000443 /* biggest and least used members go last */
444 double t_double;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000445 tsplitter fsplitter, rsplitter;
446};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000447#define G1 (ptr_to_globals[-1])
448#define G (*(struct globals2 *const)ptr_to_globals)
449/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
450/* char G1size[sizeof(G1)]; - 0x6c */
451/* char Gsize[sizeof(G)]; - 0x1cc */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000452/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000453/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
454#define beginseq (G1.beginseq )
455#define mainseq (G1.mainseq )
456#define endseq (G1.endseq )
457#define seq (G1.seq )
458#define break_ptr (G1.break_ptr )
459#define continue_ptr (G1.continue_ptr)
460#define iF (G1.iF )
461#define vhash (G1.vhash )
462#define ahash (G1.ahash )
463#define fdhash (G1.fdhash )
464#define fnhash (G1.fnhash )
465#define g_progname (G1.g_progname )
466#define g_lineno (G1.g_lineno )
467#define nfields (G1.nfields )
468#define maxfields (G1.maxfields )
469#define Fields (G1.Fields )
470#define g_cb (G1.g_cb )
471#define g_pos (G1.g_pos )
472#define g_buf (G1.g_buf )
473#define icase (G1.icase )
474#define exiting (G1.exiting )
475#define nextrec (G1.nextrec )
476#define nextfile (G1.nextfile )
477#define is_f0_split (G1.is_f0_split )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000478#define t_info (G.t_info )
479#define t_tclass (G.t_tclass )
480#define t_string (G.t_string )
481#define t_double (G.t_double )
482#define t_lineno (G.t_lineno )
483#define t_rollback (G.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000484#define intvar (G.intvar )
485#define fsplitter (G.fsplitter )
486#define rsplitter (G.rsplitter )
487#define INIT_G() do { \
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000488 PTR_TO_GLOBALS = xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000489 G.next_token__ltclass = TC_OPTERM; \
490 G.evaluate__seed = 1; \
491} while (0)
492
Glenn L McGrath545106f2002-11-11 06:21:00 +0000493
494/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000495static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000496static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000497static void chain_group(void);
498static var *evaluate(node *, var *);
499static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000500static int fmt_num(char *, int, const char *, double, int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000501static int awk_exit(int) ATTRIBUTE_NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000502
503/* ---- error handling ---- */
504
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000505static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
506static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
507static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
508static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
509static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
510static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
511static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
512static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
513static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
Denis Vlasenkof782f522007-01-01 23:51:30 +0000514#if !ENABLE_FEATURE_AWK_MATH
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000515static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000516#endif
517
Denis Vlasenkof782f522007-01-01 23:51:30 +0000518static void zero_out_var(var * vp)
519{
520 memset(vp, 0, sizeof(*vp));
521}
522
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000523static void syntax_error(const char *const message) ATTRIBUTE_NORETURN;
524static void syntax_error(const char *const message)
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000525{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000526 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000527}
528
Glenn L McGrath545106f2002-11-11 06:21:00 +0000529/* ---- hash stuff ---- */
530
Denis Vlasenkof782f522007-01-01 23:51:30 +0000531static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000532{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000533 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000534
Denis Vlasenkof782f522007-01-01 23:51:30 +0000535 while (*name) idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000536 return idx;
537}
538
539/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000540static xhash *hash_init(void)
541{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000542 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000543
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000544 newhash = xzalloc(sizeof(xhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000545 newhash->csize = FIRST_PRIME;
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000546 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000547
548 return newhash;
549}
550
551/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000552static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000553{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000554 hash_item *hi;
555
556 hi = hash->items [ hashidx(name) % hash->csize ];
557 while (hi) {
558 if (strcmp(hi->name, name) == 0)
559 return &(hi->data);
560 hi = hi->next;
561 }
562 return NULL;
563}
564
565/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000566static void hash_rebuild(xhash *hash)
567{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000568 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000569 hash_item **newitems, *hi, *thi;
570
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000571 if (hash->nprime == ARRAY_SIZE(PRIMES))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000572 return;
573
574 newsize = PRIMES[hash->nprime++];
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000575 newitems = xzalloc(newsize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000576
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000577 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000578 hi = hash->items[i];
579 while (hi) {
580 thi = hi;
581 hi = thi->next;
582 idx = hashidx(thi->name) % newsize;
583 thi->next = newitems[idx];
584 newitems[idx] = thi;
585 }
586 }
587
588 free(hash->items);
589 hash->csize = newsize;
590 hash->items = newitems;
591}
592
593/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000594static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000595{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000596 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000597 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000598 int l;
599
600 hi = hash_search(hash, name);
Denis Vlasenkob78c7822007-07-18 18:31:11 +0000601 if (!hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000602 if (++hash->nel / hash->csize > 10)
603 hash_rebuild(hash);
604
Rob Landleya3896512006-05-07 20:20:34 +0000605 l = strlen(name) + 1;
Rob Landley9ffd4232006-05-21 18:30:35 +0000606 hi = xzalloc(sizeof(hash_item) + l);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000607 memcpy(hi->name, name, l);
608
609 idx = hashidx(name) % hash->csize;
610 hi->next = hash->items[idx];
611 hash->items[idx] = hi;
612 hash->glen += l;
613 }
614 return &(hi->data);
615}
616
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000617#define findvar(hash, name) ((var*) hash_find((hash), (name)))
618#define newvar(name) ((var*) hash_find(vhash, (name)))
619#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
620#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000621
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000622static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000623{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000624 hash_item *hi, **phi;
625
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000626 phi = &(hash->items[hashidx(name) % hash->csize]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000627 while (*phi) {
628 hi = *phi;
629 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000630 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000631 hash->nel--;
632 *phi = hi->next;
633 free(hi);
634 break;
635 }
636 phi = &(hi->next);
637 }
638}
639
640/* ------ some useful functions ------ */
641
Mike Frysinger10a11e22005-09-27 02:23:02 +0000642static void skip_spaces(char **s)
643{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000644 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000645
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000646 while (1) {
647 if (*p == '\\' && p[1] == '\n') {
648 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000649 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000650 } else if (*p != ' ' && *p != '\t') {
651 break;
652 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000653 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000654 }
655 *s = p;
656}
657
Mike Frysinger10a11e22005-09-27 02:23:02 +0000658static char *nextword(char **s)
659{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000660 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000661
Denis Vlasenkof782f522007-01-01 23:51:30 +0000662 while (*(*s)++) /* */;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000663
664 return p;
665}
666
Mike Frysinger10a11e22005-09-27 02:23:02 +0000667static char nextchar(char **s)
668{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000669 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000670
671 c = *((*s)++);
672 pps = *s;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000673 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000674 if (c == '\\' && *s == pps) c = *((*s)++);
675 return c;
676}
677
Denis Vlasenko3ad5d0c2007-06-12 20:54:54 +0000678static int ALWAYS_INLINE isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000679{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000680 return (isalnum(c) || c == '_');
681}
682
Mike Frysinger10a11e22005-09-27 02:23:02 +0000683static FILE *afopen(const char *path, const char *mode)
684{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000685 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000686}
687
688/* -------- working with variables (set/get/copy/etc) -------- */
689
Mike Frysinger10a11e22005-09-27 02:23:02 +0000690static xhash *iamarray(var *v)
691{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000692 var *a = v;
693
694 while (a->type & VF_CHILD)
695 a = a->x.parent;
696
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000697 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000698 a->type |= VF_ARRAY;
699 a->x.array = hash_init();
700 }
701 return a->x.array;
702}
703
Mike Frysinger10a11e22005-09-27 02:23:02 +0000704static void clear_array(xhash *array)
705{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000706 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000707 hash_item *hi, *thi;
708
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000709 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000710 hi = array->items[i];
711 while (hi) {
712 thi = hi;
713 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000714 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000715 free(thi);
716 }
717 array->items[i] = NULL;
718 }
719 array->glen = array->nel = 0;
720}
721
722/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000723static var *clrvar(var *v)
724{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000725 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000726 free(v->string);
727
728 v->type &= VF_DONTTOUCH;
729 v->type |= VF_DIRTY;
730 v->string = NULL;
731 return v;
732}
733
734/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000735static var *setvar_p(var *v, char *value)
736{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000737 clrvar(v);
738 v->string = value;
739 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000740 return v;
741}
742
743/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000744static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000745{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000746 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000747}
748
749/* same as setvar_s but set USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000750static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000751{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000752 setvar_s(v, value);
753 v->type |= VF_USER;
754 return v;
755}
756
757/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000758static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000759{
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000760 char sidx[sizeof(int)*3 + 1];
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000761 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000762
763 sprintf(sidx, "%d", idx);
764 v = findvar(iamarray(a), sidx);
765 setvar_u(v, s);
766}
767
768/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000769static var *setvar_i(var *v, double value)
770{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000771 clrvar(v);
772 v->type |= VF_NUMBER;
773 v->number = value;
774 handle_special(v);
775 return v;
776}
777
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000778static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000779{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000780 /* if v is numeric and has no cached string, convert it to string */
781 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000782 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
783 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000784 v->type |= VF_CACHED;
785 }
786 return (v->string == NULL) ? "" : v->string;
787}
788
Mike Frysinger10a11e22005-09-27 02:23:02 +0000789static double getvar_i(var *v)
790{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000791 char *s;
792
793 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
794 v->number = 0;
795 s = v->string;
796 if (s && *s) {
797 v->number = strtod(s, &s);
798 if (v->type & VF_USER) {
799 skip_spaces(&s);
800 if (*s != '\0')
801 v->type &= ~VF_USER;
802 }
803 } else {
804 v->type &= ~VF_USER;
805 }
806 v->type |= VF_CACHED;
807 }
808 return v->number;
809}
810
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000811static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000812{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000813 if (dest != src) {
814 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000815 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000816 dest->number = src->number;
817 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000818 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000819 }
820 handle_special(dest);
821 return dest;
822}
823
Mike Frysinger10a11e22005-09-27 02:23:02 +0000824static var *incvar(var *v)
825{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000826 return setvar_i(v, getvar_i(v) + 1.);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000827}
828
829/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000830static int is_numeric(var *v)
831{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000832 getvar_i(v);
833 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
834}
835
836/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000837static int istrue(var *v)
838{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000839 if (is_numeric(v))
840 return (v->number == 0) ? 0 : 1;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000841 return (v->string && *(v->string)) ? 1 : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000842}
843
Eric Andersenaff114c2004-04-14 17:51:38 +0000844/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000845static var *nvalloc(int n)
846{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000847 nvblock *pb = NULL;
848 var *v, *r;
849 int size;
850
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000851 while (g_cb) {
852 pb = g_cb;
853 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break;
854 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000855 }
856
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000857 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000858 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000859 g_cb = xmalloc(sizeof(nvblock) + size * sizeof(var));
860 g_cb->size = size;
861 g_cb->pos = g_cb->nv;
862 g_cb->prev = pb;
863 g_cb->next = NULL;
864 if (pb) pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000865 }
866
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000867 v = r = g_cb->pos;
868 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000869
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000870 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000871 v->type = 0;
872 v->string = NULL;
873 v++;
874 }
875
876 return r;
877}
878
Mike Frysinger10a11e22005-09-27 02:23:02 +0000879static void nvfree(var *v)
880{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000881 var *p;
882
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000883 if (v < g_cb->nv || v >= g_cb->pos)
884 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000885
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000886 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000887 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000888 clear_array(iamarray(p));
889 free(p->x.array->items);
890 free(p->x.array);
891 }
892 if (p->type & VF_WALK)
893 free(p->x.walker);
894
895 clrvar(p);
896 }
897
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000898 g_cb->pos = v;
899 while (g_cb->prev && g_cb->pos == g_cb->nv) {
900 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000901 }
902}
903
904/* ------- awk program text parsing ------- */
905
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000906/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000907 * If token isn't expected, give away. Return token class
908 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000909static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000910{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000911#define concat_inserted (G.next_token__concat_inserted)
912#define save_tclass (G.next_token__save_tclass)
913#define save_info (G.next_token__save_info)
914/* Initialized to TC_OPTERM: */
915#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000916
Denis Vlasenkof782f522007-01-01 23:51:30 +0000917 char *p, *pp, *s;
918 const char *tl;
919 uint32_t tc;
920 const uint32_t *ti;
921 int l;
922
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000923 if (t_rollback) {
924 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000925
926 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000927 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000928 t_tclass = save_tclass;
929 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000930
931 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000932 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000933 readnext:
Glenn L McGrath545106f2002-11-11 06:21:00 +0000934 skip_spaces(&p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000935 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000936 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000937 while (*p != '\n' && *p != '\0')
938 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000939
940 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000941 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000942
943 if (*p == '\0') {
944 tc = TC_EOF;
945
946 } else if (*p == '\"') {
947 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000948 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000949 while (*p != '\"') {
950 if (*p == '\0' || *p == '\n')
951 syntax_error(EMSG_UNEXP_EOS);
952 *(s++) = nextchar(&p);
953 }
954 p++;
955 *s = '\0';
956 tc = TC_STRING;
957
958 } else if ((expected & TC_REGEXP) && *p == '/') {
959 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000960 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000961 while (*p != '/') {
962 if (*p == '\0' || *p == '\n')
963 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +0000964 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000965 if (*s++ == '\\') {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000966 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000967 *(s-1) = bb_process_escape_sequence((const char **)&p);
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000968 if (*pp == '\\')
969 *s++ = '\\';
970 if (p == pp)
971 *s++ = *p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000972 }
973 }
974 p++;
975 *s = '\0';
976 tc = TC_REGEXP;
977
978 } else if (*p == '.' || isdigit(*p)) {
979 /* it's a number */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000980 t_double = strtod(p, &p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000981 if (*p == '.')
982 syntax_error(EMSG_UNEXP_TOKEN);
983 tc = TC_NUMBER;
984
985 } else {
986 /* search for something known */
987 tl = tokenlist;
988 tc = 0x00000001;
989 ti = tokeninfo;
990 while (*tl) {
991 l = *(tl++);
992 if (l == NTCC) {
993 tc <<= 1;
994 continue;
995 }
996 /* if token class is expected, token
997 * matches and it's not a longer word,
998 * then this is what we are looking for
999 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001000 if ((tc & (expected | TC_WORD | TC_NEWLINE))
1001 && *tl == *p && strncmp(p, tl, l) == 0
1002 && !((tc & TC_WORD) && isalnum_(p[l]))
1003 ) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001004 t_info = *ti;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001005 p += l;
1006 break;
1007 }
1008 ti++;
1009 tl += l;
1010 }
1011
Denis Vlasenkof782f522007-01-01 23:51:30 +00001012 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001013 /* it's a name (var/array/function),
1014 * otherwise it's something wrong
1015 */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001016 if (!isalnum_(*p))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001017 syntax_error(EMSG_UNEXP_TOKEN);
1018
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001019 t_string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001020 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001021 *(p-1) = *p;
1022 }
1023 *(p-1) = '\0';
1024 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +00001025 /* also consume whitespace between functionname and bracket */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001026 if (!(expected & TC_VARIABLE))
1027 skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001028 if (*p == '(') {
1029 tc = TC_FUNCTION;
1030 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001031 if (*p == '[') {
1032 p++;
1033 tc = TC_ARRAY;
1034 }
1035 }
1036 }
1037 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001038 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001039
1040 /* skipping newlines in some cases */
1041 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1042 goto readnext;
1043
1044 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001045 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001046 concat_inserted = TRUE;
1047 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001048 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001049 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001050 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001051 }
1052
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001053 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001054 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001055 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001056
1057 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001058 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001059 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001060 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001061
1062 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001063#undef concat_inserted
1064#undef save_tclass
1065#undef save_info
1066#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001067}
1068
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001069static void rollback_token(void)
1070{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001071 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001072}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001073
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001074static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001075{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001076 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001077
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001078 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001079 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001080 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001081 return n;
1082}
1083
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001084static node *mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001085{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001086 n->info = OC_REGEXP;
1087 n->l.re = re;
1088 n->r.ire = re + 1;
1089 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001090 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001091
1092 return n;
1093}
1094
Mike Frysinger10a11e22005-09-27 02:23:02 +00001095static node *condition(void)
1096{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001097 next_token(TC_SEQSTART);
1098 return parse_expr(TC_SEQTERM);
1099}
1100
1101/* parse expression terminated by given argument, return ptr
1102 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001103static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001104{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001105 node sn;
1106 node *cn = &sn;
1107 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001108 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001109 var *v;
1110
1111 sn.info = PRIMASK;
1112 sn.r.n = glptr = NULL;
1113 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1114
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001115 while (!((tc = next_token(xtc)) & iexp)) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001116 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001117 /* input redirection (<) attached to glptr node */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001118 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001119 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001120 xtc = TC_OPERAND | TC_UOPPRE;
1121 glptr = NULL;
1122
1123 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1124 /* for binary and postfix-unary operators, jump back over
1125 * previous operators with higher priority */
1126 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001127 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1128 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) )
Glenn L McGrath545106f2002-11-11 06:21:00 +00001129 vn = vn->a.n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001130 if ((t_info & OPCLSMASK) == OC_TERNARY)
1131 t_info += P(6);
1132 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001133 cn->a.n = vn->a.n;
1134 if (tc & TC_BINOP) {
1135 cn->l.n = vn;
1136 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001137 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001138 /* it's a pipe */
1139 next_token(TC_GETLINE);
1140 /* give maximum priority to this pipe */
1141 cn->info &= ~PRIMASK;
1142 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1143 }
1144 } else {
1145 cn->r.n = vn;
1146 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1147 }
1148 vn->a.n = cn;
1149
1150 } else {
1151 /* for operands and prefix-unary operators, attach them
1152 * to last node */
1153 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001154 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001155 cn->a.n = vn;
1156 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1157 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001158 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001159 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001160 * only simple tclasses should be used! */
1161 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001162 case TC_VARIABLE:
1163 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001164 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001165 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001166 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001167 cn->info = OC_FNARG;
1168 cn->l.i = v->x.aidx;
1169 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001170 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001171 }
1172 if (tc & TC_ARRAY) {
1173 cn->info |= xS;
1174 cn->r.n = parse_expr(TC_ARRTERM);
1175 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001176 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001177
Denis Vlasenkof782f522007-01-01 23:51:30 +00001178 case TC_NUMBER:
1179 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001180 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001181 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001182 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001183 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001184 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001185 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001186 break;
1187
Denis Vlasenkof782f522007-01-01 23:51:30 +00001188 case TC_REGEXP:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001189 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001190 break;
1191
Denis Vlasenkof782f522007-01-01 23:51:30 +00001192 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001193 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001194 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001195 cn->l.n = condition();
1196 break;
1197
Denis Vlasenkof782f522007-01-01 23:51:30 +00001198 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001199 cn = vn->r.n = parse_expr(TC_SEQTERM);
1200 cn->a.n = vn;
1201 break;
1202
Denis Vlasenkof782f522007-01-01 23:51:30 +00001203 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001204 glptr = cn;
1205 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1206 break;
1207
Denis Vlasenkof782f522007-01-01 23:51:30 +00001208 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001209 cn->l.n = condition();
1210 break;
1211 }
1212 }
1213 }
1214 }
1215 return sn.r.n;
1216}
1217
1218/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001219static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001220{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001221 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001222
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001223 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001224 seq->first = seq->last = new_node(0);
1225
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001226 if (seq->programname != g_progname) {
1227 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001228 n = chain_node(OC_NEWSOURCE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001229 n->l.s = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001230 }
1231
1232 n = seq->last;
1233 n->info = info;
1234 seq->last = n->a.n = new_node(OC_DONE);
1235
1236 return n;
1237}
1238
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001239static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001240{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001241 node *n;
1242
1243 n = chain_node(info);
1244 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001245 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001246 rollback_token();
1247}
1248
Mike Frysinger10a11e22005-09-27 02:23:02 +00001249static node *chain_loop(node *nn)
1250{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001251 node *n, *n2, *save_brk, *save_cont;
1252
1253 save_brk = break_ptr;
1254 save_cont = continue_ptr;
1255
1256 n = chain_node(OC_BR | Vx);
1257 continue_ptr = new_node(OC_EXEC);
1258 break_ptr = new_node(OC_EXEC);
1259 chain_group();
1260 n2 = chain_node(OC_EXEC | Vx);
1261 n2->l.n = nn;
1262 n2->a.n = n;
1263 continue_ptr->a.n = n2;
1264 break_ptr->a.n = n->r.n = seq->last;
1265
1266 continue_ptr = save_cont;
1267 break_ptr = save_brk;
1268
1269 return n;
1270}
1271
1272/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001273static void chain_group(void)
1274{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001275 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001276 node *n, *n2, *n3;
1277
1278 do {
1279 c = next_token(TC_GRPSEQ);
1280 } while (c & TC_NEWLINE);
1281
1282 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001283 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001284 if (t_tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001285 rollback_token();
1286 chain_group();
1287 }
1288 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1289 rollback_token();
1290 chain_expr(OC_EXEC | Vx);
1291 } else { /* TC_STATEMNT */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001292 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001293 case ST_IF:
1294 n = chain_node(OC_BR | Vx);
1295 n->l.n = condition();
1296 chain_group();
1297 n2 = chain_node(OC_EXEC);
1298 n->r.n = seq->last;
1299 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001300 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001301 n2->a.n = seq->last;
1302 } else {
1303 rollback_token();
1304 }
1305 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001306
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001307 case ST_WHILE:
1308 n2 = condition();
1309 n = chain_loop(NULL);
1310 n->l.n = n2;
1311 break;
1312
1313 case ST_DO:
1314 n2 = chain_node(OC_EXEC);
1315 n = chain_loop(NULL);
1316 n2->a.n = n->a.n;
1317 next_token(TC_WHILE);
1318 n->l.n = condition();
1319 break;
1320
1321 case ST_FOR:
1322 next_token(TC_SEQSTART);
1323 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001324 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001325 if ((n2->info & OPCLSMASK) != OC_IN)
1326 syntax_error(EMSG_UNEXP_TOKEN);
1327 n = chain_node(OC_WALKINIT | VV);
1328 n->l.n = n2->l.n;
1329 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001330 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001331 n->info = OC_WALKNEXT | Vx;
1332 n->l.n = n2->l.n;
1333 } else { /* for (;;) */
1334 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001335 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001336 n2 = parse_expr(TC_SEMICOL);
1337 n3 = parse_expr(TC_SEQTERM);
1338 n = chain_loop(n3);
1339 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001340 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001341 n->info = OC_EXEC;
1342 }
1343 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001344
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001345 case OC_PRINT:
1346 case OC_PRINTF:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001347 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001348 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001349 if (t_tclass & TC_OUTRDR) {
1350 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001351 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1352 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001353 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001354 rollback_token();
1355 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001356
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001357 case OC_BREAK:
1358 n = chain_node(OC_EXEC);
1359 n->a.n = break_ptr;
1360 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001361
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001362 case OC_CONTINUE:
1363 n = chain_node(OC_EXEC);
1364 n->a.n = continue_ptr;
1365 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001366
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001367 /* delete, next, nextfile, return, exit */
1368 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001369 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001370 }
1371 }
1372}
1373
Mike Frysinger10a11e22005-09-27 02:23:02 +00001374static void parse_program(char *p)
1375{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001376 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001377 node *cn;
1378 func *f;
1379 var *v;
1380
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001381 g_pos = p;
1382 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001383 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001384 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001385
1386 if (tclass & TC_OPTERM)
1387 continue;
1388
1389 seq = &mainseq;
1390 if (tclass & TC_BEGIN) {
1391 seq = &beginseq;
1392 chain_group();
1393
1394 } else if (tclass & TC_END) {
1395 seq = &endseq;
1396 chain_group();
1397
1398 } else if (tclass & TC_FUNCDECL) {
1399 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001400 g_pos++;
1401 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001402 f->body.first = NULL;
1403 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001404 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001405 v = findvar(ahash, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001406 v->x.aidx = (f->nargs)++;
1407
1408 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1409 break;
1410 }
1411 seq = &(f->body);
1412 chain_group();
1413 clear_array(ahash);
1414
1415 } else if (tclass & TC_OPSEQ) {
1416 rollback_token();
1417 cn = chain_node(OC_TEST);
1418 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001419 if (t_tclass & TC_GRPSTART) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001420 rollback_token();
1421 chain_group();
1422 } else {
1423 chain_node(OC_PRINT);
1424 }
1425 cn->r.n = mainseq.last;
1426
1427 } else /* if (tclass & TC_GRPSTART) */ {
1428 rollback_token();
1429 chain_group();
1430 }
1431 }
1432}
1433
1434
1435/* -------- program execution part -------- */
1436
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001437static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001438{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001439 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001440 node *n;
1441
1442 re = &spl->re[0];
1443 ire = &spl->re[1];
1444 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001445 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001446 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001447 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001448 }
Rob Landleya3896512006-05-07 20:20:34 +00001449 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001450 mk_re_node(s, n, re);
1451 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001452 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001453 }
1454
1455 return n;
1456}
1457
1458/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001459 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001460 * be later regfree'd manually
1461 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001462static regex_t *as_regex(node *op, regex_t *preg)
1463{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001464 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001465 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001466
1467 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1468 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001469 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001470 v = nvalloc(1);
1471 s = getvar_s(evaluate(op, v));
1472 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1473 nvfree(v);
1474 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001475}
1476
1477/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001478static void qrealloc(char **b, int n, int *size)
1479{
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001480 if (!*b || n >= *size)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001481 *b = xrealloc(*b, *size = n + (n>>1) + 80);
1482}
1483
1484/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001485static void fsrealloc(int size)
1486{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001487 int i;
1488
1489 if (size >= maxfields) {
1490 i = maxfields;
1491 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001492 Fields = xrealloc(Fields, maxfields * sizeof(var));
1493 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001494 Fields[i].type = VF_SPECIAL;
1495 Fields[i].string = NULL;
1496 }
1497 }
1498
1499 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001500 for (i = size; i < nfields; i++) {
1501 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001502 }
1503 }
1504 nfields = size;
1505}
1506
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001507static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001508{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001509 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001510 char c[4];
1511 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001512 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001513
1514 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001515 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1516 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001517
1518 c[0] = c[1] = (char)spl->info;
1519 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001520 if (*getvar_s(intvar[RS]) == '\0')
1521 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001522
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001523 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1524 if (!*s)
1525 return n; /* "": zero fields */
1526 n++; /* at least one field will be there */
1527 do {
1528 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001529 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1530 && pmatch[0].rm_so <= l
1531 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001532 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001533 if (pmatch[0].rm_eo == 0) {
1534 l++;
1535 pmatch[0].rm_eo++;
1536 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001537 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001538 } else {
1539 pmatch[0].rm_eo = l;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001540 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001541 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001542 memcpy(s1, s, l);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001543 s1[l] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001544 nextword(&s1);
1545 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001546 } while (*s);
1547 return n;
1548 }
1549 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001550 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001551 *s1++ = *s++;
1552 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001553 n++;
1554 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001555 return n;
1556 }
1557 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001558 if (icase) {
1559 c[0] = toupper(c[0]);
1560 c[1] = tolower(c[1]);
1561 }
1562 if (*s1) n++;
1563 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001564 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001565 n++;
1566 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001567 return n;
1568 }
1569 /* space split */
1570 while (*s) {
1571 s = skip_whitespace(s);
1572 if (!*s) break;
1573 n++;
1574 while (*s && !isspace(*s))
1575 *s1++ = *s++;
1576 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001577 }
1578 return n;
1579}
1580
Mike Frysinger10a11e22005-09-27 02:23:02 +00001581static void split_f0(void)
1582{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001583/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001584#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001585
Glenn L McGrath545106f2002-11-11 06:21:00 +00001586 int i, n;
1587 char *s;
1588
1589 if (is_f0_split)
1590 return;
1591
1592 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001593 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001594 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001595 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001596 fsrealloc(n);
1597 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001598 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001599 Fields[i].string = nextword(&s);
1600 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1601 }
1602
1603 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001604 clrvar(intvar[NF]);
1605 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1606 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001607#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001608}
1609
1610/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001611static void handle_special(var *v)
1612{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001613 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001614 char *b;
1615 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001616 int sl, l, len, i, bsize;
1617
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001618 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001619 return;
1620
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001621 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001622 n = (int)getvar_i(v);
1623 fsrealloc(n);
1624
1625 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001626 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001627 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001628 b = NULL;
1629 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001630 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001631 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001632 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001633 if (b) {
1634 memcpy(b+len, sep, sl);
1635 len += sl;
1636 }
1637 qrealloc(&b, len+l+sl, &bsize);
1638 memcpy(b+len, s, l);
1639 len += l;
1640 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001641 if (b)
1642 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001643 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001644 is_f0_split = TRUE;
1645
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001646 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001647 is_f0_split = FALSE;
1648
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001649 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001650 mk_splitter(getvar_s(v), &fsplitter);
1651
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001652 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001653 mk_splitter(getvar_s(v), &rsplitter);
1654
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001655 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001656 icase = istrue(v);
1657
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001658 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001659 n = getvar_i(intvar[NF]);
1660 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001661 /* right here v is invalid. Just to note... */
1662 }
1663}
1664
1665/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001666static node *nextarg(node **pn)
1667{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001668 node *n;
1669
1670 n = *pn;
1671 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1672 *pn = n->r.n;
1673 n = n->l.n;
1674 } else {
1675 *pn = NULL;
1676 }
1677 return n;
1678}
1679
Mike Frysinger10a11e22005-09-27 02:23:02 +00001680static void hashwalk_init(var *v, xhash *array)
1681{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001682 char **w;
1683 hash_item *hi;
1684 int i;
1685
1686 if (v->type & VF_WALK)
1687 free(v->x.walker);
1688
1689 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001690 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001691 w[0] = w[1] = (char *)(w + 2);
1692 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001693 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001694 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001695 strcpy(*w, hi->name);
1696 nextword(w);
1697 hi = hi->next;
1698 }
1699 }
1700}
1701
Mike Frysinger10a11e22005-09-27 02:23:02 +00001702static int hashwalk_next(var *v)
1703{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001704 char **w;
1705
1706 w = v->x.walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001707 if (w[1] == w[0])
Glenn L McGrath545106f2002-11-11 06:21:00 +00001708 return FALSE;
1709
1710 setvar_s(v, nextword(w+1));
1711 return TRUE;
1712}
1713
1714/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001715static int ptest(node *pattern)
1716{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001717 /* ptest__v is "static": to save stack space? */
1718 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001719}
1720
1721/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001722static int awk_getline(rstream *rsm, var *v)
1723{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001724 char *b;
1725 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001726 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001727 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001728 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001729
1730 /* we're using our own buffer since we need access to accumulating
1731 * characters
1732 */
1733 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001734 m = rsm->buffer;
1735 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001736 p = rsm->pos;
1737 size = rsm->size;
1738 c = (char) rsplitter.n.info;
1739 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001740
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001741 if (!m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001742 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001743 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001744 so = eo = p;
1745 r = 1;
1746 if (p > 0) {
1747 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1748 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001749 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001750 so = pmatch[0].rm_so;
1751 eo = pmatch[0].rm_eo;
1752 if (b[eo] != '\0')
1753 break;
1754 }
1755 } else if (c != '\0') {
1756 s = strchr(b+pp, c);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001757 if (!s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001758 if (s) {
1759 so = eo = s-b;
1760 eo++;
1761 break;
1762 }
1763 } else {
1764 while (b[rp] == '\n')
1765 rp++;
1766 s = strstr(b+rp, "\n\n");
1767 if (s) {
1768 so = eo = s-b;
1769 while (b[eo] == '\n') eo++;
1770 if (b[eo] != '\0')
1771 break;
1772 }
1773 }
1774 }
1775
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001776 if (a > 0) {
1777 memmove(m, (const void *)(m+a), p+1);
1778 b = m;
1779 a = 0;
1780 }
1781
1782 qrealloc(&m, a+p+128, &size);
1783 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001784 pp = p;
1785 p += safe_read(fd, b+p, size-p-1);
1786 if (p < pp) {
1787 p = 0;
1788 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001789 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001790 }
1791 b[p] = '\0';
1792
1793 } while (p > pp);
1794
1795 if (p == 0) {
1796 r--;
1797 } else {
1798 c = b[so]; b[so] = '\0';
1799 setvar_s(v, b+rp);
1800 v->type |= VF_USER;
1801 b[so] = c;
1802 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001803 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001804 b[eo] = c;
1805 }
1806
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001807 rsm->buffer = m;
1808 rsm->adv = a + eo;
1809 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001810 rsm->size = size;
1811
1812 return r;
1813}
1814
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001815static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001816{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001817 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001818 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001819 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001820
1821 if (int_as_int && n == (int)n) {
1822 r = snprintf(b, size, "%d", (int)n);
1823 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001824 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001825 if (strchr("diouxX", c)) {
1826 r = snprintf(b, size, format, (int)n);
1827 } else if (strchr("eEfgG", c)) {
1828 r = snprintf(b, size, format, n);
1829 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001830 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001831 }
1832 }
1833 return r;
1834}
1835
1836
1837/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001838static char *awk_printf(node *n)
1839{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001840 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001841 char *fmt, *s, *f;
1842 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001843 int i, j, incr, bsize;
1844 char c, c1;
1845 var *v, *arg;
1846
1847 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001848 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001849
1850 i = 0;
1851 while (*f) {
1852 s = f;
1853 while (*f && (*f != '%' || *(++f) == '%'))
1854 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001855 while (*f && !isalpha(*f)) {
1856 if (*f == '*')
1857 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001858 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001859 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001860
1861 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001862 qrealloc(&b, incr + i, &bsize);
1863 c = *f;
1864 if (c != '\0') f++;
1865 c1 = *f;
1866 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001867 arg = evaluate(nextarg(&n), v);
1868
1869 j = i;
1870 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001871 i += sprintf(b+i, s, is_numeric(arg) ?
1872 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001873 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001874 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001875 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001876 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001877 } else {
1878 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1879 }
1880 *f = c1;
1881
1882 /* if there was an error while sprintf, return value is negative */
1883 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001884 }
1885
Denis Vlasenkof782f522007-01-01 23:51:30 +00001886 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001887 free(fmt);
1888 nvfree(v);
1889 b[i] = '\0';
1890 return b;
1891}
1892
1893/* common substitution routine
1894 * replace (nm) substring of (src) that match (n) with (repl), store
1895 * result into (dest), return number of substitutions. If nm=0, replace
1896 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1897 * subexpression matching (\1-\9)
1898 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001899static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001900{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001901 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001902 const char *s;
1903 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001904 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1905 regmatch_t pmatch[10];
1906 regex_t sreg, *re;
1907
1908 re = as_regex(rn, &sreg);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001909 if (!src) src = intvar[F0];
1910 if (!dest) dest = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001911
1912 i = di = 0;
1913 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001914 rl = strlen(repl);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001915 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001916 so = pmatch[0].rm_so;
1917 eo = pmatch[0].rm_eo;
1918
1919 qrealloc(&ds, di + eo + rl, &dssize);
1920 memcpy(ds + di, sp, eo);
1921 di += eo;
1922 if (++i >= nm) {
1923 /* replace */
1924 di -= (eo - so);
1925 nbs = 0;
1926 for (s = repl; *s; s++) {
1927 ds[di++] = c = *s;
1928 if (c == '\\') {
1929 nbs++;
1930 continue;
1931 }
1932 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1933 di -= ((nbs + 3) >> 1);
1934 j = 0;
1935 if (c != '&') {
1936 j = c - '0';
1937 nbs++;
1938 }
1939 if (nbs % 2) {
1940 ds[di++] = c;
1941 } else {
1942 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1943 qrealloc(&ds, di + rl + n, &dssize);
1944 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1945 di += n;
1946 }
1947 }
1948 nbs = 0;
1949 }
1950 }
1951
1952 sp += eo;
1953 if (i == nm) break;
1954 if (eo == so) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001955 ds[di] = *sp++;
1956 if (!ds[di++]) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001957 }
1958 }
1959
1960 qrealloc(&ds, di + strlen(sp), &dssize);
1961 strcpy(ds + di, sp);
1962 setvar_p(dest, ds);
1963 if (re == &sreg) regfree(re);
1964 return i;
1965}
1966
Mike Frysinger10a11e22005-09-27 02:23:02 +00001967static var *exec_builtin(node *op, var *res)
1968{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001969#define tspl (G.exec_builtin__tspl)
1970
Glenn L McGrath545106f2002-11-11 06:21:00 +00001971 int (*to_xxx)(int);
1972 var *tv;
1973 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001974 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001975 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001976 regmatch_t pmatch[2];
1977 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001978 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001979 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001980 int nargs;
1981 time_t tt;
1982 char *s, *s1;
1983 int i, l, ll, n;
1984
1985 tv = nvalloc(4);
1986 isr = info = op->info;
1987 op = op->l.n;
1988
1989 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001990 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001991 an[i] = nextarg(&op);
1992 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
1993 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
1994 isr >>= 1;
1995 }
1996
1997 nargs = i;
1998 if (nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001999 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002000
2001 switch (info & OPNMASK) {
2002
Denis Vlasenkof782f522007-01-01 23:51:30 +00002003 case B_a2:
2004#if ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +00002005 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
2006#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002007 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002008#endif
2009 break;
2010
Denis Vlasenkof782f522007-01-01 23:51:30 +00002011 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002012 if (nargs > 2) {
2013 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2014 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2015 } else {
2016 spl = &fsplitter.n;
2017 }
2018
2019 n = awk_split(as[0], spl, &s);
2020 s1 = s;
2021 clear_array(iamarray(av[1]));
2022 for (i=1; i<=n; i++)
2023 setari_u(av[1], i, nextword(&s1));
2024 free(s);
2025 setvar_i(res, n);
2026 break;
2027
Denis Vlasenkof782f522007-01-01 23:51:30 +00002028 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00002029 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002030 i = getvar_i(av[1]) - 1;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002031 if (i > l) i = l;
2032 if (i < 0) i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002033 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002034 if (n < 0) n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002035 s = xmalloc(n+1);
2036 strncpy(s, as[0]+i, n);
2037 s[n] = '\0';
2038 setvar_p(res, s);
2039 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002040
Denis Vlasenkof782f522007-01-01 23:51:30 +00002041 case B_an:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002042 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
2043 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002044
Denis Vlasenkof782f522007-01-01 23:51:30 +00002045 case B_co:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002046 setvar_i(res, ~(long)getvar_i(av[0]));
2047 break;
2048
Denis Vlasenkof782f522007-01-01 23:51:30 +00002049 case B_ls:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002050 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
2051 break;
2052
Denis Vlasenkof782f522007-01-01 23:51:30 +00002053 case B_or:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002054 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
2055 break;
2056
Denis Vlasenkof782f522007-01-01 23:51:30 +00002057 case B_rs:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002058 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
2059 break;
2060
Denis Vlasenkof782f522007-01-01 23:51:30 +00002061 case B_xo:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002062 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
2063 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002064
Denis Vlasenkof782f522007-01-01 23:51:30 +00002065 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002066 to_xxx = tolower;
2067 goto lo_cont;
2068
Denis Vlasenkof782f522007-01-01 23:51:30 +00002069 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002070 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002071 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00002072 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002073 while (*s1) {
2074 *s1 = (*to_xxx)(*s1);
2075 s1++;
2076 }
2077 setvar_p(res, s);
2078 break;
2079
Denis Vlasenkof782f522007-01-01 23:51:30 +00002080 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002081 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002082 ll = strlen(as[1]);
2083 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002084 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002085 if (!icase) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002086 s = strstr(as[0], as[1]);
2087 if (s) n = (s - as[0]) + 1;
2088 } else {
2089 /* this piece of code is terribly slow and
2090 * really should be rewritten
2091 */
2092 for (i=0; i<=l; i++) {
2093 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2094 n = i+1;
2095 break;
2096 }
2097 }
2098 }
2099 }
2100 setvar_i(res, n);
2101 break;
2102
Denis Vlasenkof782f522007-01-01 23:51:30 +00002103 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002104 if (nargs > 1)
2105 tt = getvar_i(av[1]);
2106 else
2107 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002108 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002109 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002110 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2111 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002112 g_buf[i] = '\0';
2113 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002114 break;
2115
Denis Vlasenkof782f522007-01-01 23:51:30 +00002116 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002117 re = as_regex(an[1], &sreg);
2118 n = regexec(re, as[0], 1, pmatch, 0);
2119 if (n == 0) {
2120 pmatch[0].rm_so++;
2121 pmatch[0].rm_eo++;
2122 } else {
2123 pmatch[0].rm_so = 0;
2124 pmatch[0].rm_eo = -1;
2125 }
2126 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2127 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2128 setvar_i(res, pmatch[0].rm_so);
2129 if (re == &sreg) regfree(re);
2130 break;
2131
Denis Vlasenkof782f522007-01-01 23:51:30 +00002132 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002133 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2134 break;
2135
Denis Vlasenkof782f522007-01-01 23:51:30 +00002136 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002137 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2138 break;
2139
Denis Vlasenkof782f522007-01-01 23:51:30 +00002140 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002141 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2142 break;
2143 }
2144
2145 nvfree(tv);
2146 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002147#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002148}
2149
2150/*
2151 * Evaluate node - the heart of the program. Supplied with subtree
2152 * and place where to store result. returns ptr to result.
2153 */
2154#define XC(n) ((n) >> 8)
2155
Mike Frysinger10a11e22005-09-27 02:23:02 +00002156static var *evaluate(node *op, var *res)
2157{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002158/* This procedure is recursive so we should count every byte */
2159#define fnargs (G.evaluate__fnargs)
2160/* seed is initialized to 1 */
2161#define seed (G.evaluate__seed)
2162#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002163
Glenn L McGrath545106f2002-11-11 06:21:00 +00002164 node *op1;
2165 var *v1;
2166 union {
2167 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002168 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002169 double d;
2170 int i;
2171 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002172 uint32_t opinfo;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002173 int opn;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002174 union {
2175 char *s;
2176 rstream *rsm;
2177 FILE *F;
2178 var *v;
2179 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002180 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002181 } X;
2182
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002183 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002184 return setvar_s(res, NULL);
2185
2186 v1 = nvalloc(2);
2187
2188 while (op) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002189 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002190 opn = (opinfo & OPNMASK);
2191 g_lineno = op->lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002192
Mike Frysingerde2b9382005-09-27 03:18:00 +00002193 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002194 op1 = op->l.n;
2195 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2196 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2197 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2198 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2199 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2200
2201 switch (XC(opinfo & OPCLSMASK)) {
2202
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002203 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002204
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002205 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002206 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002207 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2208 /* it's range pattern */
2209 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2210 op->info |= OF_CHECKED;
2211 if (ptest(op1->r.n))
2212 op->info &= ~OF_CHECKED;
2213
2214 op = op->a.n;
2215 } else {
2216 op = op->r.n;
2217 }
2218 } else {
2219 op = (ptest(op1)) ? op->a.n : op->r.n;
2220 }
2221 break;
2222
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002223 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002224 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002225 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002226
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002227 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002228 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002229 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002230 break;
2231
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002232 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002233 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002234 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002235 break;
2236
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002237 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002238 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002239 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2240 break;
2241
Denis Vlasenkof782f522007-01-01 23:51:30 +00002242 case XC( OC_PRINT ):
2243 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002244 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002245 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002246 X.rsm = newfile(R.s);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002247 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002248 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002249 X.rsm->F = popen(R.s, "w");
2250 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002251 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002252 X.rsm->is_pipe = 1;
2253 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002254 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002255 }
2256 }
2257 X.F = X.rsm->F;
2258 }
2259
2260 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002261 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002262 fputs(getvar_s(intvar[F0]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002263 } else {
2264 while (op1) {
2265 L.v = evaluate(nextarg(&op1), v1);
2266 if (L.v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002267 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002268 getvar_i(L.v), TRUE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002269 fputs(g_buf, X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002270 } else {
2271 fputs(getvar_s(L.v), X.F);
2272 }
2273
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002274 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002275 }
2276 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002277 fputs(getvar_s(intvar[ORS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002278
2279 } else { /* OC_PRINTF */
2280 L.s = awk_printf(op1);
2281 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002282 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002283 }
2284 fflush(X.F);
2285 break;
2286
Denis Vlasenkof782f522007-01-01 23:51:30 +00002287 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002288 X.info = op1->info & OPCLSMASK;
2289 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002290 R.v = op1->l.v;
2291 } else if (X.info == OC_FNARG) {
2292 R.v = &fnargs[op1->l.i];
2293 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002294 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002295 }
2296
Mike Frysingerde2b9382005-09-27 03:18:00 +00002297 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002298 clrvar(L.v);
2299 L.s = getvar_s(evaluate(op1->r.n, v1));
2300 hash_remove(iamarray(R.v), L.s);
2301 } else {
2302 clear_array(iamarray(R.v));
2303 }
2304 break;
2305
Denis Vlasenkof782f522007-01-01 23:51:30 +00002306 case XC( OC_NEWSOURCE ):
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002307 g_progname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002308 break;
2309
Denis Vlasenkof782f522007-01-01 23:51:30 +00002310 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002311 copyvar(res, L.v);
2312 break;
2313
Denis Vlasenkof782f522007-01-01 23:51:30 +00002314 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002315 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002316 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002317 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002318 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002319 clrvar(res);
2320 break;
2321
Denis Vlasenkof782f522007-01-01 23:51:30 +00002322 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002323 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002324
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002325 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002326
Denis Vlasenkof782f522007-01-01 23:51:30 +00002327 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002328 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002329 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002330 split_f0();
2331 goto v_cont;
2332
Denis Vlasenkof782f522007-01-01 23:51:30 +00002333 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002334 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002335 v_cont:
2336 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002337 break;
2338
Denis Vlasenkof782f522007-01-01 23:51:30 +00002339 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002340 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2341 break;
2342
Denis Vlasenkof782f522007-01-01 23:51:30 +00002343 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002344 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002345 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002346 goto re_cont;
2347
Denis Vlasenkof782f522007-01-01 23:51:30 +00002348 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002349 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002350 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002351 X.re = as_regex(op1, &sreg);
2352 R.i = regexec(X.re, L.s, 0, NULL, 0);
2353 if (X.re == &sreg) regfree(X.re);
2354 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2355 break;
2356
Denis Vlasenkof782f522007-01-01 23:51:30 +00002357 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002358 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002359 if (R.v == v1+1 && R.v->string) {
2360 res = setvar_p(L.v, R.v->string);
2361 R.v->string = NULL;
2362 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002363 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002364 }
2365 break;
2366
Denis Vlasenkof782f522007-01-01 23:51:30 +00002367 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002368 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002369 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002370 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2371 break;
2372
Denis Vlasenkof782f522007-01-01 23:51:30 +00002373 case XC( OC_FUNC ):
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002374 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002375 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002376
2377 X.v = R.v = nvalloc(op->r.f->nargs+1);
2378 while (op1) {
2379 L.v = evaluate(nextarg(&op1), v1);
2380 copyvar(R.v, L.v);
2381 R.v->type |= VF_CHILD;
2382 R.v->x.parent = L.v;
2383 if (++R.v - X.v >= op->r.f->nargs)
2384 break;
2385 }
2386
2387 R.v = fnargs;
2388 fnargs = X.v;
2389
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002390 L.s = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002391 res = evaluate(op->r.f->body.first, res);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002392 g_progname = L.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002393
2394 nvfree(fnargs);
2395 fnargs = R.v;
2396 break;
2397
Denis Vlasenkof782f522007-01-01 23:51:30 +00002398 case XC( OC_GETLINE ):
2399 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002400 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002401 X.rsm = newfile(L.s);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002402 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002403 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2404 X.rsm->F = popen(L.s, "r");
2405 X.rsm->is_pipe = TRUE;
2406 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002407 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002408 }
2409 }
2410 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002411 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002412 X.rsm = iF;
2413 }
2414
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002415 if (!X.rsm->F) {
2416 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002417 setvar_i(res, -1);
2418 break;
2419 }
2420
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002421 if (!op->r.n)
2422 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002423
2424 L.i = awk_getline(X.rsm, R.v);
2425 if (L.i > 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002426 if (!op1) {
2427 incvar(intvar[FNR]);
2428 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002429 }
2430 }
2431 setvar_i(res, L.i);
2432 break;
2433
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002434 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002435 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002436 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002437
Denis Vlasenkof782f522007-01-01 23:51:30 +00002438 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002439 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002440 break;
2441
Denis Vlasenkof782f522007-01-01 23:51:30 +00002442 case F_rn:
2443 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002444 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002445#if ENABLE_FEATURE_AWK_MATH
2446 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002447 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002448 break;
2449
Denis Vlasenkof782f522007-01-01 23:51:30 +00002450 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002451 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002452 break;
2453
Denis Vlasenkof782f522007-01-01 23:51:30 +00002454 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002455 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002456 break;
2457
Denis Vlasenkof782f522007-01-01 23:51:30 +00002458 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002459 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002460 break;
2461
Denis Vlasenkof782f522007-01-01 23:51:30 +00002462 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002463 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002464 break;
2465#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002466 case F_co:
2467 case F_ex:
2468 case F_lg:
2469 case F_si:
2470 case F_sq:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002471 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002472 break;
2473#endif
Denis Vlasenkof782f522007-01-01 23:51:30 +00002474 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002475 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002476 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002477 srand(seed);
2478 break;
2479
Denis Vlasenkof782f522007-01-01 23:51:30 +00002480 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002481 R.d = time(NULL);
2482 break;
2483
Denis Vlasenkof782f522007-01-01 23:51:30 +00002484 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002485 if (!op1)
2486 L.s = getvar_s(intvar[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002487 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002488 break;
2489
Denis Vlasenkof782f522007-01-01 23:51:30 +00002490 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002491 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002492 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2493 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002494 break;
2495
Denis Vlasenkof782f522007-01-01 23:51:30 +00002496 case F_ff:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002497 if (!op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002498 fflush(stdout);
2499 else {
2500 if (L.s && *L.s) {
2501 X.rsm = newfile(L.s);
2502 fflush(X.rsm->F);
2503 } else {
2504 fflush(NULL);
2505 }
2506 }
2507 break;
2508
Denis Vlasenkof782f522007-01-01 23:51:30 +00002509 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002510 X.rsm = (rstream *)hash_search(fdhash, L.s);
2511 if (X.rsm) {
2512 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002513 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002514 hash_remove(fdhash, L.s);
2515 }
2516 if (R.i != 0)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002517 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002518 R.d = (double)R.i;
2519 break;
2520 }
2521 setvar_i(res, R.d);
2522 break;
2523
Denis Vlasenkof782f522007-01-01 23:51:30 +00002524 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002525 res = exec_builtin(op, res);
2526 break;
2527
Denis Vlasenkof782f522007-01-01 23:51:30 +00002528 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002529 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002530 break;
2531
Denis Vlasenkof782f522007-01-01 23:51:30 +00002532 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002533 X.v = R.v;
2534 L.d = R.d = getvar_i(R.v);
2535 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002536 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002537 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002538 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002539 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002540 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002541 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002542 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002543 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002544 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002545 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002546 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002547 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002548 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002549 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002550 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002551 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002552 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002553 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002554 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002555 setvar_i(X.v, R.d);
2556 }
2557 setvar_i(res, L.d);
2558 break;
2559
Denis Vlasenkof782f522007-01-01 23:51:30 +00002560 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002561 R.i = (int)getvar_i(R.v);
2562 if (R.i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002563 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002564 } else {
2565 split_f0();
2566 if (R.i > nfields)
2567 fsrealloc(R.i);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002568 res = &Fields[R.i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002569 }
2570 break;
2571
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002572 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002573 case XC( OC_CONCAT ):
2574 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002575 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002576 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002577 strcpy(X.s, L.s);
2578 if ((opinfo & OPCLSMASK) == OC_COMMA) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002579 L.s = getvar_s(intvar[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002580 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002581 strcat(X.s, L.s);
2582 }
2583 strcat(X.s, R.s);
2584 setvar_p(res, X.s);
2585 break;
2586
Denis Vlasenkof782f522007-01-01 23:51:30 +00002587 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002588 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2589 break;
2590
Denis Vlasenkof782f522007-01-01 23:51:30 +00002591 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002592 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2593 break;
2594
Denis Vlasenkof782f522007-01-01 23:51:30 +00002595 case XC( OC_BINARY ):
2596 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002597 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002598 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002599 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002600 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002601 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002602 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002603 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002604 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002605 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002606 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002607 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002608 case '/':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002609 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002610 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002611 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002612 case '&':
2613#if ENABLE_FEATURE_AWK_MATH
Mike Frysingerde2b9382005-09-27 03:18:00 +00002614 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002615#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002616 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002617#endif
2618 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002619 case '%':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002620 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002621 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002622 break;
2623 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002624 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002625 break;
2626
Denis Vlasenkof782f522007-01-01 23:51:30 +00002627 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002628 if (is_numeric(L.v) && is_numeric(R.v)) {
2629 L.d = getvar_i(L.v) - getvar_i(R.v);
2630 } else {
2631 L.s = getvar_s(L.v);
2632 R.s = getvar_s(R.v);
2633 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2634 }
2635 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002636 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002637 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002638 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002639 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002640 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002641 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002642 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002643 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002644 break;
2645 }
2646 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2647 break;
2648
Denis Vlasenkof782f522007-01-01 23:51:30 +00002649 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002650 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002651 }
2652 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2653 op = op->a.n;
2654 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2655 break;
2656 if (nextrec)
2657 break;
2658 }
2659 nvfree(v1);
2660 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002661#undef fnargs
2662#undef seed
2663#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002664}
2665
2666
2667/* -------- main & co. -------- */
2668
Mike Frysinger10a11e22005-09-27 02:23:02 +00002669static int awk_exit(int r)
2670{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002671 var tv;
2672 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002673 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002674
Denis Vlasenkof782f522007-01-01 23:51:30 +00002675 zero_out_var(&tv);
2676
2677 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002678 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002679 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002680 evaluate(endseq.first, &tv);
2681 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002682
2683 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002684 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002685 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002686 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002687 if (hi->data.rs.F && hi->data.rs.is_pipe)
2688 pclose(hi->data.rs.F);
2689 hi = hi->next;
2690 }
2691 }
2692
2693 exit(r);
2694}
2695
2696/* if expr looks like "var=value", perform assignment and return 1,
2697 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002698static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002699{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002700 char *exprc, *s, *s0, *s1;
2701
Rob Landleyd921b2e2006-08-03 15:41:12 +00002702 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002703 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2704 free(exprc);
2705 return FALSE;
2706 }
2707
2708 *(s++) = '\0';
2709 s0 = s1 = s;
2710 while (*s)
2711 *(s1++) = nextchar(&s);
2712
2713 *s1 = '\0';
2714 setvar_u(newvar(exprc), s0);
2715 free(exprc);
2716 return TRUE;
2717}
2718
2719/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002720static rstream *next_input_file(void)
2721{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002722#define rsm (G.next_input_file__rsm)
2723#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002724
Glenn L McGrath545106f2002-11-11 06:21:00 +00002725 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002726 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002727
2728 if (rsm.F) fclose(rsm.F);
2729 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002730 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002731
2732 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002733 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002734 if (files_happen)
2735 return NULL;
2736 fname = "-";
2737 F = stdin;
2738 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002739 ind = getvar_s(incvar(intvar[ARGIND]));
2740 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002741 if (fname && *fname && !is_assignment(fname))
2742 F = afopen(fname, "r");
2743 }
2744 } while (!F);
2745
2746 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002747 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002748 rsm.F = F;
2749 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002750#undef rsm
2751#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002752}
2753
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002754int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00002755int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002756{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002757 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002758 char *opt_F, *opt_W;
2759 llist_t *opt_v = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002760 int i, j, flen;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002761 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002762 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002763 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002764 char *vnames = (char *)vNames; /* cheat */
2765 char *vvalues = (char *)vValues;
2766
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002767 INIT_G();
2768
Denis Vlasenko150f4022007-01-13 21:06:21 +00002769 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002770 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2771 if (ENABLE_LOCALE_SUPPORT)
2772 setlocale(LC_NUMERIC, "C");
2773
Denis Vlasenkof782f522007-01-01 23:51:30 +00002774 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002775
2776 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002777 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002778
2779 vhash = hash_init();
2780 ahash = hash_init();
2781 fdhash = hash_init();
2782 fnhash = hash_init();
2783
2784 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002785 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002786 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00002787 if (*vvalues != '\377')
2788 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002789 else
2790 setvar_i(v, 0);
2791
Denis Vlasenkof782f522007-01-01 23:51:30 +00002792 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002793 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002794 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002795 }
2796 }
2797
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002798 handle_special(intvar[FS]);
2799 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002800
Denis Vlasenkof782f522007-01-01 23:51:30 +00002801 newfile("/dev/stdin")->F = stdin;
2802 newfile("/dev/stdout")->F = stdout;
2803 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002804
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002805 /* Huh, people report that sometimes environ is NULL. Oh well. */
2806 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002807 /* environ is writable, thus we don't strdup it needlessly */
2808 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002809 char *s1 = strchr(s, '=');
2810 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002811 *s1 = '\0';
2812 /* Both findvar and setvar_u take const char*
2813 * as 2nd arg -> environment is not trashed */
2814 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
2815 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00002816 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002817 }
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002818 opt_complementary = "v::";
Denis Vlasenkofe7cd642007-08-18 15:32:12 +00002819 opt = getopt32(argv, "F:v:f:W:", &opt_F, &opt_v, &g_progname, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002820 argv += optind;
2821 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002822 if (opt & 0x1)
2823 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002824 while (opt_v) { /* -v */
2825 if (!is_assignment(llist_pop(&opt_v)))
2826 bb_show_usage();
2827 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002828 if (opt & 0x4) { // -f
Denis Vlasenkof782f522007-01-01 23:51:30 +00002829 char *s = s; /* die, gcc, die */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002830 FILE *from_file = afopen(g_progname, "r");
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002831 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002832 if (fseek(from_file, 0, SEEK_END) == 0) {
2833 flen = ftell(from_file);
2834 s = xmalloc(flen + 4);
2835 fseek(from_file, 0, SEEK_SET);
2836 i = 1 + fread(s + 1, 1, flen, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002837 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002838 for (i = j = 1; j > 0; i += j) {
2839 s = xrealloc(s, i + 4096);
2840 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002841 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002842 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002843 s[i] = '\0';
Denis Vlasenkof782f522007-01-01 23:51:30 +00002844 fclose(from_file);
2845 parse_program(s + 1);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002846 free(s);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002847 } else { // no -f: take program from 1st parameter
2848 if (!argc)
2849 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002850 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00002851 parse_program(*argv++);
2852 argc--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002853 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002854 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002855 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002856
Glenn L McGrath545106f2002-11-11 06:21:00 +00002857 /* fill in ARGV array */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002858 setvar_i(intvar[ARGC], argc + 1);
2859 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002860 i = 0;
2861 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002862 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002863
2864 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002865 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002866 awk_exit(EXIT_SUCCESS);
2867
2868 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002869 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002870
2871 /* passing through input files */
2872 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002873 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002874 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002875
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002876 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002877 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002878 incvar(intvar[NR]);
2879 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002880 evaluate(mainseq.first, &tv);
2881
2882 if (nextfile)
2883 break;
2884 }
2885
Denis Vlasenkof782f522007-01-01 23:51:30 +00002886 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002887 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002888
2889 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002890 }
2891
Glenn L McGrath545106f2002-11-11 06:21:00 +00002892 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002893 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002894}