blob: bdf2a7fa0d5f47bf05d02676b910dfee087765a2 [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 Vlasenko574f2f42008-02-27 18:41:59 +0000397 chain beginseq, mainseq, endseq;
398 chain *seq;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000399 node *break_ptr, *continue_ptr;
400 rstream *iF;
401 xhash *vhash, *ahash, *fdhash, *fnhash;
402 const char *g_progname;
403 int g_lineno;
404 int nfields;
405 int maxfields; /* used in fsrealloc() only */
406 var *Fields;
407 nvblock *g_cb;
408 char *g_pos;
409 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000410 smallint icase;
411 smallint exiting;
412 smallint nextrec;
413 smallint nextfile;
414 smallint is_f0_split;
415};
416struct globals2 {
417 uint32_t t_info; /* often used */
418 uint32_t t_tclass;
419 char *t_string;
420 int t_lineno;
421 int t_rollback;
422
423 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000424
425 /* former statics from various functions */
426 char *split_f0__fstrings;
427
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000428 uint32_t next_token__save_tclass;
429 uint32_t next_token__save_info;
430 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000431 smallint next_token__concat_inserted;
432
433 smallint next_input_file__files_happen;
434 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000435
436 var *evaluate__fnargs;
437 unsigned evaluate__seed;
438 regex_t evaluate__sreg;
439
440 var ptest__v;
441
442 tsplitter exec_builtin__tspl;
443
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000444 /* biggest and least used members go last */
445 double t_double;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000446 tsplitter fsplitter, rsplitter;
447};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000448#define G1 (ptr_to_globals[-1])
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000449#define G (*(struct globals2 *)ptr_to_globals)
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000450/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
451/* char G1size[sizeof(G1)]; - 0x6c */
452/* char Gsize[sizeof(G)]; - 0x1cc */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000453/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000454/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
455#define beginseq (G1.beginseq )
456#define mainseq (G1.mainseq )
457#define endseq (G1.endseq )
458#define seq (G1.seq )
459#define break_ptr (G1.break_ptr )
460#define continue_ptr (G1.continue_ptr)
461#define iF (G1.iF )
462#define vhash (G1.vhash )
463#define ahash (G1.ahash )
464#define fdhash (G1.fdhash )
465#define fnhash (G1.fnhash )
466#define g_progname (G1.g_progname )
467#define g_lineno (G1.g_lineno )
468#define nfields (G1.nfields )
469#define maxfields (G1.maxfields )
470#define Fields (G1.Fields )
471#define g_cb (G1.g_cb )
472#define g_pos (G1.g_pos )
473#define g_buf (G1.g_buf )
474#define icase (G1.icase )
475#define exiting (G1.exiting )
476#define nextrec (G1.nextrec )
477#define nextfile (G1.nextfile )
478#define is_f0_split (G1.is_f0_split )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000479#define t_info (G.t_info )
480#define t_tclass (G.t_tclass )
481#define t_string (G.t_string )
482#define t_double (G.t_double )
483#define t_lineno (G.t_lineno )
484#define t_rollback (G.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000485#define intvar (G.intvar )
486#define fsplitter (G.fsplitter )
487#define rsplitter (G.rsplitter )
488#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000489 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1)); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000490 G.next_token__ltclass = TC_OPTERM; \
491 G.evaluate__seed = 1; \
492} while (0)
493
Glenn L McGrath545106f2002-11-11 06:21:00 +0000494
495/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000496static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000497static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000498static void chain_group(void);
499static var *evaluate(node *, var *);
500static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000501static int fmt_num(char *, int, const char *, double, int);
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000502static int awk_exit(int) NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000503
504/* ---- error handling ---- */
505
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000506static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
507static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
508static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
509static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
510static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
511static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
512static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
513static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
514static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
Denis Vlasenkof782f522007-01-01 23:51:30 +0000515#if !ENABLE_FEATURE_AWK_MATH
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000516static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000517#endif
518
Denis Vlasenkof782f522007-01-01 23:51:30 +0000519static void zero_out_var(var * vp)
520{
521 memset(vp, 0, sizeof(*vp));
522}
523
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000524static void syntax_error(const char *const message) NORETURN;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000525static void syntax_error(const char *const message)
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000526{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000527 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000528}
529
Glenn L McGrath545106f2002-11-11 06:21:00 +0000530/* ---- hash stuff ---- */
531
Denis Vlasenkof782f522007-01-01 23:51:30 +0000532static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000533{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000534 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000535
Denis Vlasenkof782f522007-01-01 23:51:30 +0000536 while (*name) idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000537 return idx;
538}
539
540/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000541static xhash *hash_init(void)
542{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000543 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000544
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000545 newhash = xzalloc(sizeof(xhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000546 newhash->csize = FIRST_PRIME;
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000547 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000548
549 return newhash;
550}
551
552/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000553static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000554{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000555 hash_item *hi;
556
557 hi = hash->items [ hashidx(name) % hash->csize ];
558 while (hi) {
559 if (strcmp(hi->name, name) == 0)
560 return &(hi->data);
561 hi = hi->next;
562 }
563 return NULL;
564}
565
566/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000567static void hash_rebuild(xhash *hash)
568{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000569 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000570 hash_item **newitems, *hi, *thi;
571
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000572 if (hash->nprime == ARRAY_SIZE(PRIMES))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000573 return;
574
575 newsize = PRIMES[hash->nprime++];
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000576 newitems = xzalloc(newsize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000577
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000578 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000579 hi = hash->items[i];
580 while (hi) {
581 thi = hi;
582 hi = thi->next;
583 idx = hashidx(thi->name) % newsize;
584 thi->next = newitems[idx];
585 newitems[idx] = thi;
586 }
587 }
588
589 free(hash->items);
590 hash->csize = newsize;
591 hash->items = newitems;
592}
593
594/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000595static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000596{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000597 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000598 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000599 int l;
600
601 hi = hash_search(hash, name);
Denis Vlasenkob78c7822007-07-18 18:31:11 +0000602 if (!hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000603 if (++hash->nel / hash->csize > 10)
604 hash_rebuild(hash);
605
Rob Landleya3896512006-05-07 20:20:34 +0000606 l = strlen(name) + 1;
Rob Landley9ffd4232006-05-21 18:30:35 +0000607 hi = xzalloc(sizeof(hash_item) + l);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000608 memcpy(hi->name, name, l);
609
610 idx = hashidx(name) % hash->csize;
611 hi->next = hash->items[idx];
612 hash->items[idx] = hi;
613 hash->glen += l;
614 }
615 return &(hi->data);
616}
617
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000618#define findvar(hash, name) ((var*) hash_find((hash), (name)))
619#define newvar(name) ((var*) hash_find(vhash, (name)))
620#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
621#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000622
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000623static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000624{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000625 hash_item *hi, **phi;
626
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000627 phi = &(hash->items[hashidx(name) % hash->csize]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000628 while (*phi) {
629 hi = *phi;
630 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000631 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000632 hash->nel--;
633 *phi = hi->next;
634 free(hi);
635 break;
636 }
637 phi = &(hi->next);
638 }
639}
640
641/* ------ some useful functions ------ */
642
Mike Frysinger10a11e22005-09-27 02:23:02 +0000643static void skip_spaces(char **s)
644{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000645 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000646
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000647 while (1) {
648 if (*p == '\\' && p[1] == '\n') {
649 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000650 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000651 } else if (*p != ' ' && *p != '\t') {
652 break;
653 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000654 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000655 }
656 *s = p;
657}
658
Mike Frysinger10a11e22005-09-27 02:23:02 +0000659static char *nextword(char **s)
660{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000661 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000662
Denis Vlasenkof782f522007-01-01 23:51:30 +0000663 while (*(*s)++) /* */;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000664
665 return p;
666}
667
Mike Frysinger10a11e22005-09-27 02:23:02 +0000668static char nextchar(char **s)
669{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000670 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000671
672 c = *((*s)++);
673 pps = *s;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000674 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000675 if (c == '\\' && *s == pps) c = *((*s)++);
676 return c;
677}
678
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000679static ALWAYS_INLINE int isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000680{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000681 return (isalnum(c) || c == '_');
682}
683
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000684static double my_strtod(char **pp)
685{
686#if ENABLE_DESKTOP
687 if ((*pp)[0] == '0'
688 && ((((*pp)[1] | 0x20) == 'x') || isdigit((*pp)[1]))
689 ) {
690 return strtoull(*pp, pp, 0);
691 }
692#endif
693 return strtod(*pp, pp);
694}
695
Glenn L McGrath545106f2002-11-11 06:21:00 +0000696/* -------- working with variables (set/get/copy/etc) -------- */
697
Mike Frysinger10a11e22005-09-27 02:23:02 +0000698static xhash *iamarray(var *v)
699{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000700 var *a = v;
701
702 while (a->type & VF_CHILD)
703 a = a->x.parent;
704
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000705 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000706 a->type |= VF_ARRAY;
707 a->x.array = hash_init();
708 }
709 return a->x.array;
710}
711
Mike Frysinger10a11e22005-09-27 02:23:02 +0000712static void clear_array(xhash *array)
713{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000714 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000715 hash_item *hi, *thi;
716
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000717 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000718 hi = array->items[i];
719 while (hi) {
720 thi = hi;
721 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000722 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000723 free(thi);
724 }
725 array->items[i] = NULL;
726 }
727 array->glen = array->nel = 0;
728}
729
730/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000731static var *clrvar(var *v)
732{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000733 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000734 free(v->string);
735
736 v->type &= VF_DONTTOUCH;
737 v->type |= VF_DIRTY;
738 v->string = NULL;
739 return v;
740}
741
742/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000743static var *setvar_p(var *v, char *value)
744{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000745 clrvar(v);
746 v->string = value;
747 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000748 return v;
749}
750
751/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000752static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000753{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000754 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000755}
756
757/* same as setvar_s but set USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000758static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000759{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000760 setvar_s(v, value);
761 v->type |= VF_USER;
762 return v;
763}
764
765/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000766static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000767{
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000768 char sidx[sizeof(int)*3 + 1];
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000769 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000770
771 sprintf(sidx, "%d", idx);
772 v = findvar(iamarray(a), sidx);
773 setvar_u(v, s);
774}
775
776/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000777static var *setvar_i(var *v, double value)
778{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000779 clrvar(v);
780 v->type |= VF_NUMBER;
781 v->number = value;
782 handle_special(v);
783 return v;
784}
785
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000786static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000787{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000788 /* if v is numeric and has no cached string, convert it to string */
789 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000790 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
791 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000792 v->type |= VF_CACHED;
793 }
794 return (v->string == NULL) ? "" : v->string;
795}
796
Mike Frysinger10a11e22005-09-27 02:23:02 +0000797static double getvar_i(var *v)
798{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000799 char *s;
800
801 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
802 v->number = 0;
803 s = v->string;
804 if (s && *s) {
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000805 v->number = my_strtod(&s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000806 if (v->type & VF_USER) {
807 skip_spaces(&s);
808 if (*s != '\0')
809 v->type &= ~VF_USER;
810 }
811 } else {
812 v->type &= ~VF_USER;
813 }
814 v->type |= VF_CACHED;
815 }
816 return v->number;
817}
818
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000819/* Used for operands of bitwise ops */
820static unsigned long getvar_i_int(var *v)
821{
822 double d = getvar_i(v);
823
824 /* Casting doubles to longs is undefined for values outside
825 * of target type range. Try to widen it as much as possible */
826 if (d >= 0)
827 return (unsigned long)d;
Denis Vlasenko665eaff2008-09-05 04:59:02 +0000828 /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000829 return - (long) (unsigned long) (-d);
830}
831
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000832static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000833{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000834 if (dest != src) {
835 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000836 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000837 dest->number = src->number;
838 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000839 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000840 }
841 handle_special(dest);
842 return dest;
843}
844
Mike Frysinger10a11e22005-09-27 02:23:02 +0000845static var *incvar(var *v)
846{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000847 return setvar_i(v, getvar_i(v) + 1.);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000848}
849
850/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000851static int is_numeric(var *v)
852{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000853 getvar_i(v);
854 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
855}
856
857/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000858static int istrue(var *v)
859{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000860 if (is_numeric(v))
861 return (v->number == 0) ? 0 : 1;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000862 return (v->string && *(v->string)) ? 1 : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000863}
864
Eric Andersenaff114c2004-04-14 17:51:38 +0000865/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000866static var *nvalloc(int n)
867{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000868 nvblock *pb = NULL;
869 var *v, *r;
870 int size;
871
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000872 while (g_cb) {
873 pb = g_cb;
874 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break;
875 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000876 }
877
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000878 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000879 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000880 g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000881 g_cb->size = size;
882 g_cb->pos = g_cb->nv;
883 g_cb->prev = pb;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000884 /*g_cb->next = NULL; - xzalloc did it */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000885 if (pb) pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000886 }
887
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000888 v = r = g_cb->pos;
889 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000890
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000891 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000892 v->type = 0;
893 v->string = NULL;
894 v++;
895 }
896
897 return r;
898}
899
Mike Frysinger10a11e22005-09-27 02:23:02 +0000900static void nvfree(var *v)
901{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000902 var *p;
903
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000904 if (v < g_cb->nv || v >= g_cb->pos)
905 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000906
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000907 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000908 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000909 clear_array(iamarray(p));
910 free(p->x.array->items);
911 free(p->x.array);
912 }
913 if (p->type & VF_WALK)
914 free(p->x.walker);
915
916 clrvar(p);
917 }
918
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000919 g_cb->pos = v;
920 while (g_cb->prev && g_cb->pos == g_cb->nv) {
921 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000922 }
923}
924
925/* ------- awk program text parsing ------- */
926
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000927/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000928 * If token isn't expected, give away. Return token class
929 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000930static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000931{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000932#define concat_inserted (G.next_token__concat_inserted)
933#define save_tclass (G.next_token__save_tclass)
934#define save_info (G.next_token__save_info)
935/* Initialized to TC_OPTERM: */
936#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000937
Denis Vlasenkof782f522007-01-01 23:51:30 +0000938 char *p, *pp, *s;
939 const char *tl;
940 uint32_t tc;
941 const uint32_t *ti;
942 int l;
943
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000944 if (t_rollback) {
945 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000946
947 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000948 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000949 t_tclass = save_tclass;
950 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000951
952 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000953 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000954 readnext:
Glenn L McGrath545106f2002-11-11 06:21:00 +0000955 skip_spaces(&p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000956 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000957 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000958 while (*p != '\n' && *p != '\0')
959 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000960
961 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000962 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000963
964 if (*p == '\0') {
965 tc = TC_EOF;
966
967 } else if (*p == '\"') {
968 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000969 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000970 while (*p != '\"') {
971 if (*p == '\0' || *p == '\n')
972 syntax_error(EMSG_UNEXP_EOS);
973 *(s++) = nextchar(&p);
974 }
975 p++;
976 *s = '\0';
977 tc = TC_STRING;
978
979 } else if ((expected & TC_REGEXP) && *p == '/') {
980 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000981 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000982 while (*p != '/') {
983 if (*p == '\0' || *p == '\n')
984 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +0000985 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000986 if (*s++ == '\\') {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000987 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000988 *(s-1) = bb_process_escape_sequence((const char **)&p);
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000989 if (*pp == '\\')
990 *s++ = '\\';
991 if (p == pp)
992 *s++ = *p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000993 }
994 }
995 p++;
996 *s = '\0';
997 tc = TC_REGEXP;
998
999 } else if (*p == '.' || isdigit(*p)) {
1000 /* it's a number */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00001001 t_double = my_strtod(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001002 if (*p == '.')
1003 syntax_error(EMSG_UNEXP_TOKEN);
1004 tc = TC_NUMBER;
1005
1006 } else {
1007 /* search for something known */
1008 tl = tokenlist;
1009 tc = 0x00000001;
1010 ti = tokeninfo;
1011 while (*tl) {
1012 l = *(tl++);
1013 if (l == NTCC) {
1014 tc <<= 1;
1015 continue;
1016 }
1017 /* if token class is expected, token
1018 * matches and it's not a longer word,
1019 * then this is what we are looking for
1020 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001021 if ((tc & (expected | TC_WORD | TC_NEWLINE))
1022 && *tl == *p && strncmp(p, tl, l) == 0
1023 && !((tc & TC_WORD) && isalnum_(p[l]))
1024 ) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001025 t_info = *ti;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001026 p += l;
1027 break;
1028 }
1029 ti++;
1030 tl += l;
1031 }
1032
Denis Vlasenkof782f522007-01-01 23:51:30 +00001033 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001034 /* it's a name (var/array/function),
1035 * otherwise it's something wrong
1036 */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001037 if (!isalnum_(*p))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001038 syntax_error(EMSG_UNEXP_TOKEN);
1039
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001040 t_string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001041 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001042 *(p-1) = *p;
1043 }
1044 *(p-1) = '\0';
1045 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +00001046 /* also consume whitespace between functionname and bracket */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001047 if (!(expected & TC_VARIABLE))
1048 skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001049 if (*p == '(') {
1050 tc = TC_FUNCTION;
1051 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001052 if (*p == '[') {
1053 p++;
1054 tc = TC_ARRAY;
1055 }
1056 }
1057 }
1058 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001059 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001060
1061 /* skipping newlines in some cases */
1062 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1063 goto readnext;
1064
1065 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001066 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001067 concat_inserted = TRUE;
1068 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001069 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001070 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001071 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001072 }
1073
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001074 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001075 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001076 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001077
1078 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001079 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001080 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001081 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001082
1083 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001084#undef concat_inserted
1085#undef save_tclass
1086#undef save_info
1087#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001088}
1089
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001090static void rollback_token(void)
1091{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001092 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001093}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001094
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001095static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001096{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001097 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001098
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001099 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001100 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001101 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001102 return n;
1103}
1104
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001105static node *mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001106{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001107 n->info = OC_REGEXP;
1108 n->l.re = re;
1109 n->r.ire = re + 1;
1110 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001111 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001112
1113 return n;
1114}
1115
Mike Frysinger10a11e22005-09-27 02:23:02 +00001116static node *condition(void)
1117{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001118 next_token(TC_SEQSTART);
1119 return parse_expr(TC_SEQTERM);
1120}
1121
1122/* parse expression terminated by given argument, return ptr
1123 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001124static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001125{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001126 node sn;
1127 node *cn = &sn;
1128 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001129 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001130 var *v;
1131
1132 sn.info = PRIMASK;
1133 sn.r.n = glptr = NULL;
1134 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1135
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001136 while (!((tc = next_token(xtc)) & iexp)) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001137 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001138 /* input redirection (<) attached to glptr node */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001139 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001140 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001141 xtc = TC_OPERAND | TC_UOPPRE;
1142 glptr = NULL;
1143
1144 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1145 /* for binary and postfix-unary operators, jump back over
1146 * previous operators with higher priority */
1147 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001148 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1149 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) )
Glenn L McGrath545106f2002-11-11 06:21:00 +00001150 vn = vn->a.n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001151 if ((t_info & OPCLSMASK) == OC_TERNARY)
1152 t_info += P(6);
1153 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001154 cn->a.n = vn->a.n;
1155 if (tc & TC_BINOP) {
1156 cn->l.n = vn;
1157 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001158 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001159 /* it's a pipe */
1160 next_token(TC_GETLINE);
1161 /* give maximum priority to this pipe */
1162 cn->info &= ~PRIMASK;
1163 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1164 }
1165 } else {
1166 cn->r.n = vn;
1167 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1168 }
1169 vn->a.n = cn;
1170
1171 } else {
1172 /* for operands and prefix-unary operators, attach them
1173 * to last node */
1174 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001175 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001176 cn->a.n = vn;
1177 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1178 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001179 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001180 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001181 * only simple tclasses should be used! */
1182 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001183 case TC_VARIABLE:
1184 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001185 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001186 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001187 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001188 cn->info = OC_FNARG;
1189 cn->l.i = v->x.aidx;
1190 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001191 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001192 }
1193 if (tc & TC_ARRAY) {
1194 cn->info |= xS;
1195 cn->r.n = parse_expr(TC_ARRTERM);
1196 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001197 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001198
Denis Vlasenkof782f522007-01-01 23:51:30 +00001199 case TC_NUMBER:
1200 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001201 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001202 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001203 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001204 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001205 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001206 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001207 break;
1208
Denis Vlasenkof782f522007-01-01 23:51:30 +00001209 case TC_REGEXP:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001210 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001211 break;
1212
Denis Vlasenkof782f522007-01-01 23:51:30 +00001213 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001214 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001215 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001216 cn->l.n = condition();
1217 break;
1218
Denis Vlasenkof782f522007-01-01 23:51:30 +00001219 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001220 cn = vn->r.n = parse_expr(TC_SEQTERM);
1221 cn->a.n = vn;
1222 break;
1223
Denis Vlasenkof782f522007-01-01 23:51:30 +00001224 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001225 glptr = cn;
1226 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1227 break;
1228
Denis Vlasenkof782f522007-01-01 23:51:30 +00001229 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001230 cn->l.n = condition();
1231 break;
1232 }
1233 }
1234 }
1235 }
1236 return sn.r.n;
1237}
1238
1239/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001240static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001241{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001242 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001243
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001244 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001245 seq->first = seq->last = new_node(0);
1246
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001247 if (seq->programname != g_progname) {
1248 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001249 n = chain_node(OC_NEWSOURCE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001250 n->l.s = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001251 }
1252
1253 n = seq->last;
1254 n->info = info;
1255 seq->last = n->a.n = new_node(OC_DONE);
1256
1257 return n;
1258}
1259
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001260static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001261{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001262 node *n;
1263
1264 n = chain_node(info);
1265 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001266 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001267 rollback_token();
1268}
1269
Mike Frysinger10a11e22005-09-27 02:23:02 +00001270static node *chain_loop(node *nn)
1271{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001272 node *n, *n2, *save_brk, *save_cont;
1273
1274 save_brk = break_ptr;
1275 save_cont = continue_ptr;
1276
1277 n = chain_node(OC_BR | Vx);
1278 continue_ptr = new_node(OC_EXEC);
1279 break_ptr = new_node(OC_EXEC);
1280 chain_group();
1281 n2 = chain_node(OC_EXEC | Vx);
1282 n2->l.n = nn;
1283 n2->a.n = n;
1284 continue_ptr->a.n = n2;
1285 break_ptr->a.n = n->r.n = seq->last;
1286
1287 continue_ptr = save_cont;
1288 break_ptr = save_brk;
1289
1290 return n;
1291}
1292
1293/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001294static void chain_group(void)
1295{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001296 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001297 node *n, *n2, *n3;
1298
1299 do {
1300 c = next_token(TC_GRPSEQ);
1301 } while (c & TC_NEWLINE);
1302
1303 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001304 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001305 if (t_tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001306 rollback_token();
1307 chain_group();
1308 }
1309 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1310 rollback_token();
1311 chain_expr(OC_EXEC | Vx);
1312 } else { /* TC_STATEMNT */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001313 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001314 case ST_IF:
1315 n = chain_node(OC_BR | Vx);
1316 n->l.n = condition();
1317 chain_group();
1318 n2 = chain_node(OC_EXEC);
1319 n->r.n = seq->last;
1320 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001321 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001322 n2->a.n = seq->last;
1323 } else {
1324 rollback_token();
1325 }
1326 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001327
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001328 case ST_WHILE:
1329 n2 = condition();
1330 n = chain_loop(NULL);
1331 n->l.n = n2;
1332 break;
1333
1334 case ST_DO:
1335 n2 = chain_node(OC_EXEC);
1336 n = chain_loop(NULL);
1337 n2->a.n = n->a.n;
1338 next_token(TC_WHILE);
1339 n->l.n = condition();
1340 break;
1341
1342 case ST_FOR:
1343 next_token(TC_SEQSTART);
1344 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001345 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001346 if ((n2->info & OPCLSMASK) != OC_IN)
1347 syntax_error(EMSG_UNEXP_TOKEN);
1348 n = chain_node(OC_WALKINIT | VV);
1349 n->l.n = n2->l.n;
1350 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001351 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001352 n->info = OC_WALKNEXT | Vx;
1353 n->l.n = n2->l.n;
1354 } else { /* for (;;) */
1355 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001356 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001357 n2 = parse_expr(TC_SEMICOL);
1358 n3 = parse_expr(TC_SEQTERM);
1359 n = chain_loop(n3);
1360 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001361 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001362 n->info = OC_EXEC;
1363 }
1364 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001365
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001366 case OC_PRINT:
1367 case OC_PRINTF:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001368 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001369 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001370 if (t_tclass & TC_OUTRDR) {
1371 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001372 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1373 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001374 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001375 rollback_token();
1376 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001377
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001378 case OC_BREAK:
1379 n = chain_node(OC_EXEC);
1380 n->a.n = break_ptr;
1381 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001382
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001383 case OC_CONTINUE:
1384 n = chain_node(OC_EXEC);
1385 n->a.n = continue_ptr;
1386 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001387
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001388 /* delete, next, nextfile, return, exit */
1389 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001390 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001391 }
1392 }
1393}
1394
Mike Frysinger10a11e22005-09-27 02:23:02 +00001395static void parse_program(char *p)
1396{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001397 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001398 node *cn;
1399 func *f;
1400 var *v;
1401
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001402 g_pos = p;
1403 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001404 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001405 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001406
1407 if (tclass & TC_OPTERM)
1408 continue;
1409
1410 seq = &mainseq;
1411 if (tclass & TC_BEGIN) {
1412 seq = &beginseq;
1413 chain_group();
1414
1415 } else if (tclass & TC_END) {
1416 seq = &endseq;
1417 chain_group();
1418
1419 } else if (tclass & TC_FUNCDECL) {
1420 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001421 g_pos++;
1422 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001423 f->body.first = NULL;
1424 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001425 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001426 v = findvar(ahash, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001427 v->x.aidx = (f->nargs)++;
1428
1429 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1430 break;
1431 }
1432 seq = &(f->body);
1433 chain_group();
1434 clear_array(ahash);
1435
1436 } else if (tclass & TC_OPSEQ) {
1437 rollback_token();
1438 cn = chain_node(OC_TEST);
1439 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001440 if (t_tclass & TC_GRPSTART) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001441 rollback_token();
1442 chain_group();
1443 } else {
1444 chain_node(OC_PRINT);
1445 }
1446 cn->r.n = mainseq.last;
1447
1448 } else /* if (tclass & TC_GRPSTART) */ {
1449 rollback_token();
1450 chain_group();
1451 }
1452 }
1453}
1454
1455
1456/* -------- program execution part -------- */
1457
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001458static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001459{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001460 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001461 node *n;
1462
1463 re = &spl->re[0];
1464 ire = &spl->re[1];
1465 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001466 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001467 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001468 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001469 }
Rob Landleya3896512006-05-07 20:20:34 +00001470 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001471 mk_re_node(s, n, re);
1472 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001473 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001474 }
1475
1476 return n;
1477}
1478
1479/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001480 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001481 * be later regfree'd manually
1482 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001483static regex_t *as_regex(node *op, regex_t *preg)
1484{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001485 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001486 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001487
1488 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1489 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001490 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001491 v = nvalloc(1);
1492 s = getvar_s(evaluate(op, v));
1493 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1494 nvfree(v);
1495 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001496}
1497
1498/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001499static void qrealloc(char **b, int n, int *size)
1500{
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001501 if (!*b || n >= *size) {
1502 *size = n + (n>>1) + 80;
1503 *b = xrealloc(*b, *size);
1504 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001505}
1506
1507/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001508static void fsrealloc(int size)
1509{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001510 int i;
1511
1512 if (size >= maxfields) {
1513 i = maxfields;
1514 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001515 Fields = xrealloc(Fields, maxfields * sizeof(var));
1516 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001517 Fields[i].type = VF_SPECIAL;
1518 Fields[i].string = NULL;
1519 }
1520 }
1521
1522 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001523 for (i = size; i < nfields; i++) {
1524 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001525 }
1526 }
1527 nfields = size;
1528}
1529
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001530static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001531{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001532 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001533 char c[4];
1534 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001535 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001536
1537 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001538 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1539 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001540
1541 c[0] = c[1] = (char)spl->info;
1542 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001543 if (*getvar_s(intvar[RS]) == '\0')
1544 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001545
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001546 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1547 if (!*s)
1548 return n; /* "": zero fields */
1549 n++; /* at least one field will be there */
1550 do {
1551 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001552 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1553 && pmatch[0].rm_so <= l
1554 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001555 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001556 if (pmatch[0].rm_eo == 0) {
1557 l++;
1558 pmatch[0].rm_eo++;
1559 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001560 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001561 } else {
1562 pmatch[0].rm_eo = l;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001563 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001564 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001565 memcpy(s1, s, l);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001566 s1[l] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001567 nextword(&s1);
1568 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001569 } while (*s);
1570 return n;
1571 }
1572 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001573 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001574 *s1++ = *s++;
1575 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001576 n++;
1577 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001578 return n;
1579 }
1580 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001581 if (icase) {
1582 c[0] = toupper(c[0]);
1583 c[1] = tolower(c[1]);
1584 }
1585 if (*s1) n++;
1586 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001587 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001588 n++;
1589 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001590 return n;
1591 }
1592 /* space split */
1593 while (*s) {
1594 s = skip_whitespace(s);
1595 if (!*s) break;
1596 n++;
1597 while (*s && !isspace(*s))
1598 *s1++ = *s++;
1599 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001600 }
1601 return n;
1602}
1603
Mike Frysinger10a11e22005-09-27 02:23:02 +00001604static void split_f0(void)
1605{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001606/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001607#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001608
Glenn L McGrath545106f2002-11-11 06:21:00 +00001609 int i, n;
1610 char *s;
1611
1612 if (is_f0_split)
1613 return;
1614
1615 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001616 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001617 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001618 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001619 fsrealloc(n);
1620 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001621 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001622 Fields[i].string = nextword(&s);
1623 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1624 }
1625
1626 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001627 clrvar(intvar[NF]);
1628 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1629 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001630#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001631}
1632
1633/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001634static void handle_special(var *v)
1635{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001636 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001637 char *b;
1638 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001639 int sl, l, len, i, bsize;
1640
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001641 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001642 return;
1643
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001644 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001645 n = (int)getvar_i(v);
1646 fsrealloc(n);
1647
1648 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001649 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001650 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001651 b = NULL;
1652 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001653 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001654 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001655 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001656 if (b) {
1657 memcpy(b+len, sep, sl);
1658 len += sl;
1659 }
1660 qrealloc(&b, len+l+sl, &bsize);
1661 memcpy(b+len, s, l);
1662 len += l;
1663 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001664 if (b)
1665 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001666 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001667 is_f0_split = TRUE;
1668
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001669 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001670 is_f0_split = FALSE;
1671
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001672 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001673 mk_splitter(getvar_s(v), &fsplitter);
1674
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001675 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001676 mk_splitter(getvar_s(v), &rsplitter);
1677
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001678 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001679 icase = istrue(v);
1680
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001681 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001682 n = getvar_i(intvar[NF]);
1683 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001684 /* right here v is invalid. Just to note... */
1685 }
1686}
1687
1688/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001689static node *nextarg(node **pn)
1690{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001691 node *n;
1692
1693 n = *pn;
1694 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1695 *pn = n->r.n;
1696 n = n->l.n;
1697 } else {
1698 *pn = NULL;
1699 }
1700 return n;
1701}
1702
Mike Frysinger10a11e22005-09-27 02:23:02 +00001703static void hashwalk_init(var *v, xhash *array)
1704{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001705 char **w;
1706 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001707 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001708
1709 if (v->type & VF_WALK)
1710 free(v->x.walker);
1711
1712 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001713 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001714 w[0] = w[1] = (char *)(w + 2);
1715 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001716 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001717 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001718 strcpy(*w, hi->name);
1719 nextword(w);
1720 hi = hi->next;
1721 }
1722 }
1723}
1724
Mike Frysinger10a11e22005-09-27 02:23:02 +00001725static int hashwalk_next(var *v)
1726{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001727 char **w;
1728
1729 w = v->x.walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001730 if (w[1] == w[0])
Glenn L McGrath545106f2002-11-11 06:21:00 +00001731 return FALSE;
1732
1733 setvar_s(v, nextword(w+1));
1734 return TRUE;
1735}
1736
1737/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001738static int ptest(node *pattern)
1739{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001740 /* ptest__v is "static": to save stack space? */
1741 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001742}
1743
1744/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001745static int awk_getline(rstream *rsm, var *v)
1746{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001747 char *b;
1748 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001749 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001750 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001751 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001752
1753 /* we're using our own buffer since we need access to accumulating
1754 * characters
1755 */
1756 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001757 m = rsm->buffer;
1758 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001759 p = rsm->pos;
1760 size = rsm->size;
1761 c = (char) rsplitter.n.info;
1762 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001763
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001764 if (!m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001765 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001766 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001767 so = eo = p;
1768 r = 1;
1769 if (p > 0) {
1770 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1771 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001772 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001773 so = pmatch[0].rm_so;
1774 eo = pmatch[0].rm_eo;
1775 if (b[eo] != '\0')
1776 break;
1777 }
1778 } else if (c != '\0') {
1779 s = strchr(b+pp, c);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001780 if (!s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001781 if (s) {
1782 so = eo = s-b;
1783 eo++;
1784 break;
1785 }
1786 } else {
1787 while (b[rp] == '\n')
1788 rp++;
1789 s = strstr(b+rp, "\n\n");
1790 if (s) {
1791 so = eo = s-b;
1792 while (b[eo] == '\n') eo++;
1793 if (b[eo] != '\0')
1794 break;
1795 }
1796 }
1797 }
1798
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001799 if (a > 0) {
1800 memmove(m, (const void *)(m+a), p+1);
1801 b = m;
1802 a = 0;
1803 }
1804
1805 qrealloc(&m, a+p+128, &size);
1806 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001807 pp = p;
1808 p += safe_read(fd, b+p, size-p-1);
1809 if (p < pp) {
1810 p = 0;
1811 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001812 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001813 }
1814 b[p] = '\0';
1815
1816 } while (p > pp);
1817
1818 if (p == 0) {
1819 r--;
1820 } else {
1821 c = b[so]; b[so] = '\0';
1822 setvar_s(v, b+rp);
1823 v->type |= VF_USER;
1824 b[so] = c;
1825 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001826 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001827 b[eo] = c;
1828 }
1829
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001830 rsm->buffer = m;
1831 rsm->adv = a + eo;
1832 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001833 rsm->size = size;
1834
1835 return r;
1836}
1837
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001838static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001839{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001840 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001841 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001842 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001843
1844 if (int_as_int && n == (int)n) {
1845 r = snprintf(b, size, "%d", (int)n);
1846 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001847 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001848 if (strchr("diouxX", c)) {
1849 r = snprintf(b, size, format, (int)n);
1850 } else if (strchr("eEfgG", c)) {
1851 r = snprintf(b, size, format, n);
1852 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001853 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001854 }
1855 }
1856 return r;
1857}
1858
1859
1860/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001861static char *awk_printf(node *n)
1862{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001863 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001864 char *fmt, *s, *f;
1865 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001866 int i, j, incr, bsize;
1867 char c, c1;
1868 var *v, *arg;
1869
1870 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001871 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001872
1873 i = 0;
1874 while (*f) {
1875 s = f;
1876 while (*f && (*f != '%' || *(++f) == '%'))
1877 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001878 while (*f && !isalpha(*f)) {
1879 if (*f == '*')
1880 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001881 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001882 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001883
1884 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001885 qrealloc(&b, incr + i, &bsize);
1886 c = *f;
1887 if (c != '\0') f++;
1888 c1 = *f;
1889 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001890 arg = evaluate(nextarg(&n), v);
1891
1892 j = i;
1893 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001894 i += sprintf(b+i, s, is_numeric(arg) ?
1895 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001896 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001897 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001898 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001899 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001900 } else {
1901 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1902 }
1903 *f = c1;
1904
1905 /* if there was an error while sprintf, return value is negative */
1906 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001907 }
1908
Denis Vlasenkof782f522007-01-01 23:51:30 +00001909 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001910 free(fmt);
1911 nvfree(v);
1912 b[i] = '\0';
1913 return b;
1914}
1915
1916/* common substitution routine
1917 * replace (nm) substring of (src) that match (n) with (repl), store
1918 * result into (dest), return number of substitutions. If nm=0, replace
1919 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1920 * subexpression matching (\1-\9)
1921 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001922static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001923{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001924 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001925 const char *s;
1926 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001927 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1928 regmatch_t pmatch[10];
1929 regex_t sreg, *re;
1930
1931 re = as_regex(rn, &sreg);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001932 if (!src) src = intvar[F0];
1933 if (!dest) dest = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001934
1935 i = di = 0;
1936 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001937 rl = strlen(repl);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001938 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001939 so = pmatch[0].rm_so;
1940 eo = pmatch[0].rm_eo;
1941
1942 qrealloc(&ds, di + eo + rl, &dssize);
1943 memcpy(ds + di, sp, eo);
1944 di += eo;
1945 if (++i >= nm) {
1946 /* replace */
1947 di -= (eo - so);
1948 nbs = 0;
1949 for (s = repl; *s; s++) {
1950 ds[di++] = c = *s;
1951 if (c == '\\') {
1952 nbs++;
1953 continue;
1954 }
1955 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1956 di -= ((nbs + 3) >> 1);
1957 j = 0;
1958 if (c != '&') {
1959 j = c - '0';
1960 nbs++;
1961 }
1962 if (nbs % 2) {
1963 ds[di++] = c;
1964 } else {
1965 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1966 qrealloc(&ds, di + rl + n, &dssize);
1967 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1968 di += n;
1969 }
1970 }
1971 nbs = 0;
1972 }
1973 }
1974
1975 sp += eo;
1976 if (i == nm) break;
1977 if (eo == so) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001978 ds[di] = *sp++;
1979 if (!ds[di++]) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001980 }
1981 }
1982
1983 qrealloc(&ds, di + strlen(sp), &dssize);
1984 strcpy(ds + di, sp);
1985 setvar_p(dest, ds);
1986 if (re == &sreg) regfree(re);
1987 return i;
1988}
1989
Mike Frysinger10a11e22005-09-27 02:23:02 +00001990static var *exec_builtin(node *op, var *res)
1991{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001992#define tspl (G.exec_builtin__tspl)
1993
Glenn L McGrath545106f2002-11-11 06:21:00 +00001994 int (*to_xxx)(int);
1995 var *tv;
1996 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001997 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001998 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001999 regmatch_t pmatch[2];
2000 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002001 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002002 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002003 int nargs;
2004 time_t tt;
2005 char *s, *s1;
2006 int i, l, ll, n;
2007
2008 tv = nvalloc(4);
2009 isr = info = op->info;
2010 op = op->l.n;
2011
2012 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002013 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002014 an[i] = nextarg(&op);
2015 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
2016 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
2017 isr >>= 1;
2018 }
2019
2020 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002021 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002022 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002023
2024 switch (info & OPNMASK) {
2025
Denis Vlasenkof782f522007-01-01 23:51:30 +00002026 case B_a2:
2027#if ENABLE_FEATURE_AWK_MATH
Denis Vlasenko37890e22008-10-21 12:59:34 +00002028 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002029#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002030 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002031#endif
2032 break;
2033
Denis Vlasenkof782f522007-01-01 23:51:30 +00002034 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002035 if (nargs > 2) {
2036 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2037 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2038 } else {
2039 spl = &fsplitter.n;
2040 }
2041
2042 n = awk_split(as[0], spl, &s);
2043 s1 = s;
2044 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002045 for (i = 1; i <= n; i++)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002046 setari_u(av[1], i, nextword(&s1));
2047 free(s);
2048 setvar_i(res, n);
2049 break;
2050
Denis Vlasenkof782f522007-01-01 23:51:30 +00002051 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00002052 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002053 i = getvar_i(av[1]) - 1;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002054 if (i > l) i = l;
2055 if (i < 0) i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002056 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002057 if (n < 0) n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002058 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002059 setvar_p(res, s);
2060 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002061
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002062 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2063 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002064 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002065 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002066 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002067
Denis Vlasenkof782f522007-01-01 23:51:30 +00002068 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002069 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002070 break;
2071
Denis Vlasenkof782f522007-01-01 23:51:30 +00002072 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002073 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002074 break;
2075
Denis Vlasenkof782f522007-01-01 23:51:30 +00002076 case B_or:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002077 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002078 break;
2079
Denis Vlasenkof782f522007-01-01 23:51:30 +00002080 case B_rs:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002081 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002082 break;
2083
Denis Vlasenkof782f522007-01-01 23:51:30 +00002084 case B_xo:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002085 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002086 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002087
Denis Vlasenkof782f522007-01-01 23:51:30 +00002088 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002089 to_xxx = tolower;
2090 goto lo_cont;
2091
Denis Vlasenkof782f522007-01-01 23:51:30 +00002092 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002093 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002094 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00002095 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002096 while (*s1) {
2097 *s1 = (*to_xxx)(*s1);
2098 s1++;
2099 }
2100 setvar_p(res, s);
2101 break;
2102
Denis Vlasenkof782f522007-01-01 23:51:30 +00002103 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002104 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002105 ll = strlen(as[1]);
2106 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002107 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002108 if (!icase) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002109 s = strstr(as[0], as[1]);
2110 if (s) n = (s - as[0]) + 1;
2111 } else {
2112 /* this piece of code is terribly slow and
2113 * really should be rewritten
2114 */
2115 for (i=0; i<=l; i++) {
2116 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2117 n = i+1;
2118 break;
2119 }
2120 }
2121 }
2122 }
2123 setvar_i(res, n);
2124 break;
2125
Denis Vlasenkof782f522007-01-01 23:51:30 +00002126 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002127 if (nargs > 1)
2128 tt = getvar_i(av[1]);
2129 else
2130 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002131 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002132 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002133 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2134 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002135 g_buf[i] = '\0';
2136 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002137 break;
2138
Denis Vlasenkof782f522007-01-01 23:51:30 +00002139 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002140 re = as_regex(an[1], &sreg);
2141 n = regexec(re, as[0], 1, pmatch, 0);
2142 if (n == 0) {
2143 pmatch[0].rm_so++;
2144 pmatch[0].rm_eo++;
2145 } else {
2146 pmatch[0].rm_so = 0;
2147 pmatch[0].rm_eo = -1;
2148 }
2149 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2150 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2151 setvar_i(res, pmatch[0].rm_so);
2152 if (re == &sreg) regfree(re);
2153 break;
2154
Denis Vlasenkof782f522007-01-01 23:51:30 +00002155 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002156 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2157 break;
2158
Denis Vlasenkof782f522007-01-01 23:51:30 +00002159 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002160 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2161 break;
2162
Denis Vlasenkof782f522007-01-01 23:51:30 +00002163 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002164 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2165 break;
2166 }
2167
2168 nvfree(tv);
2169 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002170#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002171}
2172
2173/*
2174 * Evaluate node - the heart of the program. Supplied with subtree
2175 * and place where to store result. returns ptr to result.
2176 */
2177#define XC(n) ((n) >> 8)
2178
Mike Frysinger10a11e22005-09-27 02:23:02 +00002179static var *evaluate(node *op, var *res)
2180{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002181/* This procedure is recursive so we should count every byte */
2182#define fnargs (G.evaluate__fnargs)
2183/* seed is initialized to 1 */
2184#define seed (G.evaluate__seed)
2185#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002186
Glenn L McGrath545106f2002-11-11 06:21:00 +00002187 node *op1;
2188 var *v1;
2189 union {
2190 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002191 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002192 double d;
2193 int i;
2194 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002195 uint32_t opinfo;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002196 int opn;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002197 union {
2198 char *s;
2199 rstream *rsm;
2200 FILE *F;
2201 var *v;
2202 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002203 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002204 } X;
2205
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002206 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002207 return setvar_s(res, NULL);
2208
2209 v1 = nvalloc(2);
2210
2211 while (op) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002212 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002213 opn = (opinfo & OPNMASK);
2214 g_lineno = op->lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002215
Mike Frysingerde2b9382005-09-27 03:18:00 +00002216 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002217 op1 = op->l.n;
2218 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2219 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2220 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2221 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2222 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2223
2224 switch (XC(opinfo & OPCLSMASK)) {
2225
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002226 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002227
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002228 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002229 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002230 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2231 /* it's range pattern */
2232 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2233 op->info |= OF_CHECKED;
2234 if (ptest(op1->r.n))
2235 op->info &= ~OF_CHECKED;
2236
2237 op = op->a.n;
2238 } else {
2239 op = op->r.n;
2240 }
2241 } else {
2242 op = (ptest(op1)) ? op->a.n : op->r.n;
2243 }
2244 break;
2245
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002246 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002247 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002248 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002249
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002250 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002251 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002252 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002253 break;
2254
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002255 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002256 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002257 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002258 break;
2259
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002260 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002261 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002262 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2263 break;
2264
Denis Vlasenkof782f522007-01-01 23:51:30 +00002265 case XC( OC_PRINT ):
2266 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002267 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002268 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002269 X.rsm = newfile(R.s);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002270 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002271 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002272 X.rsm->F = popen(R.s, "w");
2273 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002274 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002275 X.rsm->is_pipe = 1;
2276 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002277 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002278 }
2279 }
2280 X.F = X.rsm->F;
2281 }
2282
2283 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002284 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002285 fputs(getvar_s(intvar[F0]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002286 } else {
2287 while (op1) {
2288 L.v = evaluate(nextarg(&op1), v1);
2289 if (L.v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002290 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002291 getvar_i(L.v), TRUE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002292 fputs(g_buf, X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002293 } else {
2294 fputs(getvar_s(L.v), X.F);
2295 }
2296
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002297 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002298 }
2299 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002300 fputs(getvar_s(intvar[ORS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002301
2302 } else { /* OC_PRINTF */
2303 L.s = awk_printf(op1);
2304 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002305 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002306 }
2307 fflush(X.F);
2308 break;
2309
Denis Vlasenkof782f522007-01-01 23:51:30 +00002310 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002311 X.info = op1->info & OPCLSMASK;
2312 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002313 R.v = op1->l.v;
2314 } else if (X.info == OC_FNARG) {
2315 R.v = &fnargs[op1->l.i];
2316 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002317 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002318 }
2319
Mike Frysingerde2b9382005-09-27 03:18:00 +00002320 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002321 clrvar(L.v);
2322 L.s = getvar_s(evaluate(op1->r.n, v1));
2323 hash_remove(iamarray(R.v), L.s);
2324 } else {
2325 clear_array(iamarray(R.v));
2326 }
2327 break;
2328
Denis Vlasenkof782f522007-01-01 23:51:30 +00002329 case XC( OC_NEWSOURCE ):
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002330 g_progname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002331 break;
2332
Denis Vlasenkof782f522007-01-01 23:51:30 +00002333 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002334 copyvar(res, L.v);
2335 break;
2336
Denis Vlasenkof782f522007-01-01 23:51:30 +00002337 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002338 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002339 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002340 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002341 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002342 clrvar(res);
2343 break;
2344
Denis Vlasenkof782f522007-01-01 23:51:30 +00002345 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002346 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002347
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002348 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002349
Denis Vlasenkof782f522007-01-01 23:51:30 +00002350 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002351 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002352 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002353 split_f0();
2354 goto v_cont;
2355
Denis Vlasenkof782f522007-01-01 23:51:30 +00002356 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002357 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002358 v_cont:
2359 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002360 break;
2361
Denis Vlasenkof782f522007-01-01 23:51:30 +00002362 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002363 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2364 break;
2365
Denis Vlasenkof782f522007-01-01 23:51:30 +00002366 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002367 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002368 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002369 goto re_cont;
2370
Denis Vlasenkof782f522007-01-01 23:51:30 +00002371 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002372 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002373 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002374 X.re = as_regex(op1, &sreg);
2375 R.i = regexec(X.re, L.s, 0, NULL, 0);
2376 if (X.re == &sreg) regfree(X.re);
2377 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2378 break;
2379
Denis Vlasenkof782f522007-01-01 23:51:30 +00002380 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002381 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002382 if (R.v == v1+1 && R.v->string) {
2383 res = setvar_p(L.v, R.v->string);
2384 R.v->string = NULL;
2385 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002386 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002387 }
2388 break;
2389
Denis Vlasenkof782f522007-01-01 23:51:30 +00002390 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002391 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002392 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002393 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2394 break;
2395
Denis Vlasenkof782f522007-01-01 23:51:30 +00002396 case XC( OC_FUNC ):
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002397 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002398 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002399
2400 X.v = R.v = nvalloc(op->r.f->nargs+1);
2401 while (op1) {
2402 L.v = evaluate(nextarg(&op1), v1);
2403 copyvar(R.v, L.v);
2404 R.v->type |= VF_CHILD;
2405 R.v->x.parent = L.v;
2406 if (++R.v - X.v >= op->r.f->nargs)
2407 break;
2408 }
2409
2410 R.v = fnargs;
2411 fnargs = X.v;
2412
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002413 L.s = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002414 res = evaluate(op->r.f->body.first, res);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002415 g_progname = L.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002416
2417 nvfree(fnargs);
2418 fnargs = R.v;
2419 break;
2420
Denis Vlasenkof782f522007-01-01 23:51:30 +00002421 case XC( OC_GETLINE ):
2422 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002423 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002424 X.rsm = newfile(L.s);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002425 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002426 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2427 X.rsm->F = popen(L.s, "r");
2428 X.rsm->is_pipe = TRUE;
2429 } else {
Denis Vlasenko5415c852008-07-21 23:05:26 +00002430 X.rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002431 }
2432 }
2433 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002434 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002435 X.rsm = iF;
2436 }
2437
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002438 if (!X.rsm->F) {
2439 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002440 setvar_i(res, -1);
2441 break;
2442 }
2443
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002444 if (!op->r.n)
2445 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002446
2447 L.i = awk_getline(X.rsm, R.v);
2448 if (L.i > 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002449 if (!op1) {
2450 incvar(intvar[FNR]);
2451 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002452 }
2453 }
2454 setvar_i(res, L.i);
2455 break;
2456
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002457 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002458 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002459 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002460
Denis Vlasenkof782f522007-01-01 23:51:30 +00002461 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002462 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002463 break;
2464
Denis Vlasenkof782f522007-01-01 23:51:30 +00002465 case F_rn:
2466 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002467 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002468#if ENABLE_FEATURE_AWK_MATH
2469 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002470 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002471 break;
2472
Denis Vlasenkof782f522007-01-01 23:51:30 +00002473 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002474 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002475 break;
2476
Denis Vlasenkof782f522007-01-01 23:51:30 +00002477 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002478 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002479 break;
2480
Denis Vlasenkof782f522007-01-01 23:51:30 +00002481 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002482 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002483 break;
2484
Denis Vlasenkof782f522007-01-01 23:51:30 +00002485 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002486 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002487 break;
2488#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002489 case F_co:
2490 case F_ex:
2491 case F_lg:
2492 case F_si:
2493 case F_sq:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002494 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002495 break;
2496#endif
Denis Vlasenkof782f522007-01-01 23:51:30 +00002497 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002498 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002499 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002500 srand(seed);
2501 break;
2502
Denis Vlasenkof782f522007-01-01 23:51:30 +00002503 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002504 R.d = time(NULL);
2505 break;
2506
Denis Vlasenkof782f522007-01-01 23:51:30 +00002507 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002508 if (!op1)
2509 L.s = getvar_s(intvar[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002510 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002511 break;
2512
Denis Vlasenkof782f522007-01-01 23:51:30 +00002513 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002514 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002515 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2516 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002517 break;
2518
Denis Vlasenkof782f522007-01-01 23:51:30 +00002519 case F_ff:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002520 if (!op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002521 fflush(stdout);
2522 else {
2523 if (L.s && *L.s) {
2524 X.rsm = newfile(L.s);
2525 fflush(X.rsm->F);
2526 } else {
2527 fflush(NULL);
2528 }
2529 }
2530 break;
2531
Denis Vlasenkof782f522007-01-01 23:51:30 +00002532 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002533 X.rsm = (rstream *)hash_search(fdhash, L.s);
2534 if (X.rsm) {
2535 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002536 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002537 hash_remove(fdhash, L.s);
2538 }
2539 if (R.i != 0)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002540 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002541 R.d = (double)R.i;
2542 break;
2543 }
2544 setvar_i(res, R.d);
2545 break;
2546
Denis Vlasenkof782f522007-01-01 23:51:30 +00002547 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002548 res = exec_builtin(op, res);
2549 break;
2550
Denis Vlasenkof782f522007-01-01 23:51:30 +00002551 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002552 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002553 break;
2554
Denis Vlasenkof782f522007-01-01 23:51:30 +00002555 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002556 X.v = R.v;
2557 L.d = R.d = getvar_i(R.v);
2558 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002559 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002560 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002561 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002562 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002563 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002564 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002565 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002566 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002567 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002568 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002569 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002570 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002571 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002572 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002573 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002574 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002575 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002576 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002577 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002578 setvar_i(X.v, R.d);
2579 }
2580 setvar_i(res, L.d);
2581 break;
2582
Denis Vlasenkof782f522007-01-01 23:51:30 +00002583 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002584 R.i = (int)getvar_i(R.v);
2585 if (R.i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002586 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002587 } else {
2588 split_f0();
2589 if (R.i > nfields)
2590 fsrealloc(R.i);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002591 res = &Fields[R.i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002592 }
2593 break;
2594
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002595 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002596 case XC( OC_CONCAT ):
2597 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002598 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002599 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002600 strcpy(X.s, L.s);
2601 if ((opinfo & OPCLSMASK) == OC_COMMA) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002602 L.s = getvar_s(intvar[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002603 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002604 strcat(X.s, L.s);
2605 }
2606 strcat(X.s, R.s);
2607 setvar_p(res, X.s);
2608 break;
2609
Denis Vlasenkof782f522007-01-01 23:51:30 +00002610 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002611 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2612 break;
2613
Denis Vlasenkof782f522007-01-01 23:51:30 +00002614 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002615 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2616 break;
2617
Denis Vlasenkof782f522007-01-01 23:51:30 +00002618 case XC( OC_BINARY ):
2619 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002620 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002621 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002622 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002623 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002624 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002625 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002626 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002627 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002628 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002629 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002630 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002631 case '/':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002632 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002633 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002634 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002635 case '&':
2636#if ENABLE_FEATURE_AWK_MATH
Mike Frysingerde2b9382005-09-27 03:18:00 +00002637 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002638#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002639 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002640#endif
2641 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002642 case '%':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002643 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002644 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002645 break;
2646 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002647 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002648 break;
2649
Denis Vlasenkof782f522007-01-01 23:51:30 +00002650 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002651 if (is_numeric(L.v) && is_numeric(R.v)) {
2652 L.d = getvar_i(L.v) - getvar_i(R.v);
2653 } else {
2654 L.s = getvar_s(L.v);
2655 R.s = getvar_s(R.v);
2656 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2657 }
2658 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002659 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002660 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002661 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002662 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002663 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002664 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002665 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002666 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002667 break;
2668 }
2669 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2670 break;
2671
Denis Vlasenkof782f522007-01-01 23:51:30 +00002672 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002673 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002674 }
2675 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2676 op = op->a.n;
2677 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2678 break;
2679 if (nextrec)
2680 break;
2681 }
2682 nvfree(v1);
2683 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002684#undef fnargs
2685#undef seed
2686#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002687}
2688
2689
2690/* -------- main & co. -------- */
2691
Mike Frysinger10a11e22005-09-27 02:23:02 +00002692static int awk_exit(int r)
2693{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002694 var tv;
2695 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002696 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002697
Denis Vlasenkof782f522007-01-01 23:51:30 +00002698 zero_out_var(&tv);
2699
2700 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002701 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002702 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002703 evaluate(endseq.first, &tv);
2704 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002705
2706 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002707 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002708 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002709 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002710 if (hi->data.rs.F && hi->data.rs.is_pipe)
2711 pclose(hi->data.rs.F);
2712 hi = hi->next;
2713 }
2714 }
2715
2716 exit(r);
2717}
2718
2719/* if expr looks like "var=value", perform assignment and return 1,
2720 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002721static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002722{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002723 char *exprc, *s, *s0, *s1;
2724
Rob Landleyd921b2e2006-08-03 15:41:12 +00002725 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002726 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2727 free(exprc);
2728 return FALSE;
2729 }
2730
2731 *(s++) = '\0';
2732 s0 = s1 = s;
2733 while (*s)
2734 *(s1++) = nextchar(&s);
2735
2736 *s1 = '\0';
2737 setvar_u(newvar(exprc), s0);
2738 free(exprc);
2739 return TRUE;
2740}
2741
2742/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002743static rstream *next_input_file(void)
2744{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002745#define rsm (G.next_input_file__rsm)
2746#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002747
Glenn L McGrath545106f2002-11-11 06:21:00 +00002748 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002749 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002750
2751 if (rsm.F) fclose(rsm.F);
2752 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002753 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002754
2755 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002756 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002757 if (files_happen)
2758 return NULL;
2759 fname = "-";
2760 F = stdin;
2761 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002762 ind = getvar_s(incvar(intvar[ARGIND]));
2763 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002764 if (fname && *fname && !is_assignment(fname))
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002765 F = xfopen_stdin(fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002766 }
2767 } while (!F);
2768
2769 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002770 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002771 rsm.F = F;
2772 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002773#undef rsm
2774#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002775}
2776
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002777int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00002778int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002779{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002780 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002781 char *opt_F, *opt_W;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002782 llist_t *list_v = NULL;
2783 llist_t *list_f = NULL;
2784 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002785 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002786 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002787 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002788 char *vnames = (char *)vNames; /* cheat */
2789 char *vvalues = (char *)vValues;
2790
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002791 INIT_G();
2792
Denis Vlasenko150f4022007-01-13 21:06:21 +00002793 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002794 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2795 if (ENABLE_LOCALE_SUPPORT)
2796 setlocale(LC_NUMERIC, "C");
2797
Denis Vlasenkof782f522007-01-01 23:51:30 +00002798 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002799
2800 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002801 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002802
2803 vhash = hash_init();
2804 ahash = hash_init();
2805 fdhash = hash_init();
2806 fnhash = hash_init();
2807
2808 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002809 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002810 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00002811 if (*vvalues != '\377')
2812 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002813 else
2814 setvar_i(v, 0);
2815
Denis Vlasenkof782f522007-01-01 23:51:30 +00002816 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002817 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002818 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002819 }
2820 }
2821
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002822 handle_special(intvar[FS]);
2823 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002824
Denis Vlasenkof782f522007-01-01 23:51:30 +00002825 newfile("/dev/stdin")->F = stdin;
2826 newfile("/dev/stdout")->F = stdout;
2827 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002828
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002829 /* Huh, people report that sometimes environ is NULL. Oh well. */
2830 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002831 /* environ is writable, thus we don't strdup it needlessly */
2832 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002833 char *s1 = strchr(s, '=');
2834 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002835 *s1 = '\0';
2836 /* Both findvar and setvar_u take const char*
2837 * as 2nd arg -> environment is not trashed */
2838 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
2839 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00002840 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002841 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002842 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
2843 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002844 argv += optind;
2845 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002846 if (opt & 0x1)
2847 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002848 while (list_v) { /* -v */
2849 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002850 bb_show_usage();
2851 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002852 if (list_f) { /* -f */
2853 do {
2854 char *s = NULL;
2855 FILE *from_file;
2856
2857 g_progname = llist_pop(&list_f);
2858 from_file = xfopen_stdin(g_progname);
2859 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002860 for (i = j = 1; j > 0; i += j) {
2861 s = xrealloc(s, i + 4096);
2862 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002863 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002864 s[i] = '\0';
2865 fclose(from_file);
2866 parse_program(s + 1);
2867 free(s);
2868 } while (list_f);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002869 } else { // no -f: take program from 1st parameter
2870 if (!argc)
2871 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002872 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00002873 parse_program(*argv++);
2874 argc--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002875 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002876 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002877 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002878
Glenn L McGrath545106f2002-11-11 06:21:00 +00002879 /* fill in ARGV array */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002880 setvar_i(intvar[ARGC], argc + 1);
2881 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002882 i = 0;
2883 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002884 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002885
2886 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002887 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002888 awk_exit(EXIT_SUCCESS);
2889
2890 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002891 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002892
2893 /* passing through input files */
2894 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002895 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002896 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002897
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002898 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002899 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002900 incvar(intvar[NR]);
2901 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002902 evaluate(mainseq.first, &tv);
2903
2904 if (nextfile)
2905 break;
2906 }
2907
Denis Vlasenkof782f522007-01-01 23:51:30 +00002908 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002909 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002910
2911 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002912 }
2913
Glenn L McGrath545106f2002-11-11 06:21:00 +00002914 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002915 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002916}