blob: bac580497fa747cf0d92636d7e29def76f000048 [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,
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000369 SUBSEP, F0, ARGIND, ARGC,
370 ARGV, ERRNO, FNR, NR,
371 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS
Glenn L McGrath545106f2002-11-11 06:21:00 +0000372};
373
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000374static const char vNames[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000375 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
376 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000377 "SUBSEP\0" "$\0*" "ARGIND\0" "ARGC\0"
378 "ARGV\0" "ERRNO\0" "FNR\0" "NR\0"
379 "NF\0*" "IGNORECASE\0*" "ENVIRON\0" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000380
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000381static const char vValues[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000382 "%.6g\0" "%.6g\0" " \0" " \0"
383 "\n\0" "\n\0" "\0" "\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000384 "\034\0" "\0" "\377";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000385
386/* hash size may grow to these values */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000387#define FIRST_PRIME 61
388static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000389
Glenn L McGrath545106f2002-11-11 06:21:00 +0000390
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000391/* Globals. Split in two parts so that first one is addressed
392 * with (mostly short) negative offsets */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000393struct globals {
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000394 chain beginseq, mainseq, endseq;
395 chain *seq;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000396 node *break_ptr, *continue_ptr;
397 rstream *iF;
398 xhash *vhash, *ahash, *fdhash, *fnhash;
399 const char *g_progname;
400 int g_lineno;
401 int nfields;
402 int maxfields; /* used in fsrealloc() only */
403 var *Fields;
404 nvblock *g_cb;
405 char *g_pos;
406 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000407 smallint icase;
408 smallint exiting;
409 smallint nextrec;
410 smallint nextfile;
411 smallint is_f0_split;
412};
413struct globals2 {
414 uint32_t t_info; /* often used */
415 uint32_t t_tclass;
416 char *t_string;
417 int t_lineno;
418 int t_rollback;
419
420 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000421
422 /* former statics from various functions */
423 char *split_f0__fstrings;
424
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000425 uint32_t next_token__save_tclass;
426 uint32_t next_token__save_info;
427 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000428 smallint next_token__concat_inserted;
429
430 smallint next_input_file__files_happen;
431 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000432
433 var *evaluate__fnargs;
434 unsigned evaluate__seed;
435 regex_t evaluate__sreg;
436
437 var ptest__v;
438
439 tsplitter exec_builtin__tspl;
440
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000441 /* biggest and least used members go last */
442 double t_double;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000443 tsplitter fsplitter, rsplitter;
444};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000445#define G1 (ptr_to_globals[-1])
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000446#define G (*(struct globals2 *)ptr_to_globals)
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000447/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
448/* char G1size[sizeof(G1)]; - 0x6c */
449/* char Gsize[sizeof(G)]; - 0x1cc */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000450/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000451/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
452#define beginseq (G1.beginseq )
453#define mainseq (G1.mainseq )
454#define endseq (G1.endseq )
455#define seq (G1.seq )
456#define break_ptr (G1.break_ptr )
457#define continue_ptr (G1.continue_ptr)
458#define iF (G1.iF )
459#define vhash (G1.vhash )
460#define ahash (G1.ahash )
461#define fdhash (G1.fdhash )
462#define fnhash (G1.fnhash )
463#define g_progname (G1.g_progname )
464#define g_lineno (G1.g_lineno )
465#define nfields (G1.nfields )
466#define maxfields (G1.maxfields )
467#define Fields (G1.Fields )
468#define g_cb (G1.g_cb )
469#define g_pos (G1.g_pos )
470#define g_buf (G1.g_buf )
471#define icase (G1.icase )
472#define exiting (G1.exiting )
473#define nextrec (G1.nextrec )
474#define nextfile (G1.nextfile )
475#define is_f0_split (G1.is_f0_split )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000476#define t_info (G.t_info )
477#define t_tclass (G.t_tclass )
478#define t_string (G.t_string )
479#define t_double (G.t_double )
480#define t_lineno (G.t_lineno )
481#define t_rollback (G.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000482#define intvar (G.intvar )
483#define fsplitter (G.fsplitter )
484#define rsplitter (G.rsplitter )
485#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000486 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1)); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000487 G.next_token__ltclass = TC_OPTERM; \
488 G.evaluate__seed = 1; \
489} while (0)
490
Glenn L McGrath545106f2002-11-11 06:21:00 +0000491
492/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000493static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000494static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000495static void chain_group(void);
496static var *evaluate(node *, var *);
497static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000498static int fmt_num(char *, int, const char *, double, int);
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000499static int awk_exit(int) NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000500
501/* ---- error handling ---- */
502
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000503static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
504static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
505static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
506static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
507static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
508static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
509static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
510static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
511static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
Denis Vlasenko2d5bd802008-10-24 10:49:49 +0000512#if !ENABLE_FEATURE_AWK_LIBM
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000513static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000514#endif
515
Denis Vlasenkof782f522007-01-01 23:51:30 +0000516static void zero_out_var(var * vp)
517{
518 memset(vp, 0, sizeof(*vp));
519}
520
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000521static void syntax_error(const char *const message) NORETURN;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000522static void syntax_error(const char *const message)
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000523{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000524 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000525}
526
Glenn L McGrath545106f2002-11-11 06:21:00 +0000527/* ---- hash stuff ---- */
528
Denis Vlasenkof782f522007-01-01 23:51:30 +0000529static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000530{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000531 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000532
Denis Vlasenkof782f522007-01-01 23:51:30 +0000533 while (*name) idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000534 return idx;
535}
536
537/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000538static xhash *hash_init(void)
539{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000540 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000541
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000542 newhash = xzalloc(sizeof(xhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000543 newhash->csize = FIRST_PRIME;
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000544 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000545
546 return newhash;
547}
548
549/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000550static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000551{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000552 hash_item *hi;
553
554 hi = hash->items [ hashidx(name) % hash->csize ];
555 while (hi) {
556 if (strcmp(hi->name, name) == 0)
557 return &(hi->data);
558 hi = hi->next;
559 }
560 return NULL;
561}
562
563/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000564static void hash_rebuild(xhash *hash)
565{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000566 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000567 hash_item **newitems, *hi, *thi;
568
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000569 if (hash->nprime == ARRAY_SIZE(PRIMES))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000570 return;
571
572 newsize = PRIMES[hash->nprime++];
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000573 newitems = xzalloc(newsize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000574
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000575 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000576 hi = hash->items[i];
577 while (hi) {
578 thi = hi;
579 hi = thi->next;
580 idx = hashidx(thi->name) % newsize;
581 thi->next = newitems[idx];
582 newitems[idx] = thi;
583 }
584 }
585
586 free(hash->items);
587 hash->csize = newsize;
588 hash->items = newitems;
589}
590
591/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000592static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000593{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000594 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000595 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000596 int l;
597
598 hi = hash_search(hash, name);
Denis Vlasenkob78c7822007-07-18 18:31:11 +0000599 if (!hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000600 if (++hash->nel / hash->csize > 10)
601 hash_rebuild(hash);
602
Rob Landleya3896512006-05-07 20:20:34 +0000603 l = strlen(name) + 1;
Rob Landley9ffd4232006-05-21 18:30:35 +0000604 hi = xzalloc(sizeof(hash_item) + l);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000605 memcpy(hi->name, name, l);
606
607 idx = hashidx(name) % hash->csize;
608 hi->next = hash->items[idx];
609 hash->items[idx] = hi;
610 hash->glen += l;
611 }
612 return &(hi->data);
613}
614
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000615#define findvar(hash, name) ((var*) hash_find((hash), (name)))
616#define newvar(name) ((var*) hash_find(vhash, (name)))
617#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
618#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000619
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000620static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000621{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000622 hash_item *hi, **phi;
623
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000624 phi = &(hash->items[hashidx(name) % hash->csize]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000625 while (*phi) {
626 hi = *phi;
627 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000628 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000629 hash->nel--;
630 *phi = hi->next;
631 free(hi);
632 break;
633 }
634 phi = &(hi->next);
635 }
636}
637
638/* ------ some useful functions ------ */
639
Mike Frysinger10a11e22005-09-27 02:23:02 +0000640static void skip_spaces(char **s)
641{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000642 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000643
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000644 while (1) {
645 if (*p == '\\' && p[1] == '\n') {
646 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000647 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000648 } else if (*p != ' ' && *p != '\t') {
649 break;
650 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000651 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000652 }
653 *s = p;
654}
655
Mike Frysinger10a11e22005-09-27 02:23:02 +0000656static char *nextword(char **s)
657{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000658 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000659
Denis Vlasenkof782f522007-01-01 23:51:30 +0000660 while (*(*s)++) /* */;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000661
662 return p;
663}
664
Mike Frysinger10a11e22005-09-27 02:23:02 +0000665static char nextchar(char **s)
666{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000667 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000668
669 c = *((*s)++);
670 pps = *s;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000671 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000672 if (c == '\\' && *s == pps) c = *((*s)++);
673 return c;
674}
675
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000676static ALWAYS_INLINE int isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000677{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000678 return (isalnum(c) || c == '_');
679}
680
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000681static double my_strtod(char **pp)
682{
683#if ENABLE_DESKTOP
684 if ((*pp)[0] == '0'
685 && ((((*pp)[1] | 0x20) == 'x') || isdigit((*pp)[1]))
686 ) {
687 return strtoull(*pp, pp, 0);
688 }
689#endif
690 return strtod(*pp, pp);
691}
692
Glenn L McGrath545106f2002-11-11 06:21:00 +0000693/* -------- working with variables (set/get/copy/etc) -------- */
694
Mike Frysinger10a11e22005-09-27 02:23:02 +0000695static xhash *iamarray(var *v)
696{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000697 var *a = v;
698
699 while (a->type & VF_CHILD)
700 a = a->x.parent;
701
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000702 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000703 a->type |= VF_ARRAY;
704 a->x.array = hash_init();
705 }
706 return a->x.array;
707}
708
Mike Frysinger10a11e22005-09-27 02:23:02 +0000709static void clear_array(xhash *array)
710{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000711 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000712 hash_item *hi, *thi;
713
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000714 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000715 hi = array->items[i];
716 while (hi) {
717 thi = hi;
718 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000719 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000720 free(thi);
721 }
722 array->items[i] = NULL;
723 }
724 array->glen = array->nel = 0;
725}
726
727/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000728static var *clrvar(var *v)
729{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000730 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000731 free(v->string);
732
733 v->type &= VF_DONTTOUCH;
734 v->type |= VF_DIRTY;
735 v->string = NULL;
736 return v;
737}
738
739/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000740static var *setvar_p(var *v, char *value)
741{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000742 clrvar(v);
743 v->string = value;
744 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000745 return v;
746}
747
748/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000749static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000750{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000751 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000752}
753
754/* same as setvar_s but set USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000755static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000756{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000757 setvar_s(v, value);
758 v->type |= VF_USER;
759 return v;
760}
761
762/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000763static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000764{
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000765 char sidx[sizeof(int)*3 + 1];
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000766 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000767
768 sprintf(sidx, "%d", idx);
769 v = findvar(iamarray(a), sidx);
770 setvar_u(v, s);
771}
772
773/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000774static var *setvar_i(var *v, double value)
775{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000776 clrvar(v);
777 v->type |= VF_NUMBER;
778 v->number = value;
779 handle_special(v);
780 return v;
781}
782
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000783static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000784{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000785 /* if v is numeric and has no cached string, convert it to string */
786 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000787 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
788 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000789 v->type |= VF_CACHED;
790 }
791 return (v->string == NULL) ? "" : v->string;
792}
793
Mike Frysinger10a11e22005-09-27 02:23:02 +0000794static double getvar_i(var *v)
795{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000796 char *s;
797
798 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
799 v->number = 0;
800 s = v->string;
801 if (s && *s) {
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000802 v->number = my_strtod(&s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000803 if (v->type & VF_USER) {
804 skip_spaces(&s);
805 if (*s != '\0')
806 v->type &= ~VF_USER;
807 }
808 } else {
809 v->type &= ~VF_USER;
810 }
811 v->type |= VF_CACHED;
812 }
813 return v->number;
814}
815
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000816/* Used for operands of bitwise ops */
817static unsigned long getvar_i_int(var *v)
818{
819 double d = getvar_i(v);
820
821 /* Casting doubles to longs is undefined for values outside
822 * of target type range. Try to widen it as much as possible */
823 if (d >= 0)
824 return (unsigned long)d;
Denis Vlasenko665eaff2008-09-05 04:59:02 +0000825 /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000826 return - (long) (unsigned long) (-d);
827}
828
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000829static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000830{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000831 if (dest != src) {
832 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000833 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000834 dest->number = src->number;
835 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000836 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000837 }
838 handle_special(dest);
839 return dest;
840}
841
Mike Frysinger10a11e22005-09-27 02:23:02 +0000842static var *incvar(var *v)
843{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000844 return setvar_i(v, getvar_i(v) + 1.);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000845}
846
847/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000848static int is_numeric(var *v)
849{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000850 getvar_i(v);
851 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
852}
853
854/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000855static int istrue(var *v)
856{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000857 if (is_numeric(v))
858 return (v->number == 0) ? 0 : 1;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000859 return (v->string && *(v->string)) ? 1 : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000860}
861
Eric Andersenaff114c2004-04-14 17:51:38 +0000862/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000863static var *nvalloc(int n)
864{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000865 nvblock *pb = NULL;
866 var *v, *r;
867 int size;
868
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000869 while (g_cb) {
870 pb = g_cb;
871 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break;
872 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000873 }
874
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000875 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000876 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000877 g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000878 g_cb->size = size;
879 g_cb->pos = g_cb->nv;
880 g_cb->prev = pb;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000881 /*g_cb->next = NULL; - xzalloc did it */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000882 if (pb) pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000883 }
884
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000885 v = r = g_cb->pos;
886 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000887
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000888 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000889 v->type = 0;
890 v->string = NULL;
891 v++;
892 }
893
894 return r;
895}
896
Mike Frysinger10a11e22005-09-27 02:23:02 +0000897static void nvfree(var *v)
898{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000899 var *p;
900
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000901 if (v < g_cb->nv || v >= g_cb->pos)
902 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000903
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000904 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000905 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000906 clear_array(iamarray(p));
907 free(p->x.array->items);
908 free(p->x.array);
909 }
910 if (p->type & VF_WALK)
911 free(p->x.walker);
912
913 clrvar(p);
914 }
915
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000916 g_cb->pos = v;
917 while (g_cb->prev && g_cb->pos == g_cb->nv) {
918 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000919 }
920}
921
922/* ------- awk program text parsing ------- */
923
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000924/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000925 * If token isn't expected, give away. Return token class
926 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000927static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000928{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000929#define concat_inserted (G.next_token__concat_inserted)
930#define save_tclass (G.next_token__save_tclass)
931#define save_info (G.next_token__save_info)
932/* Initialized to TC_OPTERM: */
933#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000934
Denis Vlasenkof782f522007-01-01 23:51:30 +0000935 char *p, *pp, *s;
936 const char *tl;
937 uint32_t tc;
938 const uint32_t *ti;
939 int l;
940
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000941 if (t_rollback) {
942 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000943
944 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000945 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000946 t_tclass = save_tclass;
947 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000948
949 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000950 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000951 readnext:
Glenn L McGrath545106f2002-11-11 06:21:00 +0000952 skip_spaces(&p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000953 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000954 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000955 while (*p != '\n' && *p != '\0')
956 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000957
958 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000959 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000960
961 if (*p == '\0') {
962 tc = TC_EOF;
963
964 } else if (*p == '\"') {
965 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000966 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000967 while (*p != '\"') {
968 if (*p == '\0' || *p == '\n')
969 syntax_error(EMSG_UNEXP_EOS);
970 *(s++) = nextchar(&p);
971 }
972 p++;
973 *s = '\0';
974 tc = TC_STRING;
975
976 } else if ((expected & TC_REGEXP) && *p == '/') {
977 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000978 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000979 while (*p != '/') {
980 if (*p == '\0' || *p == '\n')
981 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +0000982 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000983 if (*s++ == '\\') {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000984 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000985 *(s-1) = bb_process_escape_sequence((const char **)&p);
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000986 if (*pp == '\\')
987 *s++ = '\\';
988 if (p == pp)
989 *s++ = *p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000990 }
991 }
992 p++;
993 *s = '\0';
994 tc = TC_REGEXP;
995
996 } else if (*p == '.' || isdigit(*p)) {
997 /* it's a number */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000998 t_double = my_strtod(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000999 if (*p == '.')
1000 syntax_error(EMSG_UNEXP_TOKEN);
1001 tc = TC_NUMBER;
1002
1003 } else {
1004 /* search for something known */
1005 tl = tokenlist;
1006 tc = 0x00000001;
1007 ti = tokeninfo;
1008 while (*tl) {
1009 l = *(tl++);
1010 if (l == NTCC) {
1011 tc <<= 1;
1012 continue;
1013 }
1014 /* if token class is expected, token
1015 * matches and it's not a longer word,
1016 * then this is what we are looking for
1017 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001018 if ((tc & (expected | TC_WORD | TC_NEWLINE))
1019 && *tl == *p && strncmp(p, tl, l) == 0
1020 && !((tc & TC_WORD) && isalnum_(p[l]))
1021 ) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001022 t_info = *ti;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001023 p += l;
1024 break;
1025 }
1026 ti++;
1027 tl += l;
1028 }
1029
Denis Vlasenkof782f522007-01-01 23:51:30 +00001030 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001031 /* it's a name (var/array/function),
1032 * otherwise it's something wrong
1033 */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001034 if (!isalnum_(*p))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001035 syntax_error(EMSG_UNEXP_TOKEN);
1036
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001037 t_string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001038 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001039 *(p-1) = *p;
1040 }
1041 *(p-1) = '\0';
1042 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +00001043 /* also consume whitespace between functionname and bracket */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001044 if (!(expected & TC_VARIABLE))
1045 skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001046 if (*p == '(') {
1047 tc = TC_FUNCTION;
1048 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001049 if (*p == '[') {
1050 p++;
1051 tc = TC_ARRAY;
1052 }
1053 }
1054 }
1055 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001056 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001057
1058 /* skipping newlines in some cases */
1059 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1060 goto readnext;
1061
1062 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001063 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001064 concat_inserted = TRUE;
1065 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001066 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001067 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001068 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001069 }
1070
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001071 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001072 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001073 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001074
1075 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001076 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001077 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001078 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001079
1080 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001081#undef concat_inserted
1082#undef save_tclass
1083#undef save_info
1084#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001085}
1086
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001087static void rollback_token(void)
1088{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001089 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001090}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001091
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001092static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001093{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001094 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001095
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001096 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001097 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001098 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001099 return n;
1100}
1101
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001102static node *mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001103{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001104 n->info = OC_REGEXP;
1105 n->l.re = re;
1106 n->r.ire = re + 1;
1107 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001108 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001109
1110 return n;
1111}
1112
Mike Frysinger10a11e22005-09-27 02:23:02 +00001113static node *condition(void)
1114{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001115 next_token(TC_SEQSTART);
1116 return parse_expr(TC_SEQTERM);
1117}
1118
1119/* parse expression terminated by given argument, return ptr
1120 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001121static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001122{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001123 node sn;
1124 node *cn = &sn;
1125 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001126 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001127 var *v;
1128
1129 sn.info = PRIMASK;
1130 sn.r.n = glptr = NULL;
1131 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1132
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001133 while (!((tc = next_token(xtc)) & iexp)) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001134 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001135 /* input redirection (<) attached to glptr node */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001136 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001137 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001138 xtc = TC_OPERAND | TC_UOPPRE;
1139 glptr = NULL;
1140
1141 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1142 /* for binary and postfix-unary operators, jump back over
1143 * previous operators with higher priority */
1144 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001145 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1146 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) )
Glenn L McGrath545106f2002-11-11 06:21:00 +00001147 vn = vn->a.n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001148 if ((t_info & OPCLSMASK) == OC_TERNARY)
1149 t_info += P(6);
1150 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001151 cn->a.n = vn->a.n;
1152 if (tc & TC_BINOP) {
1153 cn->l.n = vn;
1154 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001155 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001156 /* it's a pipe */
1157 next_token(TC_GETLINE);
1158 /* give maximum priority to this pipe */
1159 cn->info &= ~PRIMASK;
1160 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1161 }
1162 } else {
1163 cn->r.n = vn;
1164 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1165 }
1166 vn->a.n = cn;
1167
1168 } else {
1169 /* for operands and prefix-unary operators, attach them
1170 * to last node */
1171 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001172 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001173 cn->a.n = vn;
1174 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1175 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001176 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001177 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001178 * only simple tclasses should be used! */
1179 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001180 case TC_VARIABLE:
1181 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001182 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001183 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001184 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001185 cn->info = OC_FNARG;
1186 cn->l.i = v->x.aidx;
1187 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001188 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001189 }
1190 if (tc & TC_ARRAY) {
1191 cn->info |= xS;
1192 cn->r.n = parse_expr(TC_ARRTERM);
1193 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001194 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001195
Denis Vlasenkof782f522007-01-01 23:51:30 +00001196 case TC_NUMBER:
1197 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001198 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001199 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001200 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001201 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001202 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001203 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001204 break;
1205
Denis Vlasenkof782f522007-01-01 23:51:30 +00001206 case TC_REGEXP:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001207 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001208 break;
1209
Denis Vlasenkof782f522007-01-01 23:51:30 +00001210 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001211 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001212 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001213 cn->l.n = condition();
1214 break;
1215
Denis Vlasenkof782f522007-01-01 23:51:30 +00001216 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001217 cn = vn->r.n = parse_expr(TC_SEQTERM);
1218 cn->a.n = vn;
1219 break;
1220
Denis Vlasenkof782f522007-01-01 23:51:30 +00001221 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001222 glptr = cn;
1223 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1224 break;
1225
Denis Vlasenkof782f522007-01-01 23:51:30 +00001226 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001227 cn->l.n = condition();
1228 break;
1229 }
1230 }
1231 }
1232 }
1233 return sn.r.n;
1234}
1235
1236/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001237static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001238{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001239 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001240
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001241 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001242 seq->first = seq->last = new_node(0);
1243
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001244 if (seq->programname != g_progname) {
1245 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001246 n = chain_node(OC_NEWSOURCE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001247 n->l.s = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001248 }
1249
1250 n = seq->last;
1251 n->info = info;
1252 seq->last = n->a.n = new_node(OC_DONE);
1253
1254 return n;
1255}
1256
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001257static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001258{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001259 node *n;
1260
1261 n = chain_node(info);
1262 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001263 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001264 rollback_token();
1265}
1266
Mike Frysinger10a11e22005-09-27 02:23:02 +00001267static node *chain_loop(node *nn)
1268{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001269 node *n, *n2, *save_brk, *save_cont;
1270
1271 save_brk = break_ptr;
1272 save_cont = continue_ptr;
1273
1274 n = chain_node(OC_BR | Vx);
1275 continue_ptr = new_node(OC_EXEC);
1276 break_ptr = new_node(OC_EXEC);
1277 chain_group();
1278 n2 = chain_node(OC_EXEC | Vx);
1279 n2->l.n = nn;
1280 n2->a.n = n;
1281 continue_ptr->a.n = n2;
1282 break_ptr->a.n = n->r.n = seq->last;
1283
1284 continue_ptr = save_cont;
1285 break_ptr = save_brk;
1286
1287 return n;
1288}
1289
1290/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001291static void chain_group(void)
1292{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001293 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001294 node *n, *n2, *n3;
1295
1296 do {
1297 c = next_token(TC_GRPSEQ);
1298 } while (c & TC_NEWLINE);
1299
1300 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001301 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001302 if (t_tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001303 rollback_token();
1304 chain_group();
1305 }
1306 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1307 rollback_token();
1308 chain_expr(OC_EXEC | Vx);
1309 } else { /* TC_STATEMNT */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001310 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001311 case ST_IF:
1312 n = chain_node(OC_BR | Vx);
1313 n->l.n = condition();
1314 chain_group();
1315 n2 = chain_node(OC_EXEC);
1316 n->r.n = seq->last;
1317 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001318 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001319 n2->a.n = seq->last;
1320 } else {
1321 rollback_token();
1322 }
1323 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001324
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001325 case ST_WHILE:
1326 n2 = condition();
1327 n = chain_loop(NULL);
1328 n->l.n = n2;
1329 break;
1330
1331 case ST_DO:
1332 n2 = chain_node(OC_EXEC);
1333 n = chain_loop(NULL);
1334 n2->a.n = n->a.n;
1335 next_token(TC_WHILE);
1336 n->l.n = condition();
1337 break;
1338
1339 case ST_FOR:
1340 next_token(TC_SEQSTART);
1341 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001342 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001343 if ((n2->info & OPCLSMASK) != OC_IN)
1344 syntax_error(EMSG_UNEXP_TOKEN);
1345 n = chain_node(OC_WALKINIT | VV);
1346 n->l.n = n2->l.n;
1347 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001348 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001349 n->info = OC_WALKNEXT | Vx;
1350 n->l.n = n2->l.n;
1351 } else { /* for (;;) */
1352 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001353 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001354 n2 = parse_expr(TC_SEMICOL);
1355 n3 = parse_expr(TC_SEQTERM);
1356 n = chain_loop(n3);
1357 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001358 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001359 n->info = OC_EXEC;
1360 }
1361 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001362
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001363 case OC_PRINT:
1364 case OC_PRINTF:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001365 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001366 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001367 if (t_tclass & TC_OUTRDR) {
1368 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001369 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1370 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001371 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001372 rollback_token();
1373 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001374
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001375 case OC_BREAK:
1376 n = chain_node(OC_EXEC);
1377 n->a.n = break_ptr;
1378 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001379
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001380 case OC_CONTINUE:
1381 n = chain_node(OC_EXEC);
1382 n->a.n = continue_ptr;
1383 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001384
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001385 /* delete, next, nextfile, return, exit */
1386 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001387 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001388 }
1389 }
1390}
1391
Mike Frysinger10a11e22005-09-27 02:23:02 +00001392static void parse_program(char *p)
1393{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001394 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001395 node *cn;
1396 func *f;
1397 var *v;
1398
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001399 g_pos = p;
1400 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001401 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001402 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001403
1404 if (tclass & TC_OPTERM)
1405 continue;
1406
1407 seq = &mainseq;
1408 if (tclass & TC_BEGIN) {
1409 seq = &beginseq;
1410 chain_group();
1411
1412 } else if (tclass & TC_END) {
1413 seq = &endseq;
1414 chain_group();
1415
1416 } else if (tclass & TC_FUNCDECL) {
1417 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001418 g_pos++;
1419 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001420 f->body.first = NULL;
1421 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001422 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001423 v = findvar(ahash, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001424 v->x.aidx = (f->nargs)++;
1425
1426 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1427 break;
1428 }
1429 seq = &(f->body);
1430 chain_group();
1431 clear_array(ahash);
1432
1433 } else if (tclass & TC_OPSEQ) {
1434 rollback_token();
1435 cn = chain_node(OC_TEST);
1436 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001437 if (t_tclass & TC_GRPSTART) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001438 rollback_token();
1439 chain_group();
1440 } else {
1441 chain_node(OC_PRINT);
1442 }
1443 cn->r.n = mainseq.last;
1444
1445 } else /* if (tclass & TC_GRPSTART) */ {
1446 rollback_token();
1447 chain_group();
1448 }
1449 }
1450}
1451
1452
1453/* -------- program execution part -------- */
1454
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001455static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001456{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001457 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001458 node *n;
1459
1460 re = &spl->re[0];
1461 ire = &spl->re[1];
1462 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001463 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001464 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001465 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001466 }
Rob Landleya3896512006-05-07 20:20:34 +00001467 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001468 mk_re_node(s, n, re);
1469 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001470 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001471 }
1472
1473 return n;
1474}
1475
1476/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001477 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001478 * be later regfree'd manually
1479 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001480static regex_t *as_regex(node *op, regex_t *preg)
1481{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001482 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001483 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001484
1485 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1486 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001487 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001488 v = nvalloc(1);
1489 s = getvar_s(evaluate(op, v));
1490 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1491 nvfree(v);
1492 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001493}
1494
1495/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001496static void qrealloc(char **b, int n, int *size)
1497{
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001498 if (!*b || n >= *size) {
1499 *size = n + (n>>1) + 80;
1500 *b = xrealloc(*b, *size);
1501 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001502}
1503
1504/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001505static void fsrealloc(int size)
1506{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001507 int i;
1508
1509 if (size >= maxfields) {
1510 i = maxfields;
1511 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001512 Fields = xrealloc(Fields, maxfields * sizeof(var));
1513 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001514 Fields[i].type = VF_SPECIAL;
1515 Fields[i].string = NULL;
1516 }
1517 }
1518
1519 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001520 for (i = size; i < nfields; i++) {
1521 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001522 }
1523 }
1524 nfields = size;
1525}
1526
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001527static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001528{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001529 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001530 char c[4];
1531 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001532 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001533
1534 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001535 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1536 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001537
1538 c[0] = c[1] = (char)spl->info;
1539 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001540 if (*getvar_s(intvar[RS]) == '\0')
1541 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001542
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001543 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1544 if (!*s)
1545 return n; /* "": zero fields */
1546 n++; /* at least one field will be there */
1547 do {
1548 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001549 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1550 && pmatch[0].rm_so <= l
1551 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001552 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001553 if (pmatch[0].rm_eo == 0) {
1554 l++;
1555 pmatch[0].rm_eo++;
1556 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001557 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001558 } else {
1559 pmatch[0].rm_eo = l;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001560 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001561 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001562 memcpy(s1, s, l);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001563 s1[l] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001564 nextword(&s1);
1565 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001566 } while (*s);
1567 return n;
1568 }
1569 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001570 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001571 *s1++ = *s++;
1572 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001573 n++;
1574 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001575 return n;
1576 }
1577 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001578 if (icase) {
1579 c[0] = toupper(c[0]);
1580 c[1] = tolower(c[1]);
1581 }
1582 if (*s1) n++;
1583 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001584 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001585 n++;
1586 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001587 return n;
1588 }
1589 /* space split */
1590 while (*s) {
1591 s = skip_whitespace(s);
1592 if (!*s) break;
1593 n++;
1594 while (*s && !isspace(*s))
1595 *s1++ = *s++;
1596 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001597 }
1598 return n;
1599}
1600
Mike Frysinger10a11e22005-09-27 02:23:02 +00001601static void split_f0(void)
1602{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001603/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001604#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001605
Glenn L McGrath545106f2002-11-11 06:21:00 +00001606 int i, n;
1607 char *s;
1608
1609 if (is_f0_split)
1610 return;
1611
1612 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001613 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001614 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001615 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001616 fsrealloc(n);
1617 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001618 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001619 Fields[i].string = nextword(&s);
1620 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1621 }
1622
1623 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001624 clrvar(intvar[NF]);
1625 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1626 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001627#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001628}
1629
1630/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001631static void handle_special(var *v)
1632{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001633 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001634 char *b;
1635 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001636 int sl, l, len, i, bsize;
1637
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001638 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001639 return;
1640
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001641 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001642 n = (int)getvar_i(v);
1643 fsrealloc(n);
1644
1645 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001646 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001647 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001648 b = NULL;
1649 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001650 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001651 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001652 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001653 if (b) {
1654 memcpy(b+len, sep, sl);
1655 len += sl;
1656 }
1657 qrealloc(&b, len+l+sl, &bsize);
1658 memcpy(b+len, s, l);
1659 len += l;
1660 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001661 if (b)
1662 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001663 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001664 is_f0_split = TRUE;
1665
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001666 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001667 is_f0_split = FALSE;
1668
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001669 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001670 mk_splitter(getvar_s(v), &fsplitter);
1671
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001672 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001673 mk_splitter(getvar_s(v), &rsplitter);
1674
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001675 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001676 icase = istrue(v);
1677
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001678 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001679 n = getvar_i(intvar[NF]);
1680 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001681 /* right here v is invalid. Just to note... */
1682 }
1683}
1684
1685/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001686static node *nextarg(node **pn)
1687{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001688 node *n;
1689
1690 n = *pn;
1691 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1692 *pn = n->r.n;
1693 n = n->l.n;
1694 } else {
1695 *pn = NULL;
1696 }
1697 return n;
1698}
1699
Mike Frysinger10a11e22005-09-27 02:23:02 +00001700static void hashwalk_init(var *v, xhash *array)
1701{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001702 char **w;
1703 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001704 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001705
1706 if (v->type & VF_WALK)
1707 free(v->x.walker);
1708
1709 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001710 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001711 w[0] = w[1] = (char *)(w + 2);
1712 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001713 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001714 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001715 strcpy(*w, hi->name);
1716 nextword(w);
1717 hi = hi->next;
1718 }
1719 }
1720}
1721
Mike Frysinger10a11e22005-09-27 02:23:02 +00001722static int hashwalk_next(var *v)
1723{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001724 char **w;
1725
1726 w = v->x.walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001727 if (w[1] == w[0])
Glenn L McGrath545106f2002-11-11 06:21:00 +00001728 return FALSE;
1729
1730 setvar_s(v, nextword(w+1));
1731 return TRUE;
1732}
1733
1734/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001735static int ptest(node *pattern)
1736{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001737 /* ptest__v is "static": to save stack space? */
1738 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001739}
1740
1741/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001742static int awk_getline(rstream *rsm, var *v)
1743{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001744 char *b;
1745 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001746 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001747 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001748 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001749
1750 /* we're using our own buffer since we need access to accumulating
1751 * characters
1752 */
1753 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001754 m = rsm->buffer;
1755 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001756 p = rsm->pos;
1757 size = rsm->size;
1758 c = (char) rsplitter.n.info;
1759 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001760
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001761 if (!m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001762 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001763 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001764 so = eo = p;
1765 r = 1;
1766 if (p > 0) {
1767 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1768 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001769 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001770 so = pmatch[0].rm_so;
1771 eo = pmatch[0].rm_eo;
1772 if (b[eo] != '\0')
1773 break;
1774 }
1775 } else if (c != '\0') {
1776 s = strchr(b+pp, c);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001777 if (!s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001778 if (s) {
1779 so = eo = s-b;
1780 eo++;
1781 break;
1782 }
1783 } else {
1784 while (b[rp] == '\n')
1785 rp++;
1786 s = strstr(b+rp, "\n\n");
1787 if (s) {
1788 so = eo = s-b;
1789 while (b[eo] == '\n') eo++;
1790 if (b[eo] != '\0')
1791 break;
1792 }
1793 }
1794 }
1795
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001796 if (a > 0) {
1797 memmove(m, (const void *)(m+a), p+1);
1798 b = m;
1799 a = 0;
1800 }
1801
1802 qrealloc(&m, a+p+128, &size);
1803 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001804 pp = p;
1805 p += safe_read(fd, b+p, size-p-1);
1806 if (p < pp) {
1807 p = 0;
1808 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001809 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001810 }
1811 b[p] = '\0';
1812
1813 } while (p > pp);
1814
1815 if (p == 0) {
1816 r--;
1817 } else {
1818 c = b[so]; b[so] = '\0';
1819 setvar_s(v, b+rp);
1820 v->type |= VF_USER;
1821 b[so] = c;
1822 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001823 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001824 b[eo] = c;
1825 }
1826
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001827 rsm->buffer = m;
1828 rsm->adv = a + eo;
1829 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001830 rsm->size = size;
1831
1832 return r;
1833}
1834
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001835static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001836{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001837 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001838 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001839 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001840
1841 if (int_as_int && n == (int)n) {
1842 r = snprintf(b, size, "%d", (int)n);
1843 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001844 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001845 if (strchr("diouxX", c)) {
1846 r = snprintf(b, size, format, (int)n);
1847 } else if (strchr("eEfgG", c)) {
1848 r = snprintf(b, size, format, n);
1849 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001850 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001851 }
1852 }
1853 return r;
1854}
1855
Glenn L McGrath545106f2002-11-11 06:21:00 +00001856/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001857static char *awk_printf(node *n)
1858{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001859 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001860 char *fmt, *s, *f;
1861 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001862 int i, j, incr, bsize;
1863 char c, c1;
1864 var *v, *arg;
1865
1866 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001867 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001868
1869 i = 0;
1870 while (*f) {
1871 s = f;
1872 while (*f && (*f != '%' || *(++f) == '%'))
1873 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001874 while (*f && !isalpha(*f)) {
1875 if (*f == '*')
1876 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001877 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001878 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001879
1880 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001881 qrealloc(&b, incr + i, &bsize);
1882 c = *f;
1883 if (c != '\0') f++;
1884 c1 = *f;
1885 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001886 arg = evaluate(nextarg(&n), v);
1887
1888 j = i;
1889 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001890 i += sprintf(b+i, s, is_numeric(arg) ?
1891 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001892 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001893 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001894 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001895 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001896 } else {
1897 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1898 }
1899 *f = c1;
1900
1901 /* if there was an error while sprintf, return value is negative */
1902 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001903 }
1904
Denis Vlasenkof782f522007-01-01 23:51:30 +00001905 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001906 free(fmt);
1907 nvfree(v);
1908 b[i] = '\0';
1909 return b;
1910}
1911
1912/* common substitution routine
1913 * replace (nm) substring of (src) that match (n) with (repl), store
1914 * result into (dest), return number of substitutions. If nm=0, replace
1915 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1916 * subexpression matching (\1-\9)
1917 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001918static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001919{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001920 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001921 const char *s;
1922 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001923 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1924 regmatch_t pmatch[10];
1925 regex_t sreg, *re;
1926
1927 re = as_regex(rn, &sreg);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001928 if (!src) src = intvar[F0];
1929 if (!dest) dest = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001930
1931 i = di = 0;
1932 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001933 rl = strlen(repl);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001934 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001935 so = pmatch[0].rm_so;
1936 eo = pmatch[0].rm_eo;
1937
1938 qrealloc(&ds, di + eo + rl, &dssize);
1939 memcpy(ds + di, sp, eo);
1940 di += eo;
1941 if (++i >= nm) {
1942 /* replace */
1943 di -= (eo - so);
1944 nbs = 0;
1945 for (s = repl; *s; s++) {
1946 ds[di++] = c = *s;
1947 if (c == '\\') {
1948 nbs++;
1949 continue;
1950 }
1951 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1952 di -= ((nbs + 3) >> 1);
1953 j = 0;
1954 if (c != '&') {
1955 j = c - '0';
1956 nbs++;
1957 }
1958 if (nbs % 2) {
1959 ds[di++] = c;
1960 } else {
1961 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1962 qrealloc(&ds, di + rl + n, &dssize);
1963 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1964 di += n;
1965 }
1966 }
1967 nbs = 0;
1968 }
1969 }
1970
1971 sp += eo;
1972 if (i == nm) break;
1973 if (eo == so) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001974 ds[di] = *sp++;
1975 if (!ds[di++]) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001976 }
1977 }
1978
1979 qrealloc(&ds, di + strlen(sp), &dssize);
1980 strcpy(ds + di, sp);
1981 setvar_p(dest, ds);
1982 if (re == &sreg) regfree(re);
1983 return i;
1984}
1985
Mike Frysinger10a11e22005-09-27 02:23:02 +00001986static var *exec_builtin(node *op, var *res)
1987{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001988#define tspl (G.exec_builtin__tspl)
1989
Glenn L McGrath545106f2002-11-11 06:21:00 +00001990 int (*to_xxx)(int);
1991 var *tv;
1992 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001993 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001994 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001995 regmatch_t pmatch[2];
1996 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001997 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001998 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001999 int nargs;
2000 time_t tt;
2001 char *s, *s1;
2002 int i, l, ll, n;
2003
2004 tv = nvalloc(4);
2005 isr = info = op->info;
2006 op = op->l.n;
2007
2008 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002009 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002010 an[i] = nextarg(&op);
2011 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
2012 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
2013 isr >>= 1;
2014 }
2015
2016 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002017 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002018 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002019
2020 switch (info & OPNMASK) {
2021
Denis Vlasenkof782f522007-01-01 23:51:30 +00002022 case B_a2:
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002023#if ENABLE_FEATURE_AWK_LIBM
Denis Vlasenko37890e22008-10-21 12:59:34 +00002024 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002025#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002026 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002027#endif
2028 break;
2029
Denis Vlasenkof782f522007-01-01 23:51:30 +00002030 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002031 if (nargs > 2) {
2032 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2033 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2034 } else {
2035 spl = &fsplitter.n;
2036 }
2037
2038 n = awk_split(as[0], spl, &s);
2039 s1 = s;
2040 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002041 for (i = 1; i <= n; i++)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002042 setari_u(av[1], i, nextword(&s1));
2043 free(s);
2044 setvar_i(res, n);
2045 break;
2046
Denis Vlasenkof782f522007-01-01 23:51:30 +00002047 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00002048 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002049 i = getvar_i(av[1]) - 1;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002050 if (i > l) i = l;
2051 if (i < 0) i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002052 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002053 if (n < 0) n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002054 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002055 setvar_p(res, s);
2056 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002057
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002058 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2059 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002060 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002061 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002062 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002063
Denis Vlasenkof782f522007-01-01 23:51:30 +00002064 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002065 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002066 break;
2067
Denis Vlasenkof782f522007-01-01 23:51:30 +00002068 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002069 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002070 break;
2071
Denis Vlasenkof782f522007-01-01 23:51:30 +00002072 case B_or:
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_rs:
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_xo:
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;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002083
Denis Vlasenkof782f522007-01-01 23:51:30 +00002084 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002085 to_xxx = tolower;
2086 goto lo_cont;
2087
Denis Vlasenkof782f522007-01-01 23:51:30 +00002088 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002089 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002090 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00002091 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002092 while (*s1) {
2093 *s1 = (*to_xxx)(*s1);
2094 s1++;
2095 }
2096 setvar_p(res, s);
2097 break;
2098
Denis Vlasenkof782f522007-01-01 23:51:30 +00002099 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002100 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002101 ll = strlen(as[1]);
2102 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002103 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002104 if (!icase) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002105 s = strstr(as[0], as[1]);
2106 if (s) n = (s - as[0]) + 1;
2107 } else {
2108 /* this piece of code is terribly slow and
2109 * really should be rewritten
2110 */
2111 for (i=0; i<=l; i++) {
2112 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2113 n = i+1;
2114 break;
2115 }
2116 }
2117 }
2118 }
2119 setvar_i(res, n);
2120 break;
2121
Denis Vlasenkof782f522007-01-01 23:51:30 +00002122 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002123 if (nargs > 1)
2124 tt = getvar_i(av[1]);
2125 else
2126 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002127 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002128 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002129 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2130 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002131 g_buf[i] = '\0';
2132 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002133 break;
2134
Denis Vlasenkof782f522007-01-01 23:51:30 +00002135 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002136 re = as_regex(an[1], &sreg);
2137 n = regexec(re, as[0], 1, pmatch, 0);
2138 if (n == 0) {
2139 pmatch[0].rm_so++;
2140 pmatch[0].rm_eo++;
2141 } else {
2142 pmatch[0].rm_so = 0;
2143 pmatch[0].rm_eo = -1;
2144 }
2145 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2146 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2147 setvar_i(res, pmatch[0].rm_so);
2148 if (re == &sreg) regfree(re);
2149 break;
2150
Denis Vlasenkof782f522007-01-01 23:51:30 +00002151 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002152 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2153 break;
2154
Denis Vlasenkof782f522007-01-01 23:51:30 +00002155 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002156 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2157 break;
2158
Denis Vlasenkof782f522007-01-01 23:51:30 +00002159 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002160 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2161 break;
2162 }
2163
2164 nvfree(tv);
2165 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002166#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002167}
2168
2169/*
2170 * Evaluate node - the heart of the program. Supplied with subtree
2171 * and place where to store result. returns ptr to result.
2172 */
2173#define XC(n) ((n) >> 8)
2174
Mike Frysinger10a11e22005-09-27 02:23:02 +00002175static var *evaluate(node *op, var *res)
2176{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002177/* This procedure is recursive so we should count every byte */
2178#define fnargs (G.evaluate__fnargs)
2179/* seed is initialized to 1 */
2180#define seed (G.evaluate__seed)
2181#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002182
Glenn L McGrath545106f2002-11-11 06:21:00 +00002183 node *op1;
2184 var *v1;
2185 union {
2186 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002187 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002188 double d;
2189 int i;
2190 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002191 uint32_t opinfo;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002192 int opn;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002193 union {
2194 char *s;
2195 rstream *rsm;
2196 FILE *F;
2197 var *v;
2198 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002199 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002200 } X;
2201
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002202 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002203 return setvar_s(res, NULL);
2204
2205 v1 = nvalloc(2);
2206
2207 while (op) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002208 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002209 opn = (opinfo & OPNMASK);
2210 g_lineno = op->lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002211
Mike Frysingerde2b9382005-09-27 03:18:00 +00002212 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002213 op1 = op->l.n;
2214 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2215 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2216 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2217 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2218 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2219
2220 switch (XC(opinfo & OPCLSMASK)) {
2221
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002222 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002223
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002224 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002225 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002226 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2227 /* it's range pattern */
2228 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2229 op->info |= OF_CHECKED;
2230 if (ptest(op1->r.n))
2231 op->info &= ~OF_CHECKED;
2232
2233 op = op->a.n;
2234 } else {
2235 op = op->r.n;
2236 }
2237 } else {
2238 op = (ptest(op1)) ? op->a.n : op->r.n;
2239 }
2240 break;
2241
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002242 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002243 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002244 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002245
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002246 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002247 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002248 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002249 break;
2250
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002251 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002252 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002253 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002254 break;
2255
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002256 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002257 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002258 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2259 break;
2260
Denis Vlasenkof782f522007-01-01 23:51:30 +00002261 case XC( OC_PRINT ):
2262 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002263 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002264 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002265 X.rsm = newfile(R.s);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002266 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002267 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002268 X.rsm->F = popen(R.s, "w");
2269 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002270 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002271 X.rsm->is_pipe = 1;
2272 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002273 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002274 }
2275 }
2276 X.F = X.rsm->F;
2277 }
2278
2279 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002280 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002281 fputs(getvar_s(intvar[F0]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002282 } else {
2283 while (op1) {
2284 L.v = evaluate(nextarg(&op1), v1);
2285 if (L.v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002286 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002287 getvar_i(L.v), TRUE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002288 fputs(g_buf, X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002289 } else {
2290 fputs(getvar_s(L.v), X.F);
2291 }
2292
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002293 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002294 }
2295 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002296 fputs(getvar_s(intvar[ORS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002297
2298 } else { /* OC_PRINTF */
2299 L.s = awk_printf(op1);
2300 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002301 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002302 }
2303 fflush(X.F);
2304 break;
2305
Denis Vlasenkof782f522007-01-01 23:51:30 +00002306 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002307 X.info = op1->info & OPCLSMASK;
2308 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002309 R.v = op1->l.v;
2310 } else if (X.info == OC_FNARG) {
2311 R.v = &fnargs[op1->l.i];
2312 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002313 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002314 }
2315
Mike Frysingerde2b9382005-09-27 03:18:00 +00002316 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002317 clrvar(L.v);
2318 L.s = getvar_s(evaluate(op1->r.n, v1));
2319 hash_remove(iamarray(R.v), L.s);
2320 } else {
2321 clear_array(iamarray(R.v));
2322 }
2323 break;
2324
Denis Vlasenkof782f522007-01-01 23:51:30 +00002325 case XC( OC_NEWSOURCE ):
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002326 g_progname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002327 break;
2328
Denis Vlasenkof782f522007-01-01 23:51:30 +00002329 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002330 copyvar(res, L.v);
2331 break;
2332
Denis Vlasenkof782f522007-01-01 23:51:30 +00002333 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002334 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002335 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002336 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002337 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002338 clrvar(res);
2339 break;
2340
Denis Vlasenkof782f522007-01-01 23:51:30 +00002341 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002342 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002343
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002344 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002345
Denis Vlasenkof782f522007-01-01 23:51:30 +00002346 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002347 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002348 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002349 split_f0();
2350 goto v_cont;
2351
Denis Vlasenkof782f522007-01-01 23:51:30 +00002352 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002353 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002354 v_cont:
2355 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002356 break;
2357
Denis Vlasenkof782f522007-01-01 23:51:30 +00002358 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002359 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2360 break;
2361
Denis Vlasenkof782f522007-01-01 23:51:30 +00002362 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002363 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002364 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002365 goto re_cont;
2366
Denis Vlasenkof782f522007-01-01 23:51:30 +00002367 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002368 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002369 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002370 X.re = as_regex(op1, &sreg);
2371 R.i = regexec(X.re, L.s, 0, NULL, 0);
2372 if (X.re == &sreg) regfree(X.re);
2373 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2374 break;
2375
Denis Vlasenkof782f522007-01-01 23:51:30 +00002376 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002377 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002378 if (R.v == v1+1 && R.v->string) {
2379 res = setvar_p(L.v, R.v->string);
2380 R.v->string = NULL;
2381 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002382 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002383 }
2384 break;
2385
Denis Vlasenkof782f522007-01-01 23:51:30 +00002386 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002387 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002388 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002389 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2390 break;
2391
Denis Vlasenkof782f522007-01-01 23:51:30 +00002392 case XC( OC_FUNC ):
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002393 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002394 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002395
2396 X.v = R.v = nvalloc(op->r.f->nargs+1);
2397 while (op1) {
2398 L.v = evaluate(nextarg(&op1), v1);
2399 copyvar(R.v, L.v);
2400 R.v->type |= VF_CHILD;
2401 R.v->x.parent = L.v;
2402 if (++R.v - X.v >= op->r.f->nargs)
2403 break;
2404 }
2405
2406 R.v = fnargs;
2407 fnargs = X.v;
2408
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002409 L.s = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002410 res = evaluate(op->r.f->body.first, res);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002411 g_progname = L.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002412
2413 nvfree(fnargs);
2414 fnargs = R.v;
2415 break;
2416
Denis Vlasenkof782f522007-01-01 23:51:30 +00002417 case XC( OC_GETLINE ):
2418 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002419 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002420 X.rsm = newfile(L.s);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002421 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002422 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2423 X.rsm->F = popen(L.s, "r");
2424 X.rsm->is_pipe = TRUE;
2425 } else {
Denis Vlasenko5415c852008-07-21 23:05:26 +00002426 X.rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002427 }
2428 }
2429 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002430 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002431 X.rsm = iF;
2432 }
2433
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002434 if (!X.rsm->F) {
2435 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002436 setvar_i(res, -1);
2437 break;
2438 }
2439
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002440 if (!op->r.n)
2441 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002442
2443 L.i = awk_getline(X.rsm, R.v);
2444 if (L.i > 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002445 if (!op1) {
2446 incvar(intvar[FNR]);
2447 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002448 }
2449 }
2450 setvar_i(res, L.i);
2451 break;
2452
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002453 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002454 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002455 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002456
Denis Vlasenkof782f522007-01-01 23:51:30 +00002457 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002458 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002459 break;
2460
Denis Vlasenkof782f522007-01-01 23:51:30 +00002461 case F_rn:
2462 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002463 break;
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002464#if ENABLE_FEATURE_AWK_LIBM
Denis Vlasenkof782f522007-01-01 23:51:30 +00002465 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002466 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002467 break;
2468
Denis Vlasenkof782f522007-01-01 23:51:30 +00002469 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002470 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002471 break;
2472
Denis Vlasenkof782f522007-01-01 23:51:30 +00002473 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002474 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002475 break;
2476
Denis Vlasenkof782f522007-01-01 23:51:30 +00002477 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002478 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002479 break;
2480
Denis Vlasenkof782f522007-01-01 23:51:30 +00002481 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002482 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002483 break;
2484#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002485 case F_co:
2486 case F_ex:
2487 case F_lg:
2488 case F_si:
2489 case F_sq:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002490 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002491 break;
2492#endif
Denis Vlasenkof782f522007-01-01 23:51:30 +00002493 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002494 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002495 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002496 srand(seed);
2497 break;
2498
Denis Vlasenkof782f522007-01-01 23:51:30 +00002499 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002500 R.d = time(NULL);
2501 break;
2502
Denis Vlasenkof782f522007-01-01 23:51:30 +00002503 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002504 if (!op1)
2505 L.s = getvar_s(intvar[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002506 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002507 break;
2508
Denis Vlasenkof782f522007-01-01 23:51:30 +00002509 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002510 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002511 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2512 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002513 break;
2514
Denis Vlasenkof782f522007-01-01 23:51:30 +00002515 case F_ff:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002516 if (!op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002517 fflush(stdout);
2518 else {
2519 if (L.s && *L.s) {
2520 X.rsm = newfile(L.s);
2521 fflush(X.rsm->F);
2522 } else {
2523 fflush(NULL);
2524 }
2525 }
2526 break;
2527
Denis Vlasenkof782f522007-01-01 23:51:30 +00002528 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002529 X.rsm = (rstream *)hash_search(fdhash, L.s);
2530 if (X.rsm) {
2531 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002532 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002533 hash_remove(fdhash, L.s);
2534 }
2535 if (R.i != 0)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002536 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002537 R.d = (double)R.i;
2538 break;
2539 }
2540 setvar_i(res, R.d);
2541 break;
2542
Denis Vlasenkof782f522007-01-01 23:51:30 +00002543 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002544 res = exec_builtin(op, res);
2545 break;
2546
Denis Vlasenkof782f522007-01-01 23:51:30 +00002547 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002548 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002549 break;
2550
Denis Vlasenkof782f522007-01-01 23:51:30 +00002551 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002552 X.v = R.v;
2553 L.d = R.d = getvar_i(R.v);
2554 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002555 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002556 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002557 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002558 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002559 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002560 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002561 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002562 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002563 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002564 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002565 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002566 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002567 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002568 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002569 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002570 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002571 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002572 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002573 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002574 setvar_i(X.v, R.d);
2575 }
2576 setvar_i(res, L.d);
2577 break;
2578
Denis Vlasenkof782f522007-01-01 23:51:30 +00002579 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002580 R.i = (int)getvar_i(R.v);
2581 if (R.i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002582 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002583 } else {
2584 split_f0();
2585 if (R.i > nfields)
2586 fsrealloc(R.i);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002587 res = &Fields[R.i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002588 }
2589 break;
2590
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002591 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002592 case XC( OC_CONCAT ):
2593 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002594 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002595 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002596 strcpy(X.s, L.s);
2597 if ((opinfo & OPCLSMASK) == OC_COMMA) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002598 L.s = getvar_s(intvar[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002599 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002600 strcat(X.s, L.s);
2601 }
2602 strcat(X.s, R.s);
2603 setvar_p(res, X.s);
2604 break;
2605
Denis Vlasenkof782f522007-01-01 23:51:30 +00002606 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002607 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2608 break;
2609
Denis Vlasenkof782f522007-01-01 23:51:30 +00002610 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002611 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2612 break;
2613
Denis Vlasenkof782f522007-01-01 23:51:30 +00002614 case XC( OC_BINARY ):
2615 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002616 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002617 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002618 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002619 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002620 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002621 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002622 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002623 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002624 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002625 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002626 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002627 case '/':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002628 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
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 Vlasenko2d5bd802008-10-24 10:49:49 +00002632#if ENABLE_FEATURE_AWK_LIBM
Mike Frysingerde2b9382005-09-27 03:18:00 +00002633 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002634#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002635 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002636#endif
2637 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002638 case '%':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002639 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002640 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002641 break;
2642 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002643 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002644 break;
2645
Denis Vlasenkof782f522007-01-01 23:51:30 +00002646 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002647 if (is_numeric(L.v) && is_numeric(R.v)) {
2648 L.d = getvar_i(L.v) - getvar_i(R.v);
2649 } else {
2650 L.s = getvar_s(L.v);
2651 R.s = getvar_s(R.v);
2652 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2653 }
2654 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002655 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002656 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002657 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002658 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002659 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002660 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002661 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002662 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002663 break;
2664 }
2665 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2666 break;
2667
Denis Vlasenkof782f522007-01-01 23:51:30 +00002668 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002669 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002670 }
2671 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2672 op = op->a.n;
2673 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2674 break;
2675 if (nextrec)
2676 break;
2677 }
2678 nvfree(v1);
2679 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002680#undef fnargs
2681#undef seed
2682#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002683}
2684
2685
2686/* -------- main & co. -------- */
2687
Mike Frysinger10a11e22005-09-27 02:23:02 +00002688static int awk_exit(int r)
2689{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002690 var tv;
2691 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002692 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002693
Denis Vlasenkof782f522007-01-01 23:51:30 +00002694 zero_out_var(&tv);
2695
2696 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002697 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002698 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002699 evaluate(endseq.first, &tv);
2700 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002701
2702 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002703 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002704 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002705 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002706 if (hi->data.rs.F && hi->data.rs.is_pipe)
2707 pclose(hi->data.rs.F);
2708 hi = hi->next;
2709 }
2710 }
2711
2712 exit(r);
2713}
2714
2715/* if expr looks like "var=value", perform assignment and return 1,
2716 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002717static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002718{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002719 char *exprc, *s, *s0, *s1;
2720
Rob Landleyd921b2e2006-08-03 15:41:12 +00002721 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002722 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2723 free(exprc);
2724 return FALSE;
2725 }
2726
2727 *(s++) = '\0';
2728 s0 = s1 = s;
2729 while (*s)
2730 *(s1++) = nextchar(&s);
2731
2732 *s1 = '\0';
2733 setvar_u(newvar(exprc), s0);
2734 free(exprc);
2735 return TRUE;
2736}
2737
2738/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002739static rstream *next_input_file(void)
2740{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002741#define rsm (G.next_input_file__rsm)
2742#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002743
Glenn L McGrath545106f2002-11-11 06:21:00 +00002744 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002745 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002746
2747 if (rsm.F) fclose(rsm.F);
2748 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002749 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002750
2751 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002752 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002753 if (files_happen)
2754 return NULL;
2755 fname = "-";
2756 F = stdin;
2757 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002758 ind = getvar_s(incvar(intvar[ARGIND]));
2759 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002760 if (fname && *fname && !is_assignment(fname))
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002761 F = xfopen_stdin(fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002762 }
2763 } while (!F);
2764
2765 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002766 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002767 rsm.F = F;
2768 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002769#undef rsm
2770#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002771}
2772
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002773int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00002774int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002775{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002776 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002777 char *opt_F, *opt_W;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002778 llist_t *list_v = NULL;
2779 llist_t *list_f = NULL;
2780 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002781 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002782 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002783 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002784 char *vnames = (char *)vNames; /* cheat */
2785 char *vvalues = (char *)vValues;
2786
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002787 INIT_G();
2788
Denis Vlasenko150f4022007-01-13 21:06:21 +00002789 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002790 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2791 if (ENABLE_LOCALE_SUPPORT)
2792 setlocale(LC_NUMERIC, "C");
2793
Denis Vlasenkof782f522007-01-01 23:51:30 +00002794 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002795
2796 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002797 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002798
2799 vhash = hash_init();
2800 ahash = hash_init();
2801 fdhash = hash_init();
2802 fnhash = hash_init();
2803
2804 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002805 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002806 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00002807 if (*vvalues != '\377')
2808 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002809 else
2810 setvar_i(v, 0);
2811
Denis Vlasenkof782f522007-01-01 23:51:30 +00002812 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002813 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002814 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002815 }
2816 }
2817
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002818 handle_special(intvar[FS]);
2819 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002820
Denis Vlasenkof782f522007-01-01 23:51:30 +00002821 newfile("/dev/stdin")->F = stdin;
2822 newfile("/dev/stdout")->F = stdout;
2823 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002824
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002825 /* Huh, people report that sometimes environ is NULL. Oh well. */
2826 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002827 /* environ is writable, thus we don't strdup it needlessly */
2828 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002829 char *s1 = strchr(s, '=');
2830 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002831 *s1 = '\0';
2832 /* Both findvar and setvar_u take const char*
2833 * as 2nd arg -> environment is not trashed */
2834 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
2835 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00002836 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002837 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002838 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
2839 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002840 argv += optind;
2841 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002842 if (opt & 0x1)
2843 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002844 while (list_v) { /* -v */
2845 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002846 bb_show_usage();
2847 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002848 if (list_f) { /* -f */
2849 do {
2850 char *s = NULL;
2851 FILE *from_file;
2852
2853 g_progname = llist_pop(&list_f);
2854 from_file = xfopen_stdin(g_progname);
2855 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002856 for (i = j = 1; j > 0; i += j) {
2857 s = xrealloc(s, i + 4096);
2858 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002859 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002860 s[i] = '\0';
2861 fclose(from_file);
2862 parse_program(s + 1);
2863 free(s);
2864 } while (list_f);
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00002865 argc++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002866 } else { // no -f: take program from 1st parameter
2867 if (!argc)
2868 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002869 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00002870 parse_program(*argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002871 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002872 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002873 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002874
Glenn L McGrath545106f2002-11-11 06:21:00 +00002875 /* fill in ARGV array */
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00002876 setvar_i(intvar[ARGC], argc);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002877 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002878 i = 0;
2879 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002880 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002881
2882 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002883 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002884 awk_exit(EXIT_SUCCESS);
2885
2886 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002887 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002888
2889 /* passing through input files */
2890 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002891 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002892 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002893
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002894 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002895 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002896 incvar(intvar[NR]);
2897 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002898 evaluate(mainseq.first, &tv);
2899
2900 if (nextfile)
2901 break;
2902 }
2903
Denis Vlasenkof782f522007-01-01 23:51:30 +00002904 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002905 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002906
2907 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002908 }
2909
Glenn L McGrath545106f2002-11-11 06:21:00 +00002910 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002911 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002912}