blob: ae7ca23d4cb67aa1f3495a0a785560c790b30faa [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
Glenn L McGrath545106f2002-11-11 06:21:00 +000010#include "busybox.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
14
15#define MAXVARFMT 240
16#define MINNVBLOCK 64
17
18/* variable flags */
19#define VF_NUMBER 0x0001 /* 1 = primary type is number */
20#define VF_ARRAY 0x0002 /* 1 = it's an array */
21
22#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
23#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
24#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
25#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
26#define VF_FSTR 0x1000 /* 1 = string points to fstring buffer */
27#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
28#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
29
30/* these flags are static, don't change them when value is changed */
31#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
32
33/* Variable */
34typedef struct var_s {
35 unsigned short type; /* flags */
36 double number;
37 char *string;
38 union {
Mike Frysinger4b7b8a52006-04-16 05:55:15 +000039 int aidx; /* func arg idx (for compilation stage) */
Glenn L McGrath545106f2002-11-11 06:21:00 +000040 struct xhash_s *array; /* array ptr */
41 struct var_s *parent; /* for func args, ptr to actual parameter */
42 char **walker; /* list of array elements (for..in) */
43 } x;
44} var;
45
46/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
47typedef struct chain_s {
48 struct node_s *first;
49 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +000050 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +000051} chain;
52
53/* Function */
54typedef struct func_s {
55 unsigned short nargs;
56 struct chain_s body;
57} func;
58
59/* I/O stream */
60typedef struct rstream_s {
61 FILE *F;
62 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +000063 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +000064 int size;
65 int pos;
66 unsigned short is_pipe;
67} rstream;
68
69typedef struct hash_item_s {
70 union {
71 struct var_s v; /* variable/array hash */
72 struct rstream_s rs; /* redirect streams hash */
73 struct func_s f; /* functions hash */
74 } data;
75 struct hash_item_s *next; /* next in chain */
76 char name[1]; /* really it's longer */
77} hash_item;
78
79typedef struct xhash_s {
Denis Vlasenkof782f522007-01-01 23:51:30 +000080 unsigned nel; /* num of elements */
81 unsigned csize; /* current hash size */
82 unsigned nprime; /* next hash size in PRIMES[] */
83 unsigned glen; /* summary length of item names */
Glenn L McGrath545106f2002-11-11 06:21:00 +000084 struct hash_item_s **items;
85} xhash;
86
87/* Tree node */
88typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +000089 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +000090 unsigned short lineno;
91 union {
92 struct node_s *n;
93 var *v;
94 int i;
95 char *s;
96 regex_t *re;
97 } l;
98 union {
99 struct node_s *n;
100 regex_t *ire;
101 func *f;
102 int argno;
103 } r;
104 union {
105 struct node_s *n;
106 } a;
107} node;
108
109/* Block of temporary variables */
110typedef struct nvblock_s {
111 int size;
112 var *pos;
113 struct nvblock_s *prev;
114 struct nvblock_s *next;
115 var nv[0];
116} nvblock;
117
118typedef struct tsplitter_s {
119 node n;
120 regex_t re[2];
121} tsplitter;
122
123/* simple token classes */
124/* Order and hex values are very important!!! See next_token() */
125#define TC_SEQSTART 1 /* ( */
126#define TC_SEQTERM (1 << 1) /* ) */
127#define TC_REGEXP (1 << 2) /* /.../ */
128#define TC_OUTRDR (1 << 3) /* | > >> */
129#define TC_UOPPOST (1 << 4) /* unary postfix operator */
130#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
131#define TC_BINOPX (1 << 6) /* two-opnd operator */
132#define TC_IN (1 << 7)
133#define TC_COMMA (1 << 8)
134#define TC_PIPE (1 << 9) /* input redirection pipe */
135#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
136#define TC_ARRTERM (1 << 11) /* ] */
137#define TC_GRPSTART (1 << 12) /* { */
138#define TC_GRPTERM (1 << 13) /* } */
139#define TC_SEMICOL (1 << 14)
140#define TC_NEWLINE (1 << 15)
141#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
142#define TC_WHILE (1 << 17)
143#define TC_ELSE (1 << 18)
144#define TC_BUILTIN (1 << 19)
145#define TC_GETLINE (1 << 20)
146#define TC_FUNCDECL (1 << 21) /* `function' `func' */
147#define TC_BEGIN (1 << 22)
148#define TC_END (1 << 23)
149#define TC_EOF (1 << 24)
150#define TC_VARIABLE (1 << 25)
151#define TC_ARRAY (1 << 26)
152#define TC_FUNCTION (1 << 27)
153#define TC_STRING (1 << 28)
154#define TC_NUMBER (1 << 29)
155
156#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
157
158/* combined token classes */
159#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
160#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
161#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION | \
162 TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
163
164#define TC_STATEMNT (TC_STATX | TC_WHILE)
165#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
166
167/* word tokens, cannot mean something else if not expected */
168#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN | \
169 TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
170
171/* discard newlines after these */
172#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM | \
173 TC_BINOP | TC_OPTERM)
174
175/* what can expression begin with */
176#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
177/* what can group begin with */
178#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
179
180/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
181/* operator is inserted between them */
182#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM | \
183 TC_STRING | TC_NUMBER | TC_UOPPOST)
184#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
185
186#define OF_RES1 0x010000
187#define OF_RES2 0x020000
188#define OF_STR1 0x040000
189#define OF_STR2 0x080000
190#define OF_NUM1 0x100000
191#define OF_CHECKED 0x200000
192
193/* combined operator flags */
194#define xx 0
195#define xV OF_RES2
196#define xS (OF_RES2 | OF_STR2)
197#define Vx OF_RES1
198#define VV (OF_RES1 | OF_RES2)
199#define Nx (OF_RES1 | OF_NUM1)
200#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
201#define Sx (OF_RES1 | OF_STR1)
202#define SV (OF_RES1 | OF_STR1 | OF_RES2)
203#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
204
205#define OPCLSMASK 0xFF00
206#define OPNMASK 0x007F
207
208/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
209 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
210 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
211 */
212#define P(x) (x << 24)
213#define PRIMASK 0x7F000000
214#define PRIMASK2 0x7E000000
215
216/* Operation classes */
217
218#define SHIFT_TIL_THIS 0x0600
219#define RECUR_FROM_THIS 0x1000
220
221enum {
222 OC_DELETE=0x0100, OC_EXEC=0x0200, OC_NEWSOURCE=0x0300,
223 OC_PRINT=0x0400, OC_PRINTF=0x0500, OC_WALKINIT=0x0600,
224
225 OC_BR=0x0700, OC_BREAK=0x0800, OC_CONTINUE=0x0900,
226 OC_EXIT=0x0a00, OC_NEXT=0x0b00, OC_NEXTFILE=0x0c00,
227 OC_TEST=0x0d00, OC_WALKNEXT=0x0e00,
228
229 OC_BINARY=0x1000, OC_BUILTIN=0x1100, OC_COLON=0x1200,
230 OC_COMMA=0x1300, OC_COMPARE=0x1400, OC_CONCAT=0x1500,
231 OC_FBLTIN=0x1600, OC_FIELD=0x1700, OC_FNARG=0x1800,
232 OC_FUNC=0x1900, OC_GETLINE=0x1a00, OC_IN=0x1b00,
233 OC_LAND=0x1c00, OC_LOR=0x1d00, OC_MATCH=0x1e00,
234 OC_MOVE=0x1f00, OC_PGETLINE=0x2000, OC_REGEXP=0x2100,
235 OC_REPLACE=0x2200, OC_RETURN=0x2300, OC_SPRINTF=0x2400,
236 OC_TERNARY=0x2500, OC_UNARY=0x2600, OC_VAR=0x2700,
237 OC_DONE=0x2800,
238
239 ST_IF=0x3000, ST_DO=0x3100, ST_FOR=0x3200,
240 ST_WHILE=0x3300
241};
242
243/* simple builtins */
244enum {
245 F_in=0, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
246 F_ti, F_le, F_sy, F_ff, F_cl
247};
248
249/* builtins */
250enum {
251 B_a2=0, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up,
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000252 B_ge, B_gs, B_su,
253 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000254};
255
256/* tokens and their corresponding info values */
257
258#define NTC "\377" /* switch to next token class (tc<<1) */
259#define NTCC '\377'
260
261#define OC_B OC_BUILTIN
262
Denis Vlasenkof782f522007-01-01 23:51:30 +0000263static const char tokenlist[] =
264 "\1(" NTC
265 "\1)" NTC
266 "\1/" NTC /* REGEXP */
267 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
268 "\2++" "\2--" NTC /* UOPPOST */
269 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
270 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
271 "\2*=" "\2/=" "\2%=" "\2^="
272 "\1+" "\1-" "\3**=" "\2**"
273 "\1/" "\1%" "\1^" "\1*"
274 "\2!=" "\2>=" "\2<=" "\1>"
275 "\1<" "\2!~" "\1~" "\2&&"
276 "\2||" "\1?" "\1:" NTC
277 "\2in" NTC
278 "\1," NTC
279 "\1|" NTC
280 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
281 "\1]" NTC
282 "\1{" NTC
283 "\1}" NTC
284 "\1;" NTC
285 "\1\n" NTC
286 "\2if" "\2do" "\3for" "\5break" /* STATX */
287 "\10continue" "\6delete" "\5print"
288 "\6printf" "\4next" "\10nextfile"
289 "\6return" "\4exit" NTC
290 "\5while" NTC
291 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000292
Denis Vlasenkof782f522007-01-01 23:51:30 +0000293 "\3and" "\5compl" "\6lshift" "\2or"
294 "\6rshift" "\3xor"
295 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
296 "\3cos" "\3exp" "\3int" "\3log"
297 "\4rand" "\3sin" "\4sqrt" "\5srand"
298 "\6gensub" "\4gsub" "\5index" "\6length"
299 "\5match" "\5split" "\7sprintf" "\3sub"
300 "\6substr" "\7systime" "\10strftime"
301 "\7tolower" "\7toupper" NTC
302 "\7getline" NTC
303 "\4func" "\10function" NTC
304 "\5BEGIN" NTC
305 "\3END" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000306 ;
307
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000308static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000309 0,
310 0,
311 OC_REGEXP,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000312 xS|'a', xS|'w', xS|'|',
313 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
314 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M',
315 OC_FIELD|xV|P(5),
316 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74),
317 OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
318 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/',
319 OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
320 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-',
321 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
322 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%',
323 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
324 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
325 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
326 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
327 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
328 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
329 OC_COLON|xx|P(67)|':',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000330 OC_IN|SV|P(49),
331 OC_COMMA|SS|P(80),
332 OC_PGETLINE|SV|P(37),
Denis Vlasenkof782f522007-01-01 23:51:30 +0000333 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',
334 OC_UNARY|xV|P(19)|'!',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000335 0,
336 0,
337 0,
338 0,
339 0,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000340 ST_IF, ST_DO, ST_FOR, OC_BREAK,
341 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
342 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
343 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000344 ST_WHILE,
345 0,
346
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000347 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
348 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000349 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
350 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
351 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
352 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
353 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
354 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b),
355 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
356 OC_GETLINE|SV|P(0),
357 0, 0,
358 0,
359 0
360};
361
362/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000363/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000364enum {
Denis Vlasenkof782f522007-01-01 23:51:30 +0000365 CONVFMT=0, OFMT, FS, OFS,
366 ORS, RS, RT, FILENAME,
367 SUBSEP, ARGIND, ARGC, ARGV,
368 ERRNO, FNR,
369 NR, NF, IGNORECASE,
370 ENVIRON, F0, _intvarcount_
Glenn L McGrath545106f2002-11-11 06:21:00 +0000371};
372
Denis Vlasenkof782f522007-01-01 23:51:30 +0000373static const char vNames[] =
374 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
375 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
376 "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0"
377 "ERRNO\0" "FNR\0"
378 "NR\0" "NF\0*" "IGNORECASE\0*"
379 "ENVIRON\0" "$\0*" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000380
Denis Vlasenkof782f522007-01-01 23:51:30 +0000381static const char vValues[] =
382 "%.6g\0" "%.6g\0" " \0" " \0"
383 "\n\0" "\n\0" "\0" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000384 "\034\0"
385 "\377";
386
387/* hash size may grow to these values */
388#define FIRST_PRIME 61;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000389static const unsigned PRIMES[] = { 251, 1021, 4093, 16381, 65521 };
390enum { NPRIMES = sizeof(PRIMES) / sizeof(unsigned) };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000391
392/* globals */
393
394extern char **environ;
395
396static var * V[_intvarcount_];
397static chain beginseq, mainseq, endseq, *seq;
398static int nextrec, nextfile;
399static node *break_ptr, *continue_ptr;
400static rstream *iF;
401static xhash *vhash, *ahash, *fdhash, *fnhash;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000402static const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000403static short lineno;
404static int is_f0_split;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000405static int nfields;
406static var *Fields;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000407static tsplitter fsplitter, rsplitter;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000408static nvblock *cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000409static char *pos;
410static char *buf;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000411static int icase;
412static int exiting;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000413
414static struct {
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000415 uint32_t tclass;
416 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000417 char *string;
418 double number;
419 short lineno;
420 int rollback;
421} t;
422
423/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000424static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000425static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000426static void chain_group(void);
427static var *evaluate(node *, var *);
428static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000429static int fmt_num(char *, int, const char *, double, int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000430static int awk_exit(int) ATTRIBUTE_NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000431
432/* ---- error handling ---- */
433
434static const char EMSG_INTERNAL_ERROR[] = "Internal error";
435static const char EMSG_UNEXP_EOS[] = "Unexpected end of string";
436static const char EMSG_UNEXP_TOKEN[] = "Unexpected token";
437static const char EMSG_DIV_BY_ZERO[] = "Division by zero";
438static const char EMSG_INV_FMT[] = "Invalid format specifier";
439static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin";
440static const char EMSG_NOT_ARRAY[] = "Not an array";
441static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error";
442static const char EMSG_UNDEF_FUNC[] = "Call to undefined function";
Denis Vlasenkof782f522007-01-01 23:51:30 +0000443#if !ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +0000444static const char EMSG_NO_MATH[] = "Math support is not compiled in";
445#endif
446
Denis Vlasenkof782f522007-01-01 23:51:30 +0000447static void zero_out_var(var * vp)
448{
449 memset(vp, 0, sizeof(*vp));
450}
451
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000452static void syntax_error(const char * const message) ATTRIBUTE_NORETURN;
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000453static void syntax_error(const char * const message)
454{
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000455 bb_error_msg_and_die("%s:%i: %s", programname, lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000456}
457
458#define runtime_error(x) syntax_error(x)
459
460
461/* ---- hash stuff ---- */
462
Denis Vlasenkof782f522007-01-01 23:51:30 +0000463static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000464{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000465 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000466
Denis Vlasenkof782f522007-01-01 23:51:30 +0000467 while (*name) idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000468 return idx;
469}
470
471/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000472static xhash *hash_init(void)
473{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000474 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000475
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000476 newhash = xzalloc(sizeof(xhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000477 newhash->csize = FIRST_PRIME;
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000478 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000479
480 return newhash;
481}
482
483/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000484static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000485{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000486 hash_item *hi;
487
488 hi = hash->items [ hashidx(name) % hash->csize ];
489 while (hi) {
490 if (strcmp(hi->name, name) == 0)
491 return &(hi->data);
492 hi = hi->next;
493 }
494 return NULL;
495}
496
497/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000498static void hash_rebuild(xhash *hash)
499{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000500 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000501 hash_item **newitems, *hi, *thi;
502
503 if (hash->nprime == NPRIMES)
504 return;
505
506 newsize = PRIMES[hash->nprime++];
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000507 newitems = xzalloc(newsize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000508
509 for (i=0; i<hash->csize; i++) {
510 hi = hash->items[i];
511 while (hi) {
512 thi = hi;
513 hi = thi->next;
514 idx = hashidx(thi->name) % newsize;
515 thi->next = newitems[idx];
516 newitems[idx] = thi;
517 }
518 }
519
520 free(hash->items);
521 hash->csize = newsize;
522 hash->items = newitems;
523}
524
525/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000526static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000527{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000528 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000529 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000530 int l;
531
532 hi = hash_search(hash, name);
533 if (! hi) {
534 if (++hash->nel / hash->csize > 10)
535 hash_rebuild(hash);
536
Rob Landleya3896512006-05-07 20:20:34 +0000537 l = strlen(name) + 1;
Rob Landley9ffd4232006-05-21 18:30:35 +0000538 hi = xzalloc(sizeof(hash_item) + l);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000539 memcpy(hi->name, name, l);
540
541 idx = hashidx(name) % hash->csize;
542 hi->next = hash->items[idx];
543 hash->items[idx] = hi;
544 hash->glen += l;
545 }
546 return &(hi->data);
547}
548
Denis Vlasenkof782f522007-01-01 23:51:30 +0000549#define findvar(hash, name) ((var*) hash_find((hash) , (name)))
550#define newvar(name) ((var*) hash_find(vhash , (name)))
551#define newfile(name) ((rstream*)hash_find(fdhash ,(name)))
552#define newfunc(name) ((func*) hash_find(fnhash , (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000553
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000554static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000555{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000556 hash_item *hi, **phi;
557
558 phi = &(hash->items[ hashidx(name) % hash->csize ]);
559 while (*phi) {
560 hi = *phi;
561 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000562 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000563 hash->nel--;
564 *phi = hi->next;
565 free(hi);
566 break;
567 }
568 phi = &(hi->next);
569 }
570}
571
572/* ------ some useful functions ------ */
573
Mike Frysinger10a11e22005-09-27 02:23:02 +0000574static void skip_spaces(char **s)
575{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000576 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000577
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000578 while (*p == ' ' || *p == '\t' ||
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000579 (*p == '\\' && *(p+1) == '\n' && (++p, ++t.lineno))) {
Mike Frysingerde2b9382005-09-27 03:18:00 +0000580 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000581 }
582 *s = p;
583}
584
Mike Frysinger10a11e22005-09-27 02:23:02 +0000585static char *nextword(char **s)
586{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000587 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000588
Denis Vlasenkof782f522007-01-01 23:51:30 +0000589 while (*(*s)++) /* */;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000590
591 return p;
592}
593
Mike Frysinger10a11e22005-09-27 02:23:02 +0000594static char nextchar(char **s)
595{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000596 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000597
598 c = *((*s)++);
599 pps = *s;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000600 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000601 if (c == '\\' && *s == pps) c = *((*s)++);
602 return c;
603}
604
Rob Landley88621d72006-08-29 19:41:06 +0000605static int ATTRIBUTE_ALWAYS_INLINE isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000606{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000607 return (isalnum(c) || c == '_');
608}
609
Mike Frysinger10a11e22005-09-27 02:23:02 +0000610static FILE *afopen(const char *path, const char *mode)
611{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000612 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000613}
614
615/* -------- working with variables (set/get/copy/etc) -------- */
616
Mike Frysinger10a11e22005-09-27 02:23:02 +0000617static xhash *iamarray(var *v)
618{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000619 var *a = v;
620
621 while (a->type & VF_CHILD)
622 a = a->x.parent;
623
624 if (! (a->type & VF_ARRAY)) {
625 a->type |= VF_ARRAY;
626 a->x.array = hash_init();
627 }
628 return a->x.array;
629}
630
Mike Frysinger10a11e22005-09-27 02:23:02 +0000631static void clear_array(xhash *array)
632{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000633 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000634 hash_item *hi, *thi;
635
636 for (i=0; i<array->csize; i++) {
637 hi = array->items[i];
638 while (hi) {
639 thi = hi;
640 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000641 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000642 free(thi);
643 }
644 array->items[i] = NULL;
645 }
646 array->glen = array->nel = 0;
647}
648
649/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000650static var *clrvar(var *v)
651{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000652 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000653 free(v->string);
654
655 v->type &= VF_DONTTOUCH;
656 v->type |= VF_DIRTY;
657 v->string = NULL;
658 return v;
659}
660
661/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000662static var *setvar_p(var *v, char *value)
663{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000664 clrvar(v);
665 v->string = value;
666 handle_special(v);
667
668 return v;
669}
670
671/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000672static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000673{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000674 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000675}
676
677/* same as setvar_s but set USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000678static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000679{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000680 setvar_s(v, value);
681 v->type |= VF_USER;
682 return v;
683}
684
685/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000686static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000687{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000688 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000689 static char sidx[12];
690
691 sprintf(sidx, "%d", idx);
692 v = findvar(iamarray(a), sidx);
693 setvar_u(v, s);
694}
695
696/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000697static var *setvar_i(var *v, double value)
698{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000699 clrvar(v);
700 v->type |= VF_NUMBER;
701 v->number = value;
702 handle_special(v);
703 return v;
704}
705
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000706static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000707{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000708 /* if v is numeric and has no cached string, convert it to string */
709 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
710 fmt_num(buf, MAXVARFMT, getvar_s(V[CONVFMT]), v->number, TRUE);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000711 v->string = xstrdup(buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000712 v->type |= VF_CACHED;
713 }
714 return (v->string == NULL) ? "" : v->string;
715}
716
Mike Frysinger10a11e22005-09-27 02:23:02 +0000717static double getvar_i(var *v)
718{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000719 char *s;
720
721 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
722 v->number = 0;
723 s = v->string;
724 if (s && *s) {
725 v->number = strtod(s, &s);
726 if (v->type & VF_USER) {
727 skip_spaces(&s);
728 if (*s != '\0')
729 v->type &= ~VF_USER;
730 }
731 } else {
732 v->type &= ~VF_USER;
733 }
734 v->type |= VF_CACHED;
735 }
736 return v->number;
737}
738
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000739static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000740{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000741 if (dest != src) {
742 clrvar(dest);
743 dest->type |= (src->type & ~VF_DONTTOUCH);
744 dest->number = src->number;
745 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000746 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000747 }
748 handle_special(dest);
749 return dest;
750}
751
Mike Frysinger10a11e22005-09-27 02:23:02 +0000752static var *incvar(var *v)
753{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000754 return setvar_i(v, getvar_i(v)+1.);
755}
756
757/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000758static int is_numeric(var *v)
759{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000760 getvar_i(v);
761 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
762}
763
764/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000765static int istrue(var *v)
766{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000767 if (is_numeric(v))
768 return (v->number == 0) ? 0 : 1;
769 else
770 return (v->string && *(v->string)) ? 1 : 0;
771}
772
Eric Andersenaff114c2004-04-14 17:51:38 +0000773/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000774static var *nvalloc(int n)
775{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000776 nvblock *pb = NULL;
777 var *v, *r;
778 int size;
779
780 while (cb) {
781 pb = cb;
782 if ((cb->pos - cb->nv) + n <= cb->size) break;
783 cb = cb->next;
784 }
785
786 if (! cb) {
787 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkob95636c2006-12-19 23:36:04 +0000788 cb = xmalloc(sizeof(nvblock) + size * sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000789 cb->size = size;
790 cb->pos = cb->nv;
791 cb->prev = pb;
792 cb->next = NULL;
793 if (pb) pb->next = cb;
794 }
795
796 v = r = cb->pos;
797 cb->pos += n;
798
799 while (v < cb->pos) {
800 v->type = 0;
801 v->string = NULL;
802 v++;
803 }
804
805 return r;
806}
807
Mike Frysinger10a11e22005-09-27 02:23:02 +0000808static void nvfree(var *v)
809{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000810 var *p;
811
812 if (v < cb->nv || v >= cb->pos)
813 runtime_error(EMSG_INTERNAL_ERROR);
814
815 for (p=v; p<cb->pos; p++) {
816 if ((p->type & (VF_ARRAY|VF_CHILD)) == VF_ARRAY) {
817 clear_array(iamarray(p));
818 free(p->x.array->items);
819 free(p->x.array);
820 }
821 if (p->type & VF_WALK)
822 free(p->x.walker);
823
824 clrvar(p);
825 }
826
827 cb->pos = v;
828 while (cb->prev && cb->pos == cb->nv) {
829 cb = cb->prev;
830 }
831}
832
833/* ------- awk program text parsing ------- */
834
835/* Parse next token pointed by global pos, place results into global t.
836 * If token isn't expected, give away. Return token class
837 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000838static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000839{
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000840 static int concat_inserted;
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000841 static uint32_t save_tclass, save_info;
842 static uint32_t ltclass = TC_OPTERM;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000843
Denis Vlasenkof782f522007-01-01 23:51:30 +0000844 char *p, *pp, *s;
845 const char *tl;
846 uint32_t tc;
847 const uint32_t *ti;
848 int l;
849
Glenn L McGrath545106f2002-11-11 06:21:00 +0000850 if (t.rollback) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000851 t.rollback = FALSE;
852
853 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000854 concat_inserted = FALSE;
855 t.tclass = save_tclass;
856 t.info = save_info;
857
858 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000859 p = pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000860 readnext:
Glenn L McGrath545106f2002-11-11 06:21:00 +0000861 skip_spaces(&p);
862 lineno = t.lineno;
863 if (*p == '#')
864 while (*p != '\n' && *p != '\0') p++;
865
866 if (*p == '\n')
867 t.lineno++;
868
869 if (*p == '\0') {
870 tc = TC_EOF;
871
872 } else if (*p == '\"') {
873 /* it's a string */
874 t.string = s = ++p;
875 while (*p != '\"') {
876 if (*p == '\0' || *p == '\n')
877 syntax_error(EMSG_UNEXP_EOS);
878 *(s++) = nextchar(&p);
879 }
880 p++;
881 *s = '\0';
882 tc = TC_STRING;
883
884 } else if ((expected & TC_REGEXP) && *p == '/') {
885 /* it's regexp */
886 t.string = s = ++p;
887 while (*p != '/') {
888 if (*p == '\0' || *p == '\n')
889 syntax_error(EMSG_UNEXP_EOS);
890 if ((*s++ = *p++) == '\\') {
891 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000892 *(s-1) = bb_process_escape_sequence((const char **)&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000893 if (*pp == '\\') *s++ = '\\';
894 if (p == pp) *s++ = *p++;
895 }
896 }
897 p++;
898 *s = '\0';
899 tc = TC_REGEXP;
900
901 } else if (*p == '.' || isdigit(*p)) {
902 /* it's a number */
903 t.number = strtod(p, &p);
904 if (*p == '.')
905 syntax_error(EMSG_UNEXP_TOKEN);
906 tc = TC_NUMBER;
907
908 } else {
909 /* search for something known */
910 tl = tokenlist;
911 tc = 0x00000001;
912 ti = tokeninfo;
913 while (*tl) {
914 l = *(tl++);
915 if (l == NTCC) {
916 tc <<= 1;
917 continue;
918 }
919 /* if token class is expected, token
920 * matches and it's not a longer word,
921 * then this is what we are looking for
922 */
923 if ((tc & (expected | TC_WORD | TC_NEWLINE)) &&
924 *tl == *p && strncmp(p, tl, l) == 0 &&
925 !((tc & TC_WORD) && isalnum_(*(p + l)))) {
926 t.info = *ti;
927 p += l;
928 break;
929 }
930 ti++;
931 tl += l;
932 }
933
Denis Vlasenkof782f522007-01-01 23:51:30 +0000934 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000935 /* it's a name (var/array/function),
936 * otherwise it's something wrong
937 */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000938 if (!isalnum_(*p))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000939 syntax_error(EMSG_UNEXP_TOKEN);
940
941 t.string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000942 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000943 *(p-1) = *p;
944 }
945 *(p-1) = '\0';
946 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +0000947 /* also consume whitespace between functionname and bracket */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000948 if (!(expected & TC_VARIABLE)) skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000949 if (*p == '(') {
950 tc = TC_FUNCTION;
951 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000952 if (*p == '[') {
953 p++;
954 tc = TC_ARRAY;
955 }
956 }
957 }
958 }
959 pos = p;
960
961 /* skipping newlines in some cases */
962 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
963 goto readnext;
964
965 /* insert concatenation operator when needed */
966 if ((ltclass&TC_CONCAT1) && (tc&TC_CONCAT2) && (expected&TC_BINOP)) {
967 concat_inserted = TRUE;
968 save_tclass = tc;
969 save_info = t.info;
970 tc = TC_BINOP;
971 t.info = OC_CONCAT | SS | P(35);
972 }
973
974 t.tclass = tc;
975 }
976 ltclass = t.tclass;
977
978 /* Are we ready for this? */
979 if (! (ltclass & expected))
980 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
981 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
982
983 return ltclass;
984}
985
986static void rollback_token(void) { t.rollback = TRUE; }
987
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000988static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000989{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000990 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000991
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000992 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000993 n->info = info;
994 n->lineno = lineno;
995 return n;
996}
997
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000998static node *mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000999{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001000 n->info = OC_REGEXP;
1001 n->l.re = re;
1002 n->r.ire = re + 1;
1003 xregcomp(re, s, REG_EXTENDED);
1004 xregcomp(re+1, s, REG_EXTENDED | REG_ICASE);
1005
1006 return n;
1007}
1008
Mike Frysinger10a11e22005-09-27 02:23:02 +00001009static node *condition(void)
1010{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001011 next_token(TC_SEQSTART);
1012 return parse_expr(TC_SEQTERM);
1013}
1014
1015/* parse expression terminated by given argument, return ptr
1016 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001017static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001018{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001019 node sn;
1020 node *cn = &sn;
1021 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001022 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001023 var *v;
1024
1025 sn.info = PRIMASK;
1026 sn.r.n = glptr = NULL;
1027 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1028
1029 while (! ((tc = next_token(xtc)) & iexp)) {
1030 if (glptr && (t.info == (OC_COMPARE|VV|P(39)|2))) {
1031 /* input redirection (<) attached to glptr node */
1032 cn = glptr->l.n = new_node(OC_CONCAT|SS|P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001033 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001034 xtc = TC_OPERAND | TC_UOPPRE;
1035 glptr = NULL;
1036
1037 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1038 /* for binary and postfix-unary operators, jump back over
1039 * previous operators with higher priority */
1040 vn = cn;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001041 while ( ((t.info & PRIMASK) > (vn->a.n->info & PRIMASK2)) ||
Glenn L McGrath545106f2002-11-11 06:21:00 +00001042 ((t.info == vn->info) && ((t.info & OPCLSMASK) == OC_COLON)) )
1043 vn = vn->a.n;
1044 if ((t.info & OPCLSMASK) == OC_TERNARY)
1045 t.info += P(6);
1046 cn = vn->a.n->r.n = new_node(t.info);
1047 cn->a.n = vn->a.n;
1048 if (tc & TC_BINOP) {
1049 cn->l.n = vn;
1050 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1051 if ((t.info & OPCLSMASK) == OC_PGETLINE) {
1052 /* it's a pipe */
1053 next_token(TC_GETLINE);
1054 /* give maximum priority to this pipe */
1055 cn->info &= ~PRIMASK;
1056 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1057 }
1058 } else {
1059 cn->r.n = vn;
1060 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1061 }
1062 vn->a.n = cn;
1063
1064 } else {
1065 /* for operands and prefix-unary operators, attach them
1066 * to last node */
1067 vn = cn;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001068 cn = vn->r.n = new_node(t.info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001069 cn->a.n = vn;
1070 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1071 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001072 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001073 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001074 * only simple tclasses should be used! */
1075 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001076 case TC_VARIABLE:
1077 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001078 cn->info = OC_VAR;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001079 if ((v = hash_search(ahash, t.string)) != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001080 cn->info = OC_FNARG;
1081 cn->l.i = v->x.aidx;
1082 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00001083 cn->l.v = newvar(t.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001084 }
1085 if (tc & TC_ARRAY) {
1086 cn->info |= xS;
1087 cn->r.n = parse_expr(TC_ARRTERM);
1088 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001089 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001090
Denis Vlasenkof782f522007-01-01 23:51:30 +00001091 case TC_NUMBER:
1092 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001093 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001094 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001095 if (tc & TC_NUMBER)
1096 setvar_i(v, t.number);
1097 else
1098 setvar_s(v, t.string);
1099 break;
1100
Denis Vlasenkof782f522007-01-01 23:51:30 +00001101 case TC_REGEXP:
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001102 mk_re_node(t.string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001103 break;
1104
Denis Vlasenkof782f522007-01-01 23:51:30 +00001105 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001106 cn->info = OC_FUNC;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001107 cn->r.f = newfunc(t.string);
1108 cn->l.n = condition();
1109 break;
1110
Denis Vlasenkof782f522007-01-01 23:51:30 +00001111 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001112 cn = vn->r.n = parse_expr(TC_SEQTERM);
1113 cn->a.n = vn;
1114 break;
1115
Denis Vlasenkof782f522007-01-01 23:51:30 +00001116 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001117 glptr = cn;
1118 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1119 break;
1120
Denis Vlasenkof782f522007-01-01 23:51:30 +00001121 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001122 cn->l.n = condition();
1123 break;
1124 }
1125 }
1126 }
1127 }
1128 return sn.r.n;
1129}
1130
1131/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001132static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001133{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001134 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001135
1136 if (! seq->first)
1137 seq->first = seq->last = new_node(0);
1138
1139 if (seq->programname != programname) {
1140 seq->programname = programname;
1141 n = chain_node(OC_NEWSOURCE);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001142 n->l.s = xstrdup(programname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001143 }
1144
1145 n = seq->last;
1146 n->info = info;
1147 seq->last = n->a.n = new_node(OC_DONE);
1148
1149 return n;
1150}
1151
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001152static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001153{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001154 node *n;
1155
1156 n = chain_node(info);
1157 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1158 if (t.tclass & TC_GRPTERM)
1159 rollback_token();
1160}
1161
Mike Frysinger10a11e22005-09-27 02:23:02 +00001162static node *chain_loop(node *nn)
1163{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001164 node *n, *n2, *save_brk, *save_cont;
1165
1166 save_brk = break_ptr;
1167 save_cont = continue_ptr;
1168
1169 n = chain_node(OC_BR | Vx);
1170 continue_ptr = new_node(OC_EXEC);
1171 break_ptr = new_node(OC_EXEC);
1172 chain_group();
1173 n2 = chain_node(OC_EXEC | Vx);
1174 n2->l.n = nn;
1175 n2->a.n = n;
1176 continue_ptr->a.n = n2;
1177 break_ptr->a.n = n->r.n = seq->last;
1178
1179 continue_ptr = save_cont;
1180 break_ptr = save_brk;
1181
1182 return n;
1183}
1184
1185/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001186static void chain_group(void)
1187{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001188 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001189 node *n, *n2, *n3;
1190
1191 do {
1192 c = next_token(TC_GRPSEQ);
1193 } while (c & TC_NEWLINE);
1194
1195 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001196 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Mike Frysingerde2b9382005-09-27 03:18:00 +00001197 if (t.tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001198 rollback_token();
1199 chain_group();
1200 }
1201 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1202 rollback_token();
1203 chain_expr(OC_EXEC | Vx);
1204 } else { /* TC_STATEMNT */
1205 switch (t.info & OPCLSMASK) {
1206 case ST_IF:
1207 n = chain_node(OC_BR | Vx);
1208 n->l.n = condition();
1209 chain_group();
1210 n2 = chain_node(OC_EXEC);
1211 n->r.n = seq->last;
1212 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE)==TC_ELSE) {
1213 chain_group();
1214 n2->a.n = seq->last;
1215 } else {
1216 rollback_token();
1217 }
1218 break;
1219
1220 case ST_WHILE:
1221 n2 = condition();
1222 n = chain_loop(NULL);
1223 n->l.n = n2;
1224 break;
1225
1226 case ST_DO:
1227 n2 = chain_node(OC_EXEC);
1228 n = chain_loop(NULL);
1229 n2->a.n = n->a.n;
1230 next_token(TC_WHILE);
1231 n->l.n = condition();
1232 break;
1233
1234 case ST_FOR:
1235 next_token(TC_SEQSTART);
1236 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001237 if (t.tclass & TC_SEQTERM) { /* for-in */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001238 if ((n2->info & OPCLSMASK) != OC_IN)
1239 syntax_error(EMSG_UNEXP_TOKEN);
1240 n = chain_node(OC_WALKINIT | VV);
1241 n->l.n = n2->l.n;
1242 n->r.n = n2->r.n;
1243 n = chain_loop(NULL);
1244 n->info = OC_WALKNEXT | Vx;
1245 n->l.n = n2->l.n;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001246 } else { /* for (;;) */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001247 n = chain_node(OC_EXEC | Vx);
1248 n->l.n = n2;
1249 n2 = parse_expr(TC_SEMICOL);
1250 n3 = parse_expr(TC_SEQTERM);
1251 n = chain_loop(n3);
1252 n->l.n = n2;
1253 if (! n2)
1254 n->info = OC_EXEC;
1255 }
1256 break;
1257
1258 case OC_PRINT:
1259 case OC_PRINTF:
1260 n = chain_node(t.info);
1261 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
1262 if (t.tclass & TC_OUTRDR) {
1263 n->info |= t.info;
1264 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1265 }
1266 if (t.tclass & TC_GRPTERM)
1267 rollback_token();
1268 break;
1269
1270 case OC_BREAK:
1271 n = chain_node(OC_EXEC);
1272 n->a.n = break_ptr;
1273 break;
1274
1275 case OC_CONTINUE:
1276 n = chain_node(OC_EXEC);
1277 n->a.n = continue_ptr;
1278 break;
1279
1280 /* delete, next, nextfile, return, exit */
1281 default:
1282 chain_expr(t.info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001283 }
1284 }
1285}
1286
Mike Frysinger10a11e22005-09-27 02:23:02 +00001287static void parse_program(char *p)
1288{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001289 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001290 node *cn;
1291 func *f;
1292 var *v;
1293
1294 pos = p;
1295 t.lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001296 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Glenn L McGrath545106f2002-11-11 06:21:00 +00001297 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
1298
1299 if (tclass & TC_OPTERM)
1300 continue;
1301
1302 seq = &mainseq;
1303 if (tclass & TC_BEGIN) {
1304 seq = &beginseq;
1305 chain_group();
1306
1307 } else if (tclass & TC_END) {
1308 seq = &endseq;
1309 chain_group();
1310
1311 } else if (tclass & TC_FUNCDECL) {
1312 next_token(TC_FUNCTION);
1313 pos++;
1314 f = newfunc(t.string);
1315 f->body.first = NULL;
1316 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001317 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001318 v = findvar(ahash, t.string);
1319 v->x.aidx = (f->nargs)++;
1320
1321 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1322 break;
1323 }
1324 seq = &(f->body);
1325 chain_group();
1326 clear_array(ahash);
1327
1328 } else if (tclass & TC_OPSEQ) {
1329 rollback_token();
1330 cn = chain_node(OC_TEST);
1331 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
1332 if (t.tclass & TC_GRPSTART) {
1333 rollback_token();
1334 chain_group();
1335 } else {
1336 chain_node(OC_PRINT);
1337 }
1338 cn->r.n = mainseq.last;
1339
1340 } else /* if (tclass & TC_GRPSTART) */ {
1341 rollback_token();
1342 chain_group();
1343 }
1344 }
1345}
1346
1347
1348/* -------- program execution part -------- */
1349
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001350static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001351{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001352 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001353 node *n;
1354
1355 re = &spl->re[0];
1356 ire = &spl->re[1];
1357 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001358 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001359 regfree(re);
1360 regfree(ire);
1361 }
Rob Landleya3896512006-05-07 20:20:34 +00001362 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001363 mk_re_node(s, n, re);
1364 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001365 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001366 }
1367
1368 return n;
1369}
1370
1371/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001372 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001373 * be later regfree'd manually
1374 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001375static regex_t *as_regex(node *op, regex_t *preg)
1376{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001377 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001378 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001379
1380 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1381 return icase ? op->r.ire : op->l.re;
1382 } else {
1383 v = nvalloc(1);
1384 s = getvar_s(evaluate(op, v));
1385 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1386 nvfree(v);
1387 return preg;
1388 }
1389}
1390
1391/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001392static void qrealloc(char **b, int n, int *size)
1393{
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001394 if (!*b || n >= *size)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001395 *b = xrealloc(*b, *size = n + (n>>1) + 80);
1396}
1397
1398/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001399static void fsrealloc(int size)
1400{
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001401 static int maxfields; /* = 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00001402 int i;
1403
1404 if (size >= maxfields) {
1405 i = maxfields;
1406 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001407 Fields = xrealloc(Fields, maxfields * sizeof(var));
1408 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001409 Fields[i].type = VF_SPECIAL;
1410 Fields[i].string = NULL;
1411 }
1412 }
1413
1414 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001415 for (i = size; i < nfields; i++) {
1416 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001417 }
1418 }
1419 nfields = size;
1420}
1421
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001422static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001423{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001424 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001425 char c[4];
1426 char *s1;
1427 regmatch_t pmatch[2];
1428
1429 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001430 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1431 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001432
1433 c[0] = c[1] = (char)spl->info;
1434 c[2] = c[3] = '\0';
1435 if (*getvar_s(V[RS]) == '\0') c[2] = '\n';
1436
1437 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1438 while (*s) {
1439 l = strcspn(s, c+2);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001440 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1441 && pmatch[0].rm_so <= l
1442 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001443 l = pmatch[0].rm_so;
1444 if (pmatch[0].rm_eo == 0) { l++; pmatch[0].rm_eo++; }
1445 } else {
1446 pmatch[0].rm_eo = l;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001447 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001448 }
1449
1450 memcpy(s1, s, l);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001451 s1[l] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001452 nextword(&s1);
1453 s += pmatch[0].rm_eo;
1454 n++;
1455 }
1456 } else if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001457 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001458 *s1++ = *s++;
1459 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001460 n++;
1461 }
1462 } else if (c[0] != ' ') { /* single-character split */
1463 if (icase) {
1464 c[0] = toupper(c[0]);
1465 c[1] = tolower(c[1]);
1466 }
1467 if (*s1) n++;
1468 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001469 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001470 n++;
1471 }
1472 } else { /* space split */
1473 while (*s) {
Denis Vlasenkod18a3a22006-10-25 12:46:03 +00001474 s = skip_whitespace(s);
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001475 if (!*s) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001476 n++;
1477 while (*s && !isspace(*s))
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001478 *s1++ = *s++;
1479 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001480 }
1481 }
1482 return n;
1483}
1484
Mike Frysinger10a11e22005-09-27 02:23:02 +00001485static void split_f0(void)
1486{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001487 static char *fstrings = NULL;
1488 int i, n;
1489 char *s;
1490
1491 if (is_f0_split)
1492 return;
1493
1494 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001495 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001496 fsrealloc(0);
1497 n = awk_split(getvar_s(V[F0]), &fsplitter.n, &fstrings);
1498 fsrealloc(n);
1499 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001500 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001501 Fields[i].string = nextword(&s);
1502 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1503 }
1504
1505 /* set NF manually to avoid side effects */
1506 clrvar(V[NF]);
1507 V[NF]->type = VF_NUMBER | VF_SPECIAL;
1508 V[NF]->number = nfields;
1509}
1510
1511/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001512static void handle_special(var *v)
1513{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001514 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001515 char *b;
1516 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001517 int sl, l, len, i, bsize;
1518
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001519 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001520 return;
1521
1522 if (v == V[NF]) {
1523 n = (int)getvar_i(v);
1524 fsrealloc(n);
1525
1526 /* recalculate $0 */
1527 sep = getvar_s(V[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001528 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001529 b = NULL;
1530 len = 0;
1531 for (i=0; i<n; i++) {
1532 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001533 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001534 if (b) {
1535 memcpy(b+len, sep, sl);
1536 len += sl;
1537 }
1538 qrealloc(&b, len+l+sl, &bsize);
1539 memcpy(b+len, s, l);
1540 len += l;
1541 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001542 if (b)
1543 b[len] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001544 setvar_p(V[F0], b);
1545 is_f0_split = TRUE;
1546
1547 } else if (v == V[F0]) {
1548 is_f0_split = FALSE;
1549
1550 } else if (v == V[FS]) {
1551 mk_splitter(getvar_s(v), &fsplitter);
1552
1553 } else if (v == V[RS]) {
1554 mk_splitter(getvar_s(v), &rsplitter);
1555
1556 } else if (v == V[IGNORECASE]) {
1557 icase = istrue(v);
1558
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001559 } else { /* $n */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001560 n = getvar_i(V[NF]);
1561 setvar_i(V[NF], n > v-Fields ? n : v-Fields+1);
1562 /* right here v is invalid. Just to note... */
1563 }
1564}
1565
1566/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001567static node *nextarg(node **pn)
1568{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001569 node *n;
1570
1571 n = *pn;
1572 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1573 *pn = n->r.n;
1574 n = n->l.n;
1575 } else {
1576 *pn = NULL;
1577 }
1578 return n;
1579}
1580
Mike Frysinger10a11e22005-09-27 02:23:02 +00001581static void hashwalk_init(var *v, xhash *array)
1582{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001583 char **w;
1584 hash_item *hi;
1585 int i;
1586
1587 if (v->type & VF_WALK)
1588 free(v->x.walker);
1589
1590 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001591 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001592 *w = *(w+1) = (char *)(w + 2);
1593 for (i=0; i<array->csize; i++) {
1594 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001595 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001596 strcpy(*w, hi->name);
1597 nextword(w);
1598 hi = hi->next;
1599 }
1600 }
1601}
1602
Mike Frysinger10a11e22005-09-27 02:23:02 +00001603static int hashwalk_next(var *v)
1604{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001605 char **w;
1606
1607 w = v->x.walker;
1608 if (*(w+1) == *w)
1609 return FALSE;
1610
1611 setvar_s(v, nextword(w+1));
1612 return TRUE;
1613}
1614
1615/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001616static int ptest(node *pattern)
1617{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001618 static var v; /* static: to save stack space? */
1619
Glenn L McGrath545106f2002-11-11 06:21:00 +00001620 return istrue(evaluate(pattern, &v));
1621}
1622
1623/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001624static int awk_getline(rstream *rsm, var *v)
1625{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001626 char *b;
1627 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001628 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001629 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001630 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001631
1632 /* we're using our own buffer since we need access to accumulating
1633 * characters
1634 */
1635 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001636 m = rsm->buffer;
1637 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001638 p = rsm->pos;
1639 size = rsm->size;
1640 c = (char) rsplitter.n.info;
1641 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001642
1643 if (! m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001644 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001645 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001646 so = eo = p;
1647 r = 1;
1648 if (p > 0) {
1649 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1650 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
1651 b, 1, pmatch, 0) == 0) {
1652 so = pmatch[0].rm_so;
1653 eo = pmatch[0].rm_eo;
1654 if (b[eo] != '\0')
1655 break;
1656 }
1657 } else if (c != '\0') {
1658 s = strchr(b+pp, c);
Rob Landley46e351d2006-02-14 16:05:32 +00001659 if (! s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001660 if (s) {
1661 so = eo = s-b;
1662 eo++;
1663 break;
1664 }
1665 } else {
1666 while (b[rp] == '\n')
1667 rp++;
1668 s = strstr(b+rp, "\n\n");
1669 if (s) {
1670 so = eo = s-b;
1671 while (b[eo] == '\n') eo++;
1672 if (b[eo] != '\0')
1673 break;
1674 }
1675 }
1676 }
1677
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001678 if (a > 0) {
1679 memmove(m, (const void *)(m+a), p+1);
1680 b = m;
1681 a = 0;
1682 }
1683
1684 qrealloc(&m, a+p+128, &size);
1685 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001686 pp = p;
1687 p += safe_read(fd, b+p, size-p-1);
1688 if (p < pp) {
1689 p = 0;
1690 r = 0;
1691 setvar_i(V[ERRNO], errno);
1692 }
1693 b[p] = '\0';
1694
1695 } while (p > pp);
1696
1697 if (p == 0) {
1698 r--;
1699 } else {
1700 c = b[so]; b[so] = '\0';
1701 setvar_s(v, b+rp);
1702 v->type |= VF_USER;
1703 b[so] = c;
1704 c = b[eo]; b[eo] = '\0';
1705 setvar_s(V[RT], b+so);
1706 b[eo] = c;
1707 }
1708
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001709 rsm->buffer = m;
1710 rsm->adv = a + eo;
1711 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001712 rsm->size = size;
1713
1714 return r;
1715}
1716
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001717static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001718{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001719 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001720 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001721 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001722
1723 if (int_as_int && n == (int)n) {
1724 r = snprintf(b, size, "%d", (int)n);
1725 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001726 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001727 if (strchr("diouxX", c)) {
1728 r = snprintf(b, size, format, (int)n);
1729 } else if (strchr("eEfgG", c)) {
1730 r = snprintf(b, size, format, n);
1731 } else {
1732 runtime_error(EMSG_INV_FMT);
1733 }
1734 }
1735 return r;
1736}
1737
1738
1739/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001740static char *awk_printf(node *n)
1741{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001742 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001743 char *fmt, *s, *f;
1744 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001745 int i, j, incr, bsize;
1746 char c, c1;
1747 var *v, *arg;
1748
1749 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001750 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001751
1752 i = 0;
1753 while (*f) {
1754 s = f;
1755 while (*f && (*f != '%' || *(++f) == '%'))
1756 f++;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001757 while (*f && !isalpha(*f))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001758 f++;
1759
1760 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001761 qrealloc(&b, incr + i, &bsize);
1762 c = *f;
1763 if (c != '\0') f++;
1764 c1 = *f;
1765 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001766 arg = evaluate(nextarg(&n), v);
1767
1768 j = i;
1769 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001770 i += sprintf(b+i, s, is_numeric(arg) ?
1771 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001772
1773 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001774 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001775 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001776 i += sprintf(b+i, s, s1);
1777
1778 } else {
1779 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1780 }
1781 *f = c1;
1782
1783 /* if there was an error while sprintf, return value is negative */
1784 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001785 }
1786
Denis Vlasenkof782f522007-01-01 23:51:30 +00001787 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001788 free(fmt);
1789 nvfree(v);
1790 b[i] = '\0';
1791 return b;
1792}
1793
1794/* common substitution routine
1795 * replace (nm) substring of (src) that match (n) with (repl), store
1796 * result into (dest), return number of substitutions. If nm=0, replace
1797 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1798 * subexpression matching (\1-\9)
1799 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001800static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001801{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001802 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001803 const char *s;
1804 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001805 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1806 regmatch_t pmatch[10];
1807 regex_t sreg, *re;
1808
1809 re = as_regex(rn, &sreg);
1810 if (! src) src = V[F0];
1811 if (! dest) dest = V[F0];
1812
1813 i = di = 0;
1814 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001815 rl = strlen(repl);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001816 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0:REG_NOTBOL) == 0) {
1817 so = pmatch[0].rm_so;
1818 eo = pmatch[0].rm_eo;
1819
1820 qrealloc(&ds, di + eo + rl, &dssize);
1821 memcpy(ds + di, sp, eo);
1822 di += eo;
1823 if (++i >= nm) {
1824 /* replace */
1825 di -= (eo - so);
1826 nbs = 0;
1827 for (s = repl; *s; s++) {
1828 ds[di++] = c = *s;
1829 if (c == '\\') {
1830 nbs++;
1831 continue;
1832 }
1833 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1834 di -= ((nbs + 3) >> 1);
1835 j = 0;
1836 if (c != '&') {
1837 j = c - '0';
1838 nbs++;
1839 }
1840 if (nbs % 2) {
1841 ds[di++] = c;
1842 } else {
1843 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1844 qrealloc(&ds, di + rl + n, &dssize);
1845 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1846 di += n;
1847 }
1848 }
1849 nbs = 0;
1850 }
1851 }
1852
1853 sp += eo;
1854 if (i == nm) break;
1855 if (eo == so) {
1856 if (! (ds[di++] = *sp++)) break;
1857 }
1858 }
1859
1860 qrealloc(&ds, di + strlen(sp), &dssize);
1861 strcpy(ds + di, sp);
1862 setvar_p(dest, ds);
1863 if (re == &sreg) regfree(re);
1864 return i;
1865}
1866
Mike Frysinger10a11e22005-09-27 02:23:02 +00001867static var *exec_builtin(node *op, var *res)
1868{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001869 int (*to_xxx)(int);
1870 var *tv;
1871 node *an[4];
1872 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001873 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001874 regmatch_t pmatch[2];
1875 regex_t sreg, *re;
1876 static tsplitter tspl;
1877 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001878 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001879 int nargs;
1880 time_t tt;
1881 char *s, *s1;
1882 int i, l, ll, n;
1883
1884 tv = nvalloc(4);
1885 isr = info = op->info;
1886 op = op->l.n;
1887
1888 av[2] = av[3] = NULL;
1889 for (i=0 ; i<4 && op ; i++) {
1890 an[i] = nextarg(&op);
1891 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
1892 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
1893 isr >>= 1;
1894 }
1895
1896 nargs = i;
1897 if (nargs < (info >> 30))
1898 runtime_error(EMSG_TOO_FEW_ARGS);
1899
1900 switch (info & OPNMASK) {
1901
Denis Vlasenkof782f522007-01-01 23:51:30 +00001902 case B_a2:
1903#if ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +00001904 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
1905#else
1906 runtime_error(EMSG_NO_MATH);
1907#endif
1908 break;
1909
Denis Vlasenkof782f522007-01-01 23:51:30 +00001910 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001911 if (nargs > 2) {
1912 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
1913 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
1914 } else {
1915 spl = &fsplitter.n;
1916 }
1917
1918 n = awk_split(as[0], spl, &s);
1919 s1 = s;
1920 clear_array(iamarray(av[1]));
1921 for (i=1; i<=n; i++)
1922 setari_u(av[1], i, nextword(&s1));
1923 free(s);
1924 setvar_i(res, n);
1925 break;
1926
Denis Vlasenkof782f522007-01-01 23:51:30 +00001927 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00001928 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001929 i = getvar_i(av[1]) - 1;
1930 if (i>l) i=l; if (i<0) i=0;
1931 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
1932 if (n<0) n=0;
1933 s = xmalloc(n+1);
1934 strncpy(s, as[0]+i, n);
1935 s[n] = '\0';
1936 setvar_p(res, s);
1937 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00001938
Denis Vlasenkof782f522007-01-01 23:51:30 +00001939 case B_an:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001940 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
1941 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00001942
Denis Vlasenkof782f522007-01-01 23:51:30 +00001943 case B_co:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001944 setvar_i(res, ~(long)getvar_i(av[0]));
1945 break;
1946
Denis Vlasenkof782f522007-01-01 23:51:30 +00001947 case B_ls:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001948 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
1949 break;
1950
Denis Vlasenkof782f522007-01-01 23:51:30 +00001951 case B_or:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001952 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
1953 break;
1954
Denis Vlasenkof782f522007-01-01 23:51:30 +00001955 case B_rs:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001956 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
1957 break;
1958
Denis Vlasenkof782f522007-01-01 23:51:30 +00001959 case B_xo:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001960 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
1961 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001962
Denis Vlasenkof782f522007-01-01 23:51:30 +00001963 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001964 to_xxx = tolower;
1965 goto lo_cont;
1966
Denis Vlasenkof782f522007-01-01 23:51:30 +00001967 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001968 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001969 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00001970 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001971 while (*s1) {
1972 *s1 = (*to_xxx)(*s1);
1973 s1++;
1974 }
1975 setvar_p(res, s);
1976 break;
1977
Denis Vlasenkof782f522007-01-01 23:51:30 +00001978 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001979 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00001980 ll = strlen(as[1]);
1981 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001982 if (ll > 0 && l >= 0) {
1983 if (! icase) {
1984 s = strstr(as[0], as[1]);
1985 if (s) n = (s - as[0]) + 1;
1986 } else {
1987 /* this piece of code is terribly slow and
1988 * really should be rewritten
1989 */
1990 for (i=0; i<=l; i++) {
1991 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
1992 n = i+1;
1993 break;
1994 }
1995 }
1996 }
1997 }
1998 setvar_i(res, n);
1999 break;
2000
Denis Vlasenkof782f522007-01-01 23:51:30 +00002001 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002002 if (nargs > 1)
2003 tt = getvar_i(av[1]);
2004 else
2005 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002006 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
2007 i = strftime(buf, MAXVARFMT,
2008 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2009 localtime(&tt));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002010 buf[i] = '\0';
2011 setvar_s(res, buf);
2012 break;
2013
Denis Vlasenkof782f522007-01-01 23:51:30 +00002014 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002015 re = as_regex(an[1], &sreg);
2016 n = regexec(re, as[0], 1, pmatch, 0);
2017 if (n == 0) {
2018 pmatch[0].rm_so++;
2019 pmatch[0].rm_eo++;
2020 } else {
2021 pmatch[0].rm_so = 0;
2022 pmatch[0].rm_eo = -1;
2023 }
2024 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2025 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2026 setvar_i(res, pmatch[0].rm_so);
2027 if (re == &sreg) regfree(re);
2028 break;
2029
Denis Vlasenkof782f522007-01-01 23:51:30 +00002030 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002031 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2032 break;
2033
Denis Vlasenkof782f522007-01-01 23:51:30 +00002034 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002035 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2036 break;
2037
Denis Vlasenkof782f522007-01-01 23:51:30 +00002038 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002039 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2040 break;
2041 }
2042
2043 nvfree(tv);
2044 return res;
2045}
2046
2047/*
2048 * Evaluate node - the heart of the program. Supplied with subtree
2049 * and place where to store result. returns ptr to result.
2050 */
2051#define XC(n) ((n) >> 8)
2052
Mike Frysinger10a11e22005-09-27 02:23:02 +00002053static var *evaluate(node *op, var *res)
2054{
Mike Frysingerde2b9382005-09-27 03:18:00 +00002055 /* This procedure is recursive so we should count every byte */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002056 static var *fnargs = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002057 static unsigned seed = 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002058 static regex_t sreg;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002059
Glenn L McGrath545106f2002-11-11 06:21:00 +00002060 node *op1;
2061 var *v1;
2062 union {
2063 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002064 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002065 double d;
2066 int i;
2067 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002068 uint32_t opinfo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002069 short opn;
2070 union {
2071 char *s;
2072 rstream *rsm;
2073 FILE *F;
2074 var *v;
2075 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002076 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002077 } X;
2078
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002079 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002080 return setvar_s(res, NULL);
2081
2082 v1 = nvalloc(2);
2083
2084 while (op) {
2085
2086 opinfo = op->info;
2087 opn = (short)(opinfo & OPNMASK);
2088 lineno = op->lineno;
2089
Mike Frysingerde2b9382005-09-27 03:18:00 +00002090 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002091 op1 = op->l.n;
2092 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2093 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2094 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2095 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2096 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2097
2098 switch (XC(opinfo & OPCLSMASK)) {
2099
2100 /* -- iterative node type -- */
2101
2102 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002103 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002104 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2105 /* it's range pattern */
2106 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2107 op->info |= OF_CHECKED;
2108 if (ptest(op1->r.n))
2109 op->info &= ~OF_CHECKED;
2110
2111 op = op->a.n;
2112 } else {
2113 op = op->r.n;
2114 }
2115 } else {
2116 op = (ptest(op1)) ? op->a.n : op->r.n;
2117 }
2118 break;
2119
2120 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002121 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002122 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002123
2124 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002125 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002126 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002127 break;
2128
2129 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002130 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002131 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002132 break;
2133
2134 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002135 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002136 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2137 break;
2138
Denis Vlasenkof782f522007-01-01 23:51:30 +00002139 case XC( OC_PRINT ):
2140 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002141 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002142 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002143 X.rsm = newfile(R.s);
2144 if (! X.rsm->F) {
2145 if (opn == '|') {
2146 if((X.rsm->F = popen(R.s, "w")) == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002147 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002148 X.rsm->is_pipe = 1;
2149 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002150 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002151 }
2152 }
2153 X.F = X.rsm->F;
2154 }
2155
2156 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002157 if (! op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002158 fputs(getvar_s(V[F0]), X.F);
2159 } else {
2160 while (op1) {
2161 L.v = evaluate(nextarg(&op1), v1);
2162 if (L.v->type & VF_NUMBER) {
2163 fmt_num(buf, MAXVARFMT, getvar_s(V[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002164 getvar_i(L.v), TRUE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002165 fputs(buf, X.F);
2166 } else {
2167 fputs(getvar_s(L.v), X.F);
2168 }
2169
2170 if (op1) fputs(getvar_s(V[OFS]), X.F);
2171 }
2172 }
2173 fputs(getvar_s(V[ORS]), X.F);
2174
2175 } else { /* OC_PRINTF */
2176 L.s = awk_printf(op1);
2177 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002178 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002179 }
2180 fflush(X.F);
2181 break;
2182
Denis Vlasenkof782f522007-01-01 23:51:30 +00002183 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002184 X.info = op1->info & OPCLSMASK;
2185 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002186 R.v = op1->l.v;
2187 } else if (X.info == OC_FNARG) {
2188 R.v = &fnargs[op1->l.i];
2189 } else {
2190 runtime_error(EMSG_NOT_ARRAY);
2191 }
2192
Mike Frysingerde2b9382005-09-27 03:18:00 +00002193 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002194 clrvar(L.v);
2195 L.s = getvar_s(evaluate(op1->r.n, v1));
2196 hash_remove(iamarray(R.v), L.s);
2197 } else {
2198 clear_array(iamarray(R.v));
2199 }
2200 break;
2201
Denis Vlasenkof782f522007-01-01 23:51:30 +00002202 case XC( OC_NEWSOURCE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002203 programname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002204 break;
2205
Denis Vlasenkof782f522007-01-01 23:51:30 +00002206 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002207 copyvar(res, L.v);
2208 break;
2209
Denis Vlasenkof782f522007-01-01 23:51:30 +00002210 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002211 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002212 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002213 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002214 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002215 clrvar(res);
2216 break;
2217
Denis Vlasenkof782f522007-01-01 23:51:30 +00002218 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002219 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002220
2221 /* -- recursive node type -- */
2222
Denis Vlasenkof782f522007-01-01 23:51:30 +00002223 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002224 L.v = op->l.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002225 if (L.v == V[NF])
2226 split_f0();
2227 goto v_cont;
2228
Denis Vlasenkof782f522007-01-01 23:51:30 +00002229 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002230 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002231 v_cont:
2232 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002233 break;
2234
Denis Vlasenkof782f522007-01-01 23:51:30 +00002235 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002236 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2237 break;
2238
Denis Vlasenkof782f522007-01-01 23:51:30 +00002239 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002240 op1 = op;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002241 L.s = getvar_s(V[F0]);
2242 goto re_cont;
2243
Denis Vlasenkof782f522007-01-01 23:51:30 +00002244 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002245 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002246 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002247 X.re = as_regex(op1, &sreg);
2248 R.i = regexec(X.re, L.s, 0, NULL, 0);
2249 if (X.re == &sreg) regfree(X.re);
2250 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2251 break;
2252
Denis Vlasenkof782f522007-01-01 23:51:30 +00002253 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002254 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002255 if (R.v == v1+1 && R.v->string) {
2256 res = setvar_p(L.v, R.v->string);
2257 R.v->string = NULL;
2258 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002259 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002260 }
2261 break;
2262
Denis Vlasenkof782f522007-01-01 23:51:30 +00002263 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002264 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002265 runtime_error(EMSG_POSSIBLE_ERROR);
2266 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2267 break;
2268
Denis Vlasenkof782f522007-01-01 23:51:30 +00002269 case XC( OC_FUNC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002270 if (! op->r.f->body.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002271 runtime_error(EMSG_UNDEF_FUNC);
2272
2273 X.v = R.v = nvalloc(op->r.f->nargs+1);
2274 while (op1) {
2275 L.v = evaluate(nextarg(&op1), v1);
2276 copyvar(R.v, L.v);
2277 R.v->type |= VF_CHILD;
2278 R.v->x.parent = L.v;
2279 if (++R.v - X.v >= op->r.f->nargs)
2280 break;
2281 }
2282
2283 R.v = fnargs;
2284 fnargs = X.v;
2285
2286 L.s = programname;
2287 res = evaluate(op->r.f->body.first, res);
2288 programname = L.s;
2289
2290 nvfree(fnargs);
2291 fnargs = R.v;
2292 break;
2293
Denis Vlasenkof782f522007-01-01 23:51:30 +00002294 case XC( OC_GETLINE ):
2295 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002296 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002297 X.rsm = newfile(L.s);
2298 if (! X.rsm->F) {
2299 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2300 X.rsm->F = popen(L.s, "r");
2301 X.rsm->is_pipe = TRUE;
2302 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002303 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002304 }
2305 }
2306 } else {
2307 if (! iF) iF = next_input_file();
2308 X.rsm = iF;
2309 }
2310
2311 if (! X.rsm->F) {
2312 setvar_i(V[ERRNO], errno);
2313 setvar_i(res, -1);
2314 break;
2315 }
2316
2317 if (! op->r.n)
2318 R.v = V[F0];
2319
2320 L.i = awk_getline(X.rsm, R.v);
2321 if (L.i > 0) {
2322 if (! op1) {
2323 incvar(V[FNR]);
2324 incvar(V[NR]);
2325 }
2326 }
2327 setvar_i(res, L.i);
2328 break;
2329
Mike Frysingerde2b9382005-09-27 03:18:00 +00002330 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002331 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002332 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002333
Denis Vlasenkof782f522007-01-01 23:51:30 +00002334 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002335 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002336 break;
2337
Denis Vlasenkof782f522007-01-01 23:51:30 +00002338 case F_rn:
2339 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002340 break;
2341
Denis Vlasenkof782f522007-01-01 23:51:30 +00002342#if ENABLE_FEATURE_AWK_MATH
2343 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002344 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002345 break;
2346
Denis Vlasenkof782f522007-01-01 23:51:30 +00002347 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002348 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002349 break;
2350
Denis Vlasenkof782f522007-01-01 23:51:30 +00002351 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002352 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002353 break;
2354
Denis Vlasenkof782f522007-01-01 23:51:30 +00002355 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002356 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002357 break;
2358
Denis Vlasenkof782f522007-01-01 23:51:30 +00002359 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002360 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002361 break;
2362#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002363 case F_co:
2364 case F_ex:
2365 case F_lg:
2366 case F_si:
2367 case F_sq:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002368 runtime_error(EMSG_NO_MATH);
2369 break;
2370#endif
2371
Denis Vlasenkof782f522007-01-01 23:51:30 +00002372 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002373 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002374 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002375 srand(seed);
2376 break;
2377
Denis Vlasenkof782f522007-01-01 23:51:30 +00002378 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002379 R.d = time(NULL);
2380 break;
2381
Denis Vlasenkof782f522007-01-01 23:51:30 +00002382 case F_le:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002383 if (! op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002384 L.s = getvar_s(V[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002385 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002386 break;
2387
Denis Vlasenkof782f522007-01-01 23:51:30 +00002388 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002389 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002390 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2391 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002392 break;
2393
Denis Vlasenkof782f522007-01-01 23:51:30 +00002394 case F_ff:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002395 if (! op1)
2396 fflush(stdout);
2397 else {
2398 if (L.s && *L.s) {
2399 X.rsm = newfile(L.s);
2400 fflush(X.rsm->F);
2401 } else {
2402 fflush(NULL);
2403 }
2404 }
2405 break;
2406
Denis Vlasenkof782f522007-01-01 23:51:30 +00002407 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002408 X.rsm = (rstream *)hash_search(fdhash, L.s);
2409 if (X.rsm) {
2410 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002411 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002412 hash_remove(fdhash, L.s);
2413 }
2414 if (R.i != 0)
2415 setvar_i(V[ERRNO], errno);
2416 R.d = (double)R.i;
2417 break;
2418 }
2419 setvar_i(res, R.d);
2420 break;
2421
Denis Vlasenkof782f522007-01-01 23:51:30 +00002422 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002423 res = exec_builtin(op, res);
2424 break;
2425
Denis Vlasenkof782f522007-01-01 23:51:30 +00002426 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002427 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002428 break;
2429
Denis Vlasenkof782f522007-01-01 23:51:30 +00002430 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002431 X.v = R.v;
2432 L.d = R.d = getvar_i(R.v);
2433 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002434 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002435 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002436 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002437 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002438 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002439 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002440 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002441 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002442 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002443 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002444 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002445 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002446 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002447 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002448 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002449 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002450 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002451 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002452 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002453 setvar_i(X.v, R.d);
2454 }
2455 setvar_i(res, L.d);
2456 break;
2457
Denis Vlasenkof782f522007-01-01 23:51:30 +00002458 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002459 R.i = (int)getvar_i(R.v);
2460 if (R.i == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002461 res = V[F0];
2462 } else {
2463 split_f0();
2464 if (R.i > nfields)
2465 fsrealloc(R.i);
2466
2467 res = &Fields[R.i-1];
2468 }
2469 break;
2470
2471 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002472 case XC( OC_CONCAT ):
2473 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002474 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002475 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002476 strcpy(X.s, L.s);
2477 if ((opinfo & OPCLSMASK) == OC_COMMA) {
2478 L.s = getvar_s(V[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002479 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002480 strcat(X.s, L.s);
2481 }
2482 strcat(X.s, R.s);
2483 setvar_p(res, X.s);
2484 break;
2485
Denis Vlasenkof782f522007-01-01 23:51:30 +00002486 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002487 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2488 break;
2489
Denis Vlasenkof782f522007-01-01 23:51:30 +00002490 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002491 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2492 break;
2493
Denis Vlasenkof782f522007-01-01 23:51:30 +00002494 case XC( OC_BINARY ):
2495 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002496 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002497 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002498 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002499 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002500 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002501 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002502 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002503 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002504 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002505 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002506 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002507 case '/':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002508 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2509 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002510 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002511 case '&':
2512#if ENABLE_FEATURE_AWK_MATH
Mike Frysingerde2b9382005-09-27 03:18:00 +00002513 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002514#else
2515 runtime_error(EMSG_NO_MATH);
2516#endif
2517 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002518 case '%':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002519 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2520 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002521 break;
2522 }
2523 res = setvar_i(((opinfo&OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
2524 break;
2525
Denis Vlasenkof782f522007-01-01 23:51:30 +00002526 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002527 if (is_numeric(L.v) && is_numeric(R.v)) {
2528 L.d = getvar_i(L.v) - getvar_i(R.v);
2529 } else {
2530 L.s = getvar_s(L.v);
2531 R.s = getvar_s(R.v);
2532 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2533 }
2534 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002535 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002536 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002537 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002538 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002539 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002540 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002541 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002542 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002543 break;
2544 }
2545 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2546 break;
2547
Denis Vlasenkof782f522007-01-01 23:51:30 +00002548 default:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002549 runtime_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002550 }
2551 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2552 op = op->a.n;
2553 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2554 break;
2555 if (nextrec)
2556 break;
2557 }
2558 nvfree(v1);
2559 return res;
2560}
2561
2562
2563/* -------- main & co. -------- */
2564
Mike Frysinger10a11e22005-09-27 02:23:02 +00002565static int awk_exit(int r)
2566{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002567 var tv;
2568 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002569 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002570
Denis Vlasenkof782f522007-01-01 23:51:30 +00002571 zero_out_var(&tv);
2572
2573 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002574 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002575 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002576 evaluate(endseq.first, &tv);
2577 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002578
2579 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002580 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002581 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002582 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002583 if (hi->data.rs.F && hi->data.rs.is_pipe)
2584 pclose(hi->data.rs.F);
2585 hi = hi->next;
2586 }
2587 }
2588
2589 exit(r);
2590}
2591
2592/* if expr looks like "var=value", perform assignment and return 1,
2593 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002594static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002595{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002596 char *exprc, *s, *s0, *s1;
2597
Rob Landleyd921b2e2006-08-03 15:41:12 +00002598 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002599 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2600 free(exprc);
2601 return FALSE;
2602 }
2603
2604 *(s++) = '\0';
2605 s0 = s1 = s;
2606 while (*s)
2607 *(s1++) = nextchar(&s);
2608
2609 *s1 = '\0';
2610 setvar_u(newvar(exprc), s0);
2611 free(exprc);
2612 return TRUE;
2613}
2614
2615/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002616static rstream *next_input_file(void)
2617{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002618 static rstream rsm;
2619 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002620 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002621 static int files_happen = FALSE;
2622
2623 if (rsm.F) fclose(rsm.F);
2624 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002625 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002626
2627 do {
2628 if (getvar_i(V[ARGIND])+1 >= getvar_i(V[ARGC])) {
2629 if (files_happen)
2630 return NULL;
2631 fname = "-";
2632 F = stdin;
2633 } else {
2634 ind = getvar_s(incvar(V[ARGIND]));
2635 fname = getvar_s(findvar(iamarray(V[ARGV]), ind));
2636 if (fname && *fname && !is_assignment(fname))
2637 F = afopen(fname, "r");
2638 }
2639 } while (!F);
2640
2641 files_happen = TRUE;
2642 setvar_s(V[FILENAME], fname);
2643 rsm.F = F;
2644 return &rsm;
2645}
2646
Rob Landleydfba7412006-03-06 20:47:33 +00002647int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002648{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002649 unsigned opt;
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002650 char *opt_F, *opt_v, *opt_W;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002651 int i, j, flen;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002652 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002653 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002654 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002655 char *vnames = (char *)vNames; /* cheat */
2656 char *vvalues = (char *)vValues;
2657
Denis Vlasenko150f4022007-01-13 21:06:21 +00002658 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002659 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2660 if (ENABLE_LOCALE_SUPPORT)
2661 setlocale(LC_NUMERIC, "C");
2662
Denis Vlasenkof782f522007-01-01 23:51:30 +00002663 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002664
2665 /* allocate global buffer */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002666 buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002667
2668 vhash = hash_init();
2669 ahash = hash_init();
2670 fdhash = hash_init();
2671 fnhash = hash_init();
2672
2673 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002674 for (i = 0; *vnames; i++) {
2675 V[i] = v = newvar(nextword(&vnames));
2676 if (*vvalues != '\377')
2677 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002678 else
2679 setvar_i(v, 0);
2680
Denis Vlasenkof782f522007-01-01 23:51:30 +00002681 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002682 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002683 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002684 }
2685 }
2686
2687 handle_special(V[FS]);
2688 handle_special(V[RS]);
2689
Denis Vlasenkof782f522007-01-01 23:51:30 +00002690 newfile("/dev/stdin")->F = stdin;
2691 newfile("/dev/stdout")->F = stdout;
2692 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002693
Denis Vlasenkof782f522007-01-01 23:51:30 +00002694 for (envp = environ; *envp; envp++) {
2695 char *s = xstrdup(*envp);
2696 char *s1 = strchr(s, '=');
2697 if (s1) {
2698 *s1++ = '\0';
2699 setvar_u(findvar(iamarray(V[ENVIRON]), s), s1);
Eric Andersen67776be2004-07-30 23:52:08 +00002700 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002701 free(s);
2702 }
2703
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002704 opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &programname, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002705 argv += optind;
2706 argc -= optind;
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002707 if (opt & 0x1) setvar_s(V[FS], opt_F); // -F
2708 if (opt & 0x2) if (!is_assignment(opt_v)) bb_show_usage(); // -v
2709 if (opt & 0x4) { // -f
Denis Vlasenkof782f522007-01-01 23:51:30 +00002710 char *s = s; /* die, gcc, die */
2711 FILE *from_file = afopen(programname, "r");
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002712 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002713 if (fseek(from_file, 0, SEEK_END) == 0) {
2714 flen = ftell(from_file);
2715 s = xmalloc(flen + 4);
2716 fseek(from_file, 0, SEEK_SET);
2717 i = 1 + fread(s + 1, 1, flen, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002718 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002719 for (i = j = 1; j > 0; i += j) {
2720 s = xrealloc(s, i + 4096);
2721 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002722 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002723 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002724 s[i] = '\0';
Denis Vlasenkof782f522007-01-01 23:51:30 +00002725 fclose(from_file);
2726 parse_program(s + 1);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002727 free(s);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002728 } else { // no -f: take program from 1st parameter
2729 if (!argc)
2730 bb_show_usage();
2731 programname = "cmd. line";
2732 parse_program(*argv++);
2733 argc--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002734 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002735 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002736 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002737
Glenn L McGrath545106f2002-11-11 06:21:00 +00002738 /* fill in ARGV array */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002739 setvar_i(V[ARGC], argc + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002740 setari_u(V[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002741 i = 0;
2742 while (*argv)
2743 setari_u(V[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002744
2745 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002746 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002747 awk_exit(EXIT_SUCCESS);
2748
2749 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002750 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002751
2752 /* passing through input files */
2753 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002754 nextfile = FALSE;
2755 setvar_i(V[FNR], 0);
2756
Denis Vlasenkof782f522007-01-01 23:51:30 +00002757 while ((i = awk_getline(iF, V[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002758 nextrec = FALSE;
2759 incvar(V[NR]);
2760 incvar(V[FNR]);
2761 evaluate(mainseq.first, &tv);
2762
2763 if (nextfile)
2764 break;
2765 }
2766
Denis Vlasenkof782f522007-01-01 23:51:30 +00002767 if (i < 0)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002768 runtime_error(strerror(errno));
2769
2770 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002771 }
2772
Glenn L McGrath545106f2002-11-11 06:21:00 +00002773 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002774 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002775}