blob: f48b0e43fba084e452492b3c59aaddd5fbbe9777 [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;
50 char *programname;
51} 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;
402static char *programname;
403static 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
Mike Frysinger10a11e22005-09-27 02:23:02 +0000706static char *getvar_s(var *v)
707{
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) {
851
852 t.rollback = FALSE;
853
854 } else if (concat_inserted) {
855
856 concat_inserted = FALSE;
857 t.tclass = save_tclass;
858 t.info = save_info;
859
860 } else {
861
862 p = pos;
863
864 readnext:
865 skip_spaces(&p);
866 lineno = t.lineno;
867 if (*p == '#')
868 while (*p != '\n' && *p != '\0') p++;
869
870 if (*p == '\n')
871 t.lineno++;
872
873 if (*p == '\0') {
874 tc = TC_EOF;
875
876 } else if (*p == '\"') {
877 /* it's a string */
878 t.string = s = ++p;
879 while (*p != '\"') {
880 if (*p == '\0' || *p == '\n')
881 syntax_error(EMSG_UNEXP_EOS);
882 *(s++) = nextchar(&p);
883 }
884 p++;
885 *s = '\0';
886 tc = TC_STRING;
887
888 } else if ((expected & TC_REGEXP) && *p == '/') {
889 /* it's regexp */
890 t.string = s = ++p;
891 while (*p != '/') {
892 if (*p == '\0' || *p == '\n')
893 syntax_error(EMSG_UNEXP_EOS);
894 if ((*s++ = *p++) == '\\') {
895 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000896 *(s-1) = bb_process_escape_sequence((const char **)&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000897 if (*pp == '\\') *s++ = '\\';
898 if (p == pp) *s++ = *p++;
899 }
900 }
901 p++;
902 *s = '\0';
903 tc = TC_REGEXP;
904
905 } else if (*p == '.' || isdigit(*p)) {
906 /* it's a number */
907 t.number = strtod(p, &p);
908 if (*p == '.')
909 syntax_error(EMSG_UNEXP_TOKEN);
910 tc = TC_NUMBER;
911
912 } else {
913 /* search for something known */
914 tl = tokenlist;
915 tc = 0x00000001;
916 ti = tokeninfo;
917 while (*tl) {
918 l = *(tl++);
919 if (l == NTCC) {
920 tc <<= 1;
921 continue;
922 }
923 /* if token class is expected, token
924 * matches and it's not a longer word,
925 * then this is what we are looking for
926 */
927 if ((tc & (expected | TC_WORD | TC_NEWLINE)) &&
928 *tl == *p && strncmp(p, tl, l) == 0 &&
929 !((tc & TC_WORD) && isalnum_(*(p + l)))) {
930 t.info = *ti;
931 p += l;
932 break;
933 }
934 ti++;
935 tl += l;
936 }
937
Denis Vlasenkof782f522007-01-01 23:51:30 +0000938 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000939 /* it's a name (var/array/function),
940 * otherwise it's something wrong
941 */
942 if (! isalnum_(*p))
943 syntax_error(EMSG_UNEXP_TOKEN);
944
945 t.string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000946 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000947 *(p-1) = *p;
948 }
949 *(p-1) = '\0';
950 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +0000951 /* also consume whitespace between functionname and bracket */
Rob Landley46e351d2006-02-14 16:05:32 +0000952 if (! (expected & TC_VARIABLE)) skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000953 if (*p == '(') {
954 tc = TC_FUNCTION;
955 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000956 if (*p == '[') {
957 p++;
958 tc = TC_ARRAY;
959 }
960 }
961 }
962 }
963 pos = p;
964
965 /* skipping newlines in some cases */
966 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
967 goto readnext;
968
969 /* insert concatenation operator when needed */
970 if ((ltclass&TC_CONCAT1) && (tc&TC_CONCAT2) && (expected&TC_BINOP)) {
971 concat_inserted = TRUE;
972 save_tclass = tc;
973 save_info = t.info;
974 tc = TC_BINOP;
975 t.info = OC_CONCAT | SS | P(35);
976 }
977
978 t.tclass = tc;
979 }
980 ltclass = t.tclass;
981
982 /* Are we ready for this? */
983 if (! (ltclass & expected))
984 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
985 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
986
987 return ltclass;
988}
989
990static void rollback_token(void) { t.rollback = TRUE; }
991
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000992static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000993{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000994 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000995
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000996 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000997 n->info = info;
998 n->lineno = lineno;
999 return n;
1000}
1001
Mike Frysinger10a11e22005-09-27 02:23:02 +00001002static node *mk_re_node(char *s, node *n, regex_t *re)
1003{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001004 n->info = OC_REGEXP;
1005 n->l.re = re;
1006 n->r.ire = re + 1;
1007 xregcomp(re, s, REG_EXTENDED);
1008 xregcomp(re+1, s, REG_EXTENDED | REG_ICASE);
1009
1010 return n;
1011}
1012
Mike Frysinger10a11e22005-09-27 02:23:02 +00001013static node *condition(void)
1014{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001015 next_token(TC_SEQSTART);
1016 return parse_expr(TC_SEQTERM);
1017}
1018
1019/* parse expression terminated by given argument, return ptr
1020 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001021static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001022{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001023 node sn;
1024 node *cn = &sn;
1025 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001026 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001027 var *v;
1028
1029 sn.info = PRIMASK;
1030 sn.r.n = glptr = NULL;
1031 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1032
1033 while (! ((tc = next_token(xtc)) & iexp)) {
1034 if (glptr && (t.info == (OC_COMPARE|VV|P(39)|2))) {
1035 /* input redirection (<) attached to glptr node */
1036 cn = glptr->l.n = new_node(OC_CONCAT|SS|P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001037 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001038 xtc = TC_OPERAND | TC_UOPPRE;
1039 glptr = NULL;
1040
1041 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1042 /* for binary and postfix-unary operators, jump back over
1043 * previous operators with higher priority */
1044 vn = cn;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001045 while ( ((t.info & PRIMASK) > (vn->a.n->info & PRIMASK2)) ||
Glenn L McGrath545106f2002-11-11 06:21:00 +00001046 ((t.info == vn->info) && ((t.info & OPCLSMASK) == OC_COLON)) )
1047 vn = vn->a.n;
1048 if ((t.info & OPCLSMASK) == OC_TERNARY)
1049 t.info += P(6);
1050 cn = vn->a.n->r.n = new_node(t.info);
1051 cn->a.n = vn->a.n;
1052 if (tc & TC_BINOP) {
1053 cn->l.n = vn;
1054 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1055 if ((t.info & OPCLSMASK) == OC_PGETLINE) {
1056 /* it's a pipe */
1057 next_token(TC_GETLINE);
1058 /* give maximum priority to this pipe */
1059 cn->info &= ~PRIMASK;
1060 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1061 }
1062 } else {
1063 cn->r.n = vn;
1064 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1065 }
1066 vn->a.n = cn;
1067
1068 } else {
1069 /* for operands and prefix-unary operators, attach them
1070 * to last node */
1071 vn = cn;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001072 cn = vn->r.n = new_node(t.info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001073 cn->a.n = vn;
1074 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1075 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001076 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001077 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001078 * only simple tclasses should be used! */
1079 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001080 case TC_VARIABLE:
1081 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001082 cn->info = OC_VAR;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001083 if ((v = hash_search(ahash, t.string)) != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001084 cn->info = OC_FNARG;
1085 cn->l.i = v->x.aidx;
1086 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00001087 cn->l.v = newvar(t.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001088 }
1089 if (tc & TC_ARRAY) {
1090 cn->info |= xS;
1091 cn->r.n = parse_expr(TC_ARRTERM);
1092 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001093 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001094
Denis Vlasenkof782f522007-01-01 23:51:30 +00001095 case TC_NUMBER:
1096 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001097 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001098 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001099 if (tc & TC_NUMBER)
1100 setvar_i(v, t.number);
1101 else
1102 setvar_s(v, t.string);
1103 break;
1104
Denis Vlasenkof782f522007-01-01 23:51:30 +00001105 case TC_REGEXP:
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001106 mk_re_node(t.string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001107 break;
1108
Denis Vlasenkof782f522007-01-01 23:51:30 +00001109 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001110 cn->info = OC_FUNC;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001111 cn->r.f = newfunc(t.string);
1112 cn->l.n = condition();
1113 break;
1114
Denis Vlasenkof782f522007-01-01 23:51:30 +00001115 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001116 cn = vn->r.n = parse_expr(TC_SEQTERM);
1117 cn->a.n = vn;
1118 break;
1119
Denis Vlasenkof782f522007-01-01 23:51:30 +00001120 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001121 glptr = cn;
1122 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1123 break;
1124
Denis Vlasenkof782f522007-01-01 23:51:30 +00001125 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001126 cn->l.n = condition();
1127 break;
1128 }
1129 }
1130 }
1131 }
1132 return sn.r.n;
1133}
1134
1135/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001136static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001137{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001138 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001139
1140 if (! seq->first)
1141 seq->first = seq->last = new_node(0);
1142
1143 if (seq->programname != programname) {
1144 seq->programname = programname;
1145 n = chain_node(OC_NEWSOURCE);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001146 n->l.s = xstrdup(programname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001147 }
1148
1149 n = seq->last;
1150 n->info = info;
1151 seq->last = n->a.n = new_node(OC_DONE);
1152
1153 return n;
1154}
1155
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001156static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001157{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001158 node *n;
1159
1160 n = chain_node(info);
1161 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1162 if (t.tclass & TC_GRPTERM)
1163 rollback_token();
1164}
1165
Mike Frysinger10a11e22005-09-27 02:23:02 +00001166static node *chain_loop(node *nn)
1167{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001168 node *n, *n2, *save_brk, *save_cont;
1169
1170 save_brk = break_ptr;
1171 save_cont = continue_ptr;
1172
1173 n = chain_node(OC_BR | Vx);
1174 continue_ptr = new_node(OC_EXEC);
1175 break_ptr = new_node(OC_EXEC);
1176 chain_group();
1177 n2 = chain_node(OC_EXEC | Vx);
1178 n2->l.n = nn;
1179 n2->a.n = n;
1180 continue_ptr->a.n = n2;
1181 break_ptr->a.n = n->r.n = seq->last;
1182
1183 continue_ptr = save_cont;
1184 break_ptr = save_brk;
1185
1186 return n;
1187}
1188
1189/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001190static void chain_group(void)
1191{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001192 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001193 node *n, *n2, *n3;
1194
1195 do {
1196 c = next_token(TC_GRPSEQ);
1197 } while (c & TC_NEWLINE);
1198
1199 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001200 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Mike Frysingerde2b9382005-09-27 03:18:00 +00001201 if (t.tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001202 rollback_token();
1203 chain_group();
1204 }
1205 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1206 rollback_token();
1207 chain_expr(OC_EXEC | Vx);
1208 } else { /* TC_STATEMNT */
1209 switch (t.info & OPCLSMASK) {
1210 case ST_IF:
1211 n = chain_node(OC_BR | Vx);
1212 n->l.n = condition();
1213 chain_group();
1214 n2 = chain_node(OC_EXEC);
1215 n->r.n = seq->last;
1216 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE)==TC_ELSE) {
1217 chain_group();
1218 n2->a.n = seq->last;
1219 } else {
1220 rollback_token();
1221 }
1222 break;
1223
1224 case ST_WHILE:
1225 n2 = condition();
1226 n = chain_loop(NULL);
1227 n->l.n = n2;
1228 break;
1229
1230 case ST_DO:
1231 n2 = chain_node(OC_EXEC);
1232 n = chain_loop(NULL);
1233 n2->a.n = n->a.n;
1234 next_token(TC_WHILE);
1235 n->l.n = condition();
1236 break;
1237
1238 case ST_FOR:
1239 next_token(TC_SEQSTART);
1240 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001241 if (t.tclass & TC_SEQTERM) { /* for-in */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001242 if ((n2->info & OPCLSMASK) != OC_IN)
1243 syntax_error(EMSG_UNEXP_TOKEN);
1244 n = chain_node(OC_WALKINIT | VV);
1245 n->l.n = n2->l.n;
1246 n->r.n = n2->r.n;
1247 n = chain_loop(NULL);
1248 n->info = OC_WALKNEXT | Vx;
1249 n->l.n = n2->l.n;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001250 } else { /* for (;;) */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001251 n = chain_node(OC_EXEC | Vx);
1252 n->l.n = n2;
1253 n2 = parse_expr(TC_SEMICOL);
1254 n3 = parse_expr(TC_SEQTERM);
1255 n = chain_loop(n3);
1256 n->l.n = n2;
1257 if (! n2)
1258 n->info = OC_EXEC;
1259 }
1260 break;
1261
1262 case OC_PRINT:
1263 case OC_PRINTF:
1264 n = chain_node(t.info);
1265 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
1266 if (t.tclass & TC_OUTRDR) {
1267 n->info |= t.info;
1268 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1269 }
1270 if (t.tclass & TC_GRPTERM)
1271 rollback_token();
1272 break;
1273
1274 case OC_BREAK:
1275 n = chain_node(OC_EXEC);
1276 n->a.n = break_ptr;
1277 break;
1278
1279 case OC_CONTINUE:
1280 n = chain_node(OC_EXEC);
1281 n->a.n = continue_ptr;
1282 break;
1283
1284 /* delete, next, nextfile, return, exit */
1285 default:
1286 chain_expr(t.info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001287 }
1288 }
1289}
1290
Mike Frysinger10a11e22005-09-27 02:23:02 +00001291static void parse_program(char *p)
1292{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001293 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001294 node *cn;
1295 func *f;
1296 var *v;
1297
1298 pos = p;
1299 t.lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001300 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Glenn L McGrath545106f2002-11-11 06:21:00 +00001301 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
1302
1303 if (tclass & TC_OPTERM)
1304 continue;
1305
1306 seq = &mainseq;
1307 if (tclass & TC_BEGIN) {
1308 seq = &beginseq;
1309 chain_group();
1310
1311 } else if (tclass & TC_END) {
1312 seq = &endseq;
1313 chain_group();
1314
1315 } else if (tclass & TC_FUNCDECL) {
1316 next_token(TC_FUNCTION);
1317 pos++;
1318 f = newfunc(t.string);
1319 f->body.first = NULL;
1320 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001321 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001322 v = findvar(ahash, t.string);
1323 v->x.aidx = (f->nargs)++;
1324
1325 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1326 break;
1327 }
1328 seq = &(f->body);
1329 chain_group();
1330 clear_array(ahash);
1331
1332 } else if (tclass & TC_OPSEQ) {
1333 rollback_token();
1334 cn = chain_node(OC_TEST);
1335 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
1336 if (t.tclass & TC_GRPSTART) {
1337 rollback_token();
1338 chain_group();
1339 } else {
1340 chain_node(OC_PRINT);
1341 }
1342 cn->r.n = mainseq.last;
1343
1344 } else /* if (tclass & TC_GRPSTART) */ {
1345 rollback_token();
1346 chain_group();
1347 }
1348 }
1349}
1350
1351
1352/* -------- program execution part -------- */
1353
Mike Frysinger10a11e22005-09-27 02:23:02 +00001354static node *mk_splitter(char *s, tsplitter *spl)
1355{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001356 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001357 node *n;
1358
1359 re = &spl->re[0];
1360 ire = &spl->re[1];
1361 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001362 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001363 regfree(re);
1364 regfree(ire);
1365 }
Rob Landleya3896512006-05-07 20:20:34 +00001366 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001367 mk_re_node(s, n, re);
1368 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001369 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001370 }
1371
1372 return n;
1373}
1374
1375/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001376 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001377 * be later regfree'd manually
1378 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001379static regex_t *as_regex(node *op, regex_t *preg)
1380{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001381 var *v;
1382 char *s;
1383
1384 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1385 return icase ? op->r.ire : op->l.re;
1386 } else {
1387 v = nvalloc(1);
1388 s = getvar_s(evaluate(op, v));
1389 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1390 nvfree(v);
1391 return preg;
1392 }
1393}
1394
1395/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001396static void qrealloc(char **b, int n, int *size)
1397{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001398 if (! *b || n >= *size)
1399 *b = xrealloc(*b, *size = n + (n>>1) + 80);
1400}
1401
1402/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001403static void fsrealloc(int size)
1404{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001405 static int maxfields = 0;
1406 int i;
1407
1408 if (size >= maxfields) {
1409 i = maxfields;
1410 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001411 Fields = xrealloc(Fields, maxfields * sizeof(var));
1412 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001413 Fields[i].type = VF_SPECIAL;
1414 Fields[i].string = NULL;
1415 }
1416 }
1417
1418 if (size < nfields) {
1419 for (i=size; i<nfields; i++) {
1420 clrvar(Fields+i);
1421 }
1422 }
1423 nfields = size;
1424}
1425
Mike Frysinger10a11e22005-09-27 02:23:02 +00001426static int awk_split(char *s, node *spl, char **slist)
1427{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001428 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001429 char c[4];
1430 char *s1;
1431 regmatch_t pmatch[2];
1432
1433 /* in worst case, each char would be a separate field */
Rob Landleyd921b2e2006-08-03 15:41:12 +00001434 *slist = s1 = xstrndup(s, strlen(s) * 2 + 3);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001435
1436 c[0] = c[1] = (char)spl->info;
1437 c[2] = c[3] = '\0';
1438 if (*getvar_s(V[RS]) == '\0') c[2] = '\n';
1439
1440 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1441 while (*s) {
1442 l = strcspn(s, c+2);
1443 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0 &&
1444 pmatch[0].rm_so <= l) {
1445 l = pmatch[0].rm_so;
1446 if (pmatch[0].rm_eo == 0) { l++; pmatch[0].rm_eo++; }
1447 } else {
1448 pmatch[0].rm_eo = l;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001449 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001450 }
1451
1452 memcpy(s1, s, l);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001453 s1[l] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001454 nextword(&s1);
1455 s += pmatch[0].rm_eo;
1456 n++;
1457 }
1458 } else if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001459 while (*s) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001460 *(s1++) = *(s++);
1461 *(s1++) = '\0';
1462 n++;
1463 }
1464 } else if (c[0] != ' ') { /* single-character split */
1465 if (icase) {
1466 c[0] = toupper(c[0]);
1467 c[1] = tolower(c[1]);
1468 }
1469 if (*s1) n++;
1470 while ((s1 = strpbrk(s1, c))) {
1471 *(s1++) = '\0';
1472 n++;
1473 }
1474 } else { /* space split */
1475 while (*s) {
Denis Vlasenkod18a3a22006-10-25 12:46:03 +00001476 s = skip_whitespace(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001477 if (! *s) break;
1478 n++;
1479 while (*s && !isspace(*s))
1480 *(s1++) = *(s++);
1481 *(s1++) = '\0';
1482 }
1483 }
1484 return n;
1485}
1486
Mike Frysinger10a11e22005-09-27 02:23:02 +00001487static void split_f0(void)
1488{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001489 static char *fstrings = NULL;
1490 int i, n;
1491 char *s;
1492
1493 if (is_f0_split)
1494 return;
1495
1496 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001497 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001498 fsrealloc(0);
1499 n = awk_split(getvar_s(V[F0]), &fsplitter.n, &fstrings);
1500 fsrealloc(n);
1501 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001502 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001503 Fields[i].string = nextword(&s);
1504 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1505 }
1506
1507 /* set NF manually to avoid side effects */
1508 clrvar(V[NF]);
1509 V[NF]->type = VF_NUMBER | VF_SPECIAL;
1510 V[NF]->number = nfields;
1511}
1512
1513/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001514static void handle_special(var *v)
1515{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001516 int n;
1517 char *b, *sep, *s;
1518 int sl, l, len, i, bsize;
1519
1520 if (! (v->type & VF_SPECIAL))
1521 return;
1522
1523 if (v == V[NF]) {
1524 n = (int)getvar_i(v);
1525 fsrealloc(n);
1526
1527 /* recalculate $0 */
1528 sep = getvar_s(V[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001529 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001530 b = NULL;
1531 len = 0;
1532 for (i=0; i<n; i++) {
1533 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001534 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001535 if (b) {
1536 memcpy(b+len, sep, sl);
1537 len += sl;
1538 }
1539 qrealloc(&b, len+l+sl, &bsize);
1540 memcpy(b+len, s, l);
1541 len += l;
1542 }
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00001543 if (b) 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
1559 } else { /* $n */
1560 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;
1743 char *fmt, *s, *s1, *f;
1744 int i, j, incr, bsize;
1745 char c, c1;
1746 var *v, *arg;
1747
1748 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001749 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001750
1751 i = 0;
1752 while (*f) {
1753 s = f;
1754 while (*f && (*f != '%' || *(++f) == '%'))
1755 f++;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001756 while (*f && !isalpha(*f))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001757 f++;
1758
1759 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001760 qrealloc(&b, incr + i, &bsize);
1761 c = *f;
1762 if (c != '\0') f++;
1763 c1 = *f;
1764 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001765 arg = evaluate(nextarg(&n), v);
1766
1767 j = i;
1768 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001769 i += sprintf(b+i, s, is_numeric(arg) ?
1770 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001771
1772 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001773 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001774 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001775 i += sprintf(b+i, s, s1);
1776
1777 } else {
1778 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1779 }
1780 *f = c1;
1781
1782 /* if there was an error while sprintf, return value is negative */
1783 if (i < j) i = j;
1784
1785 }
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 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001800static int awk_sub(node *rn, char *repl, int nm, var *src, var *dest, int ex)
1801{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001802 char *ds = NULL;
1803 char *sp, *s;
1804 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1805 regmatch_t pmatch[10];
1806 regex_t sreg, *re;
1807
1808 re = as_regex(rn, &sreg);
1809 if (! src) src = V[F0];
1810 if (! dest) dest = V[F0];
1811
1812 i = di = 0;
1813 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001814 rl = strlen(repl);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001815 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0:REG_NOTBOL) == 0) {
1816 so = pmatch[0].rm_so;
1817 eo = pmatch[0].rm_eo;
1818
1819 qrealloc(&ds, di + eo + rl, &dssize);
1820 memcpy(ds + di, sp, eo);
1821 di += eo;
1822 if (++i >= nm) {
1823 /* replace */
1824 di -= (eo - so);
1825 nbs = 0;
1826 for (s = repl; *s; s++) {
1827 ds[di++] = c = *s;
1828 if (c == '\\') {
1829 nbs++;
1830 continue;
1831 }
1832 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1833 di -= ((nbs + 3) >> 1);
1834 j = 0;
1835 if (c != '&') {
1836 j = c - '0';
1837 nbs++;
1838 }
1839 if (nbs % 2) {
1840 ds[di++] = c;
1841 } else {
1842 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1843 qrealloc(&ds, di + rl + n, &dssize);
1844 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1845 di += n;
1846 }
1847 }
1848 nbs = 0;
1849 }
1850 }
1851
1852 sp += eo;
1853 if (i == nm) break;
1854 if (eo == so) {
1855 if (! (ds[di++] = *sp++)) break;
1856 }
1857 }
1858
1859 qrealloc(&ds, di + strlen(sp), &dssize);
1860 strcpy(ds + di, sp);
1861 setvar_p(dest, ds);
1862 if (re == &sreg) regfree(re);
1863 return i;
1864}
1865
Mike Frysinger10a11e22005-09-27 02:23:02 +00001866static var *exec_builtin(node *op, var *res)
1867{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001868 int (*to_xxx)(int);
1869 var *tv;
1870 node *an[4];
1871 var *av[4];
1872 char *as[4];
1873 regmatch_t pmatch[2];
1874 regex_t sreg, *re;
1875 static tsplitter tspl;
1876 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001877 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001878 int nargs;
1879 time_t tt;
1880 char *s, *s1;
1881 int i, l, ll, n;
1882
1883 tv = nvalloc(4);
1884 isr = info = op->info;
1885 op = op->l.n;
1886
1887 av[2] = av[3] = NULL;
1888 for (i=0 ; i<4 && op ; i++) {
1889 an[i] = nextarg(&op);
1890 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
1891 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
1892 isr >>= 1;
1893 }
1894
1895 nargs = i;
1896 if (nargs < (info >> 30))
1897 runtime_error(EMSG_TOO_FEW_ARGS);
1898
1899 switch (info & OPNMASK) {
1900
Denis Vlasenkof782f522007-01-01 23:51:30 +00001901 case B_a2:
1902#if ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +00001903 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
1904#else
1905 runtime_error(EMSG_NO_MATH);
1906#endif
1907 break;
1908
Denis Vlasenkof782f522007-01-01 23:51:30 +00001909 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001910 if (nargs > 2) {
1911 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
1912 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
1913 } else {
1914 spl = &fsplitter.n;
1915 }
1916
1917 n = awk_split(as[0], spl, &s);
1918 s1 = s;
1919 clear_array(iamarray(av[1]));
1920 for (i=1; i<=n; i++)
1921 setari_u(av[1], i, nextword(&s1));
1922 free(s);
1923 setvar_i(res, n);
1924 break;
1925
Denis Vlasenkof782f522007-01-01 23:51:30 +00001926 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00001927 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001928 i = getvar_i(av[1]) - 1;
1929 if (i>l) i=l; if (i<0) i=0;
1930 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
1931 if (n<0) n=0;
1932 s = xmalloc(n+1);
1933 strncpy(s, as[0]+i, n);
1934 s[n] = '\0';
1935 setvar_p(res, s);
1936 break;
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001937
Denis Vlasenkof782f522007-01-01 23:51:30 +00001938 case B_an:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001939 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
1940 break;
1941
Denis Vlasenkof782f522007-01-01 23:51:30 +00001942 case B_co:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001943 setvar_i(res, ~(long)getvar_i(av[0]));
1944 break;
1945
Denis Vlasenkof782f522007-01-01 23:51:30 +00001946 case B_ls:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001947 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
1948 break;
1949
Denis Vlasenkof782f522007-01-01 23:51:30 +00001950 case B_or:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001951 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
1952 break;
1953
Denis Vlasenkof782f522007-01-01 23:51:30 +00001954 case B_rs:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001955 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
1956 break;
1957
Denis Vlasenkof782f522007-01-01 23:51:30 +00001958 case B_xo:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001959 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
1960 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001961
Denis Vlasenkof782f522007-01-01 23:51:30 +00001962 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001963 to_xxx = tolower;
1964 goto lo_cont;
1965
Denis Vlasenkof782f522007-01-01 23:51:30 +00001966 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001967 to_xxx = toupper;
1968lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00001969 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001970 while (*s1) {
1971 *s1 = (*to_xxx)(*s1);
1972 s1++;
1973 }
1974 setvar_p(res, s);
1975 break;
1976
Denis Vlasenkof782f522007-01-01 23:51:30 +00001977 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001978 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00001979 ll = strlen(as[1]);
1980 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001981 if (ll > 0 && l >= 0) {
1982 if (! icase) {
1983 s = strstr(as[0], as[1]);
1984 if (s) n = (s - as[0]) + 1;
1985 } else {
1986 /* this piece of code is terribly slow and
1987 * really should be rewritten
1988 */
1989 for (i=0; i<=l; i++) {
1990 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
1991 n = i+1;
1992 break;
1993 }
1994 }
1995 }
1996 }
1997 setvar_i(res, n);
1998 break;
1999
Denis Vlasenkof782f522007-01-01 23:51:30 +00002000 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002001 if (nargs > 1)
2002 tt = getvar_i(av[1]);
2003 else
2004 time(&tt);
2005 s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
2006 i = strftime(buf, MAXVARFMT, s, localtime(&tt));
2007 buf[i] = '\0';
2008 setvar_s(res, buf);
2009 break;
2010
Denis Vlasenkof782f522007-01-01 23:51:30 +00002011 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002012 re = as_regex(an[1], &sreg);
2013 n = regexec(re, as[0], 1, pmatch, 0);
2014 if (n == 0) {
2015 pmatch[0].rm_so++;
2016 pmatch[0].rm_eo++;
2017 } else {
2018 pmatch[0].rm_so = 0;
2019 pmatch[0].rm_eo = -1;
2020 }
2021 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2022 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2023 setvar_i(res, pmatch[0].rm_so);
2024 if (re == &sreg) regfree(re);
2025 break;
2026
Denis Vlasenkof782f522007-01-01 23:51:30 +00002027 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002028 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2029 break;
2030
Denis Vlasenkof782f522007-01-01 23:51:30 +00002031 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002032 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2033 break;
2034
Denis Vlasenkof782f522007-01-01 23:51:30 +00002035 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002036 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2037 break;
2038 }
2039
2040 nvfree(tv);
2041 return res;
2042}
2043
2044/*
2045 * Evaluate node - the heart of the program. Supplied with subtree
2046 * and place where to store result. returns ptr to result.
2047 */
2048#define XC(n) ((n) >> 8)
2049
Mike Frysinger10a11e22005-09-27 02:23:02 +00002050static var *evaluate(node *op, var *res)
2051{
Mike Frysingerde2b9382005-09-27 03:18:00 +00002052 /* This procedure is recursive so we should count every byte */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002053 static var *fnargs = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002054 static unsigned seed = 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002055 static regex_t sreg;
2056 node *op1;
2057 var *v1;
2058 union {
2059 var *v;
2060 char *s;
2061 double d;
2062 int i;
2063 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002064 uint32_t opinfo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002065 short opn;
2066 union {
2067 char *s;
2068 rstream *rsm;
2069 FILE *F;
2070 var *v;
2071 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002072 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002073 } X;
2074
2075 if (! op)
2076 return setvar_s(res, NULL);
2077
2078 v1 = nvalloc(2);
2079
2080 while (op) {
2081
2082 opinfo = op->info;
2083 opn = (short)(opinfo & OPNMASK);
2084 lineno = op->lineno;
2085
Mike Frysingerde2b9382005-09-27 03:18:00 +00002086 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002087 op1 = op->l.n;
2088 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2089 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2090 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2091 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2092 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2093
2094 switch (XC(opinfo & OPCLSMASK)) {
2095
2096 /* -- iterative node type -- */
2097
2098 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002099 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002100 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2101 /* it's range pattern */
2102 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2103 op->info |= OF_CHECKED;
2104 if (ptest(op1->r.n))
2105 op->info &= ~OF_CHECKED;
2106
2107 op = op->a.n;
2108 } else {
2109 op = op->r.n;
2110 }
2111 } else {
2112 op = (ptest(op1)) ? op->a.n : op->r.n;
2113 }
2114 break;
2115
2116 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002117 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002118 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002119
2120 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002121 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002122 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002123 break;
2124
2125 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002126 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002127 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002128 break;
2129
2130 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002131 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002132 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2133 break;
2134
Denis Vlasenkof782f522007-01-01 23:51:30 +00002135 case XC( OC_PRINT ):
2136 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002137 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002138 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002139 X.rsm = newfile(R.s);
2140 if (! X.rsm->F) {
2141 if (opn == '|') {
2142 if((X.rsm->F = popen(R.s, "w")) == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002143 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002144 X.rsm->is_pipe = 1;
2145 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002146 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002147 }
2148 }
2149 X.F = X.rsm->F;
2150 }
2151
2152 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002153 if (! op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002154 fputs(getvar_s(V[F0]), X.F);
2155 } else {
2156 while (op1) {
2157 L.v = evaluate(nextarg(&op1), v1);
2158 if (L.v->type & VF_NUMBER) {
2159 fmt_num(buf, MAXVARFMT, getvar_s(V[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002160 getvar_i(L.v), TRUE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002161 fputs(buf, X.F);
2162 } else {
2163 fputs(getvar_s(L.v), X.F);
2164 }
2165
2166 if (op1) fputs(getvar_s(V[OFS]), X.F);
2167 }
2168 }
2169 fputs(getvar_s(V[ORS]), X.F);
2170
2171 } else { /* OC_PRINTF */
2172 L.s = awk_printf(op1);
2173 fputs(L.s, X.F);
2174 free(L.s);
2175 }
2176 fflush(X.F);
2177 break;
2178
Denis Vlasenkof782f522007-01-01 23:51:30 +00002179 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002180 X.info = op1->info & OPCLSMASK;
2181 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002182 R.v = op1->l.v;
2183 } else if (X.info == OC_FNARG) {
2184 R.v = &fnargs[op1->l.i];
2185 } else {
2186 runtime_error(EMSG_NOT_ARRAY);
2187 }
2188
Mike Frysingerde2b9382005-09-27 03:18:00 +00002189 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002190 clrvar(L.v);
2191 L.s = getvar_s(evaluate(op1->r.n, v1));
2192 hash_remove(iamarray(R.v), L.s);
2193 } else {
2194 clear_array(iamarray(R.v));
2195 }
2196 break;
2197
Denis Vlasenkof782f522007-01-01 23:51:30 +00002198 case XC( OC_NEWSOURCE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002199 programname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002200 break;
2201
Denis Vlasenkof782f522007-01-01 23:51:30 +00002202 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002203 copyvar(res, L.v);
2204 break;
2205
Denis Vlasenkof782f522007-01-01 23:51:30 +00002206 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002207 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002208 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002209 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002210 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002211 clrvar(res);
2212 break;
2213
Denis Vlasenkof782f522007-01-01 23:51:30 +00002214 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002215 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002216
2217 /* -- recursive node type -- */
2218
Denis Vlasenkof782f522007-01-01 23:51:30 +00002219 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002220 L.v = op->l.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002221 if (L.v == V[NF])
2222 split_f0();
2223 goto v_cont;
2224
Denis Vlasenkof782f522007-01-01 23:51:30 +00002225 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002226 L.v = &fnargs[op->l.i];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002227
2228v_cont:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002229 res = (op->r.n) ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002230 break;
2231
Denis Vlasenkof782f522007-01-01 23:51:30 +00002232 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002233 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2234 break;
2235
Denis Vlasenkof782f522007-01-01 23:51:30 +00002236 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002237 op1 = op;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002238 L.s = getvar_s(V[F0]);
2239 goto re_cont;
2240
Denis Vlasenkof782f522007-01-01 23:51:30 +00002241 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002242 op1 = op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002243re_cont:
2244 X.re = as_regex(op1, &sreg);
2245 R.i = regexec(X.re, L.s, 0, NULL, 0);
2246 if (X.re == &sreg) regfree(X.re);
2247 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2248 break;
2249
Denis Vlasenkof782f522007-01-01 23:51:30 +00002250 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002251 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002252 if (R.v == v1+1 && R.v->string) {
2253 res = setvar_p(L.v, R.v->string);
2254 R.v->string = NULL;
2255 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002256 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002257 }
2258 break;
2259
Denis Vlasenkof782f522007-01-01 23:51:30 +00002260 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002261 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002262 runtime_error(EMSG_POSSIBLE_ERROR);
2263 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2264 break;
2265
Denis Vlasenkof782f522007-01-01 23:51:30 +00002266 case XC( OC_FUNC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002267 if (! op->r.f->body.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002268 runtime_error(EMSG_UNDEF_FUNC);
2269
2270 X.v = R.v = nvalloc(op->r.f->nargs+1);
2271 while (op1) {
2272 L.v = evaluate(nextarg(&op1), v1);
2273 copyvar(R.v, L.v);
2274 R.v->type |= VF_CHILD;
2275 R.v->x.parent = L.v;
2276 if (++R.v - X.v >= op->r.f->nargs)
2277 break;
2278 }
2279
2280 R.v = fnargs;
2281 fnargs = X.v;
2282
2283 L.s = programname;
2284 res = evaluate(op->r.f->body.first, res);
2285 programname = L.s;
2286
2287 nvfree(fnargs);
2288 fnargs = R.v;
2289 break;
2290
Denis Vlasenkof782f522007-01-01 23:51:30 +00002291 case XC( OC_GETLINE ):
2292 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002293 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002294 X.rsm = newfile(L.s);
2295 if (! X.rsm->F) {
2296 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2297 X.rsm->F = popen(L.s, "r");
2298 X.rsm->is_pipe = TRUE;
2299 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002300 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002301 }
2302 }
2303 } else {
2304 if (! iF) iF = next_input_file();
2305 X.rsm = iF;
2306 }
2307
2308 if (! X.rsm->F) {
2309 setvar_i(V[ERRNO], errno);
2310 setvar_i(res, -1);
2311 break;
2312 }
2313
2314 if (! op->r.n)
2315 R.v = V[F0];
2316
2317 L.i = awk_getline(X.rsm, R.v);
2318 if (L.i > 0) {
2319 if (! op1) {
2320 incvar(V[FNR]);
2321 incvar(V[NR]);
2322 }
2323 }
2324 setvar_i(res, L.i);
2325 break;
2326
Mike Frysingerde2b9382005-09-27 03:18:00 +00002327 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002328 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002329 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002330
Denis Vlasenkof782f522007-01-01 23:51:30 +00002331 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002332 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002333 break;
2334
Denis Vlasenkof782f522007-01-01 23:51:30 +00002335 case F_rn:
2336 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002337 break;
2338
Denis Vlasenkof782f522007-01-01 23:51:30 +00002339#if ENABLE_FEATURE_AWK_MATH
2340 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002341 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002342 break;
2343
Denis Vlasenkof782f522007-01-01 23:51:30 +00002344 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002345 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002346 break;
2347
Denis Vlasenkof782f522007-01-01 23:51:30 +00002348 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002349 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002350 break;
2351
Denis Vlasenkof782f522007-01-01 23:51:30 +00002352 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002353 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002354 break;
2355
Denis Vlasenkof782f522007-01-01 23:51:30 +00002356 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002357 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002358 break;
2359#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002360 case F_co:
2361 case F_ex:
2362 case F_lg:
2363 case F_si:
2364 case F_sq:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002365 runtime_error(EMSG_NO_MATH);
2366 break;
2367#endif
2368
Denis Vlasenkof782f522007-01-01 23:51:30 +00002369 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002370 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002371 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002372 srand(seed);
2373 break;
2374
Denis Vlasenkof782f522007-01-01 23:51:30 +00002375 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002376 R.d = time(NULL);
2377 break;
2378
Denis Vlasenkof782f522007-01-01 23:51:30 +00002379 case F_le:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002380 if (! op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002381 L.s = getvar_s(V[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002382 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002383 break;
2384
Denis Vlasenkof782f522007-01-01 23:51:30 +00002385 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002386 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002387 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2388 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002389 break;
2390
Denis Vlasenkof782f522007-01-01 23:51:30 +00002391 case F_ff:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002392 if (! op1)
2393 fflush(stdout);
2394 else {
2395 if (L.s && *L.s) {
2396 X.rsm = newfile(L.s);
2397 fflush(X.rsm->F);
2398 } else {
2399 fflush(NULL);
2400 }
2401 }
2402 break;
2403
Denis Vlasenkof782f522007-01-01 23:51:30 +00002404 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002405 X.rsm = (rstream *)hash_search(fdhash, L.s);
2406 if (X.rsm) {
2407 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002408 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002409 hash_remove(fdhash, L.s);
2410 }
2411 if (R.i != 0)
2412 setvar_i(V[ERRNO], errno);
2413 R.d = (double)R.i;
2414 break;
2415 }
2416 setvar_i(res, R.d);
2417 break;
2418
Denis Vlasenkof782f522007-01-01 23:51:30 +00002419 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002420 res = exec_builtin(op, res);
2421 break;
2422
Denis Vlasenkof782f522007-01-01 23:51:30 +00002423 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002424 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002425 break;
2426
Denis Vlasenkof782f522007-01-01 23:51:30 +00002427 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002428 X.v = R.v;
2429 L.d = R.d = getvar_i(R.v);
2430 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002431 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002432 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002433 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002434 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002435 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002436 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002437 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002438 L.d = --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 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002442 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002443 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002444 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002445 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002446 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002447 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002448 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002449 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002450 setvar_i(X.v, R.d);
2451 }
2452 setvar_i(res, L.d);
2453 break;
2454
Denis Vlasenkof782f522007-01-01 23:51:30 +00002455 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002456 R.i = (int)getvar_i(R.v);
2457 if (R.i == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002458 res = V[F0];
2459 } else {
2460 split_f0();
2461 if (R.i > nfields)
2462 fsrealloc(R.i);
2463
2464 res = &Fields[R.i-1];
2465 }
2466 break;
2467
2468 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002469 case XC( OC_CONCAT ):
2470 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002471 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002472 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002473 strcpy(X.s, L.s);
2474 if ((opinfo & OPCLSMASK) == OC_COMMA) {
2475 L.s = getvar_s(V[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002476 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002477 strcat(X.s, L.s);
2478 }
2479 strcat(X.s, R.s);
2480 setvar_p(res, X.s);
2481 break;
2482
Denis Vlasenkof782f522007-01-01 23:51:30 +00002483 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002484 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2485 break;
2486
Denis Vlasenkof782f522007-01-01 23:51:30 +00002487 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002488 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2489 break;
2490
Denis Vlasenkof782f522007-01-01 23:51:30 +00002491 case XC( OC_BINARY ):
2492 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002493 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002494 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002495 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002496 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002497 break;
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 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2506 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002507 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002508 case '&':
2509#if ENABLE_FEATURE_AWK_MATH
Mike Frysingerde2b9382005-09-27 03:18:00 +00002510 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002511#else
2512 runtime_error(EMSG_NO_MATH);
2513#endif
2514 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002515 case '%':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002516 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2517 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002518 break;
2519 }
2520 res = setvar_i(((opinfo&OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
2521 break;
2522
Denis Vlasenkof782f522007-01-01 23:51:30 +00002523 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002524 if (is_numeric(L.v) && is_numeric(R.v)) {
2525 L.d = getvar_i(L.v) - getvar_i(R.v);
2526 } else {
2527 L.s = getvar_s(L.v);
2528 R.s = getvar_s(R.v);
2529 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2530 }
2531 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002532 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002533 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002534 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002535 case 2:
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 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002539 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002540 break;
2541 }
2542 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2543 break;
2544
Denis Vlasenkof782f522007-01-01 23:51:30 +00002545 default:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002546 runtime_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002547 }
2548 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2549 op = op->a.n;
2550 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2551 break;
2552 if (nextrec)
2553 break;
2554 }
2555 nvfree(v1);
2556 return res;
2557}
2558
2559
2560/* -------- main & co. -------- */
2561
Mike Frysinger10a11e22005-09-27 02:23:02 +00002562static int awk_exit(int r)
2563{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002564 var tv;
2565 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002566 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002567
Denis Vlasenkof782f522007-01-01 23:51:30 +00002568 zero_out_var(&tv);
2569
2570 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002571 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002572 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002573 evaluate(endseq.first, &tv);
2574 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002575
2576 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002577 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002578 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002579 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002580 if (hi->data.rs.F && hi->data.rs.is_pipe)
2581 pclose(hi->data.rs.F);
2582 hi = hi->next;
2583 }
2584 }
2585
2586 exit(r);
2587}
2588
2589/* if expr looks like "var=value", perform assignment and return 1,
2590 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002591static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002592{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002593 char *exprc, *s, *s0, *s1;
2594
Rob Landleyd921b2e2006-08-03 15:41:12 +00002595 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002596 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2597 free(exprc);
2598 return FALSE;
2599 }
2600
2601 *(s++) = '\0';
2602 s0 = s1 = s;
2603 while (*s)
2604 *(s1++) = nextchar(&s);
2605
2606 *s1 = '\0';
2607 setvar_u(newvar(exprc), s0);
2608 free(exprc);
2609 return TRUE;
2610}
2611
2612/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002613static rstream *next_input_file(void)
2614{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002615 static rstream rsm;
2616 FILE *F = NULL;
2617 char *fname, *ind;
2618 static int files_happen = FALSE;
2619
2620 if (rsm.F) fclose(rsm.F);
2621 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002622 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002623
2624 do {
2625 if (getvar_i(V[ARGIND])+1 >= getvar_i(V[ARGC])) {
2626 if (files_happen)
2627 return NULL;
2628 fname = "-";
2629 F = stdin;
2630 } else {
2631 ind = getvar_s(incvar(V[ARGIND]));
2632 fname = getvar_s(findvar(iamarray(V[ARGV]), ind));
2633 if (fname && *fname && !is_assignment(fname))
2634 F = afopen(fname, "r");
2635 }
2636 } while (!F);
2637
2638 files_happen = TRUE;
2639 setvar_s(V[FILENAME], fname);
2640 rsm.F = F;
2641 return &rsm;
2642}
2643
Rob Landleydfba7412006-03-06 20:47:33 +00002644int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002645{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002646 unsigned opt;
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002647 char *opt_F, *opt_v, *opt_W;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002648 int i, j, flen;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002649 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002650 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002651 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002652 char *vnames = (char *)vNames; /* cheat */
2653 char *vvalues = (char *)vValues;
2654
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002655 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
2656 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2657 if (ENABLE_LOCALE_SUPPORT)
2658 setlocale(LC_NUMERIC, "C");
2659
Denis Vlasenkof782f522007-01-01 23:51:30 +00002660 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002661
2662 /* allocate global buffer */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002663 buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002664
2665 vhash = hash_init();
2666 ahash = hash_init();
2667 fdhash = hash_init();
2668 fnhash = hash_init();
2669
2670 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002671 for (i = 0; *vnames; i++) {
2672 V[i] = v = newvar(nextword(&vnames));
2673 if (*vvalues != '\377')
2674 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002675 else
2676 setvar_i(v, 0);
2677
Denis Vlasenkof782f522007-01-01 23:51:30 +00002678 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002679 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002680 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002681 }
2682 }
2683
2684 handle_special(V[FS]);
2685 handle_special(V[RS]);
2686
Denis Vlasenkof782f522007-01-01 23:51:30 +00002687 newfile("/dev/stdin")->F = stdin;
2688 newfile("/dev/stdout")->F = stdout;
2689 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002690
Denis Vlasenkof782f522007-01-01 23:51:30 +00002691 for (envp = environ; *envp; envp++) {
2692 char *s = xstrdup(*envp);
2693 char *s1 = strchr(s, '=');
2694 if (s1) {
2695 *s1++ = '\0';
2696 setvar_u(findvar(iamarray(V[ENVIRON]), s), s1);
Eric Andersen67776be2004-07-30 23:52:08 +00002697 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002698 free(s);
2699 }
2700
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002701 opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &programname, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002702 argv += optind;
2703 argc -= optind;
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002704 if (opt & 0x1) setvar_s(V[FS], opt_F); // -F
2705 if (opt & 0x2) if (!is_assignment(opt_v)) bb_show_usage(); // -v
2706 if (opt & 0x4) { // -f
Denis Vlasenkof782f522007-01-01 23:51:30 +00002707 char *s = s; /* die, gcc, die */
2708 FILE *from_file = afopen(programname, "r");
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002709 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002710 if (fseek(from_file, 0, SEEK_END) == 0) {
2711 flen = ftell(from_file);
2712 s = xmalloc(flen + 4);
2713 fseek(from_file, 0, SEEK_SET);
2714 i = 1 + fread(s + 1, 1, flen, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002715 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002716 for (i = j = 1; j > 0; i += j) {
2717 s = xrealloc(s, i + 4096);
2718 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002719 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002720 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002721 s[i] = '\0';
Denis Vlasenkof782f522007-01-01 23:51:30 +00002722 fclose(from_file);
2723 parse_program(s + 1);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002724 free(s);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002725 } else { // no -f: take program from 1st parameter
2726 if (!argc)
2727 bb_show_usage();
2728 programname = "cmd. line";
2729 parse_program(*argv++);
2730 argc--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002731 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002732 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002733 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002734
Glenn L McGrath545106f2002-11-11 06:21:00 +00002735 /* fill in ARGV array */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002736 setvar_i(V[ARGC], argc + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002737 setari_u(V[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002738 i = 0;
2739 while (*argv)
2740 setari_u(V[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002741
2742 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002743 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002744 awk_exit(EXIT_SUCCESS);
2745
2746 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002747 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002748
2749 /* passing through input files */
2750 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002751 nextfile = FALSE;
2752 setvar_i(V[FNR], 0);
2753
Denis Vlasenkof782f522007-01-01 23:51:30 +00002754 while ((i = awk_getline(iF, V[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002755 nextrec = FALSE;
2756 incvar(V[NR]);
2757 incvar(V[FNR]);
2758 evaluate(mainseq.first, &tv);
2759
2760 if (nextfile)
2761 break;
2762 }
2763
Denis Vlasenkof782f522007-01-01 23:51:30 +00002764 if (i < 0)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002765 runtime_error(strerror(errno));
2766
2767 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002768 }
2769
Glenn L McGrath545106f2002-11-11 06:21:00 +00002770 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002771 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002772}