blob: bc9e99a6f555982e30bd08bfe43f017355c9a1fc [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
Denis Vlasenko99912ca2007-04-10 15:43:37 +000014/* This is a NOEXEC applet. Be very careful! */
15
Glenn L McGrath545106f2002-11-11 06:21:00 +000016
Denis Vlasenko629563b2007-02-24 17:05:52 +000017#define MAXVARFMT 240
18#define MINNVBLOCK 64
Glenn L McGrath545106f2002-11-11 06:21:00 +000019
20/* variable flags */
Denis Vlasenko629563b2007-02-24 17:05:52 +000021#define VF_NUMBER 0x0001 /* 1 = primary type is number */
22#define VF_ARRAY 0x0002 /* 1 = it's an array */
Glenn L McGrath545106f2002-11-11 06:21:00 +000023
Denis Vlasenko629563b2007-02-24 17:05:52 +000024#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
25#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
26#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
27#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
28#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
29#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
30#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
Glenn L McGrath545106f2002-11-11 06:21:00 +000031
32/* these flags are static, don't change them when value is changed */
Denis Vlasenko629563b2007-02-24 17:05:52 +000033#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
Glenn L McGrath545106f2002-11-11 06:21:00 +000034
35/* Variable */
36typedef struct var_s {
Denis Vlasenko629563b2007-02-24 17:05:52 +000037 unsigned short type; /* flags */
Glenn L McGrath545106f2002-11-11 06:21:00 +000038 double number;
39 char *string;
40 union {
Denis Vlasenko629563b2007-02-24 17:05:52 +000041 int aidx; /* func arg idx (for compilation stage) */
42 struct xhash_s *array; /* array ptr */
43 struct var_s *parent; /* for func args, ptr to actual parameter */
44 char **walker; /* list of array elements (for..in) */
Glenn L McGrath545106f2002-11-11 06:21:00 +000045 } x;
46} var;
47
48/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
49typedef struct chain_s {
50 struct node_s *first;
51 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +000052 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +000053} chain;
54
55/* Function */
56typedef struct func_s {
57 unsigned short nargs;
58 struct chain_s body;
59} func;
60
61/* I/O stream */
62typedef struct rstream_s {
63 FILE *F;
64 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +000065 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +000066 int size;
67 int pos;
68 unsigned short is_pipe;
69} rstream;
70
71typedef struct hash_item_s {
72 union {
73 struct var_s v; /* variable/array hash */
74 struct rstream_s rs; /* redirect streams hash */
75 struct func_s f; /* functions hash */
76 } data;
77 struct hash_item_s *next; /* next in chain */
78 char name[1]; /* really it's longer */
79} hash_item;
80
81typedef struct xhash_s {
Denis Vlasenkof782f522007-01-01 23:51:30 +000082 unsigned nel; /* num of elements */
83 unsigned csize; /* current hash size */
84 unsigned nprime; /* next hash size in PRIMES[] */
85 unsigned glen; /* summary length of item names */
Glenn L McGrath545106f2002-11-11 06:21:00 +000086 struct hash_item_s **items;
87} xhash;
88
89/* Tree node */
90typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +000091 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +000092 unsigned short lineno;
93 union {
94 struct node_s *n;
95 var *v;
96 int i;
97 char *s;
98 regex_t *re;
99 } l;
100 union {
101 struct node_s *n;
102 regex_t *ire;
103 func *f;
104 int argno;
105 } r;
106 union {
107 struct node_s *n;
108 } a;
109} node;
110
111/* Block of temporary variables */
112typedef struct nvblock_s {
113 int size;
114 var *pos;
115 struct nvblock_s *prev;
116 struct nvblock_s *next;
117 var nv[0];
118} nvblock;
119
120typedef struct tsplitter_s {
121 node n;
122 regex_t re[2];
123} tsplitter;
124
125/* simple token classes */
126/* Order and hex values are very important!!! See next_token() */
127#define TC_SEQSTART 1 /* ( */
128#define TC_SEQTERM (1 << 1) /* ) */
129#define TC_REGEXP (1 << 2) /* /.../ */
130#define TC_OUTRDR (1 << 3) /* | > >> */
131#define TC_UOPPOST (1 << 4) /* unary postfix operator */
132#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
133#define TC_BINOPX (1 << 6) /* two-opnd operator */
134#define TC_IN (1 << 7)
135#define TC_COMMA (1 << 8)
136#define TC_PIPE (1 << 9) /* input redirection pipe */
137#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
138#define TC_ARRTERM (1 << 11) /* ] */
139#define TC_GRPSTART (1 << 12) /* { */
140#define TC_GRPTERM (1 << 13) /* } */
141#define TC_SEMICOL (1 << 14)
142#define TC_NEWLINE (1 << 15)
143#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
144#define TC_WHILE (1 << 17)
145#define TC_ELSE (1 << 18)
146#define TC_BUILTIN (1 << 19)
147#define TC_GETLINE (1 << 20)
148#define TC_FUNCDECL (1 << 21) /* `function' `func' */
149#define TC_BEGIN (1 << 22)
150#define TC_END (1 << 23)
151#define TC_EOF (1 << 24)
152#define TC_VARIABLE (1 << 25)
153#define TC_ARRAY (1 << 26)
154#define TC_FUNCTION (1 << 27)
155#define TC_STRING (1 << 28)
156#define TC_NUMBER (1 << 29)
157
158#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
159
160/* combined token classes */
161#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
162#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
163#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION | \
164 TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
165
166#define TC_STATEMNT (TC_STATX | TC_WHILE)
167#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
168
169/* word tokens, cannot mean something else if not expected */
170#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN | \
171 TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
172
173/* discard newlines after these */
174#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM | \
175 TC_BINOP | TC_OPTERM)
176
177/* what can expression begin with */
178#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
179/* what can group begin with */
180#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
181
182/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
183/* operator is inserted between them */
184#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM | \
185 TC_STRING | TC_NUMBER | TC_UOPPOST)
186#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
187
188#define OF_RES1 0x010000
189#define OF_RES2 0x020000
190#define OF_STR1 0x040000
191#define OF_STR2 0x080000
192#define OF_NUM1 0x100000
193#define OF_CHECKED 0x200000
194
195/* combined operator flags */
196#define xx 0
197#define xV OF_RES2
198#define xS (OF_RES2 | OF_STR2)
199#define Vx OF_RES1
200#define VV (OF_RES1 | OF_RES2)
201#define Nx (OF_RES1 | OF_NUM1)
202#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
203#define Sx (OF_RES1 | OF_STR1)
204#define SV (OF_RES1 | OF_STR1 | OF_RES2)
205#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
206
207#define OPCLSMASK 0xFF00
208#define OPNMASK 0x007F
209
210/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
211 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
212 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
213 */
214#define P(x) (x << 24)
215#define PRIMASK 0x7F000000
216#define PRIMASK2 0x7E000000
217
218/* Operation classes */
219
220#define SHIFT_TIL_THIS 0x0600
221#define RECUR_FROM_THIS 0x1000
222
223enum {
224 OC_DELETE=0x0100, OC_EXEC=0x0200, OC_NEWSOURCE=0x0300,
225 OC_PRINT=0x0400, OC_PRINTF=0x0500, OC_WALKINIT=0x0600,
226
227 OC_BR=0x0700, OC_BREAK=0x0800, OC_CONTINUE=0x0900,
228 OC_EXIT=0x0a00, OC_NEXT=0x0b00, OC_NEXTFILE=0x0c00,
229 OC_TEST=0x0d00, OC_WALKNEXT=0x0e00,
230
231 OC_BINARY=0x1000, OC_BUILTIN=0x1100, OC_COLON=0x1200,
232 OC_COMMA=0x1300, OC_COMPARE=0x1400, OC_CONCAT=0x1500,
233 OC_FBLTIN=0x1600, OC_FIELD=0x1700, OC_FNARG=0x1800,
234 OC_FUNC=0x1900, OC_GETLINE=0x1a00, OC_IN=0x1b00,
235 OC_LAND=0x1c00, OC_LOR=0x1d00, OC_MATCH=0x1e00,
236 OC_MOVE=0x1f00, OC_PGETLINE=0x2000, OC_REGEXP=0x2100,
237 OC_REPLACE=0x2200, OC_RETURN=0x2300, OC_SPRINTF=0x2400,
238 OC_TERNARY=0x2500, OC_UNARY=0x2600, OC_VAR=0x2700,
239 OC_DONE=0x2800,
240
241 ST_IF=0x3000, ST_DO=0x3100, ST_FOR=0x3200,
242 ST_WHILE=0x3300
243};
244
245/* simple builtins */
246enum {
247 F_in=0, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
248 F_ti, F_le, F_sy, F_ff, F_cl
249};
250
251/* builtins */
252enum {
253 B_a2=0, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up,
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000254 B_ge, B_gs, B_su,
255 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000256};
257
258/* tokens and their corresponding info values */
259
260#define NTC "\377" /* switch to next token class (tc<<1) */
261#define NTCC '\377'
262
263#define OC_B OC_BUILTIN
264
Denis Vlasenkof782f522007-01-01 23:51:30 +0000265static const char tokenlist[] =
266 "\1(" NTC
267 "\1)" NTC
268 "\1/" NTC /* REGEXP */
269 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
270 "\2++" "\2--" NTC /* UOPPOST */
271 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
272 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
273 "\2*=" "\2/=" "\2%=" "\2^="
274 "\1+" "\1-" "\3**=" "\2**"
275 "\1/" "\1%" "\1^" "\1*"
276 "\2!=" "\2>=" "\2<=" "\1>"
277 "\1<" "\2!~" "\1~" "\2&&"
278 "\2||" "\1?" "\1:" NTC
279 "\2in" NTC
280 "\1," NTC
281 "\1|" NTC
282 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
283 "\1]" NTC
284 "\1{" NTC
285 "\1}" NTC
286 "\1;" NTC
287 "\1\n" NTC
288 "\2if" "\2do" "\3for" "\5break" /* STATX */
289 "\10continue" "\6delete" "\5print"
290 "\6printf" "\4next" "\10nextfile"
291 "\6return" "\4exit" NTC
292 "\5while" NTC
293 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000294
Denis Vlasenkof782f522007-01-01 23:51:30 +0000295 "\3and" "\5compl" "\6lshift" "\2or"
296 "\6rshift" "\3xor"
297 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
298 "\3cos" "\3exp" "\3int" "\3log"
299 "\4rand" "\3sin" "\4sqrt" "\5srand"
300 "\6gensub" "\4gsub" "\5index" "\6length"
301 "\5match" "\5split" "\7sprintf" "\3sub"
302 "\6substr" "\7systime" "\10strftime"
303 "\7tolower" "\7toupper" NTC
304 "\7getline" NTC
305 "\4func" "\10function" NTC
306 "\5BEGIN" NTC
307 "\3END" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000308 ;
309
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000310static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000311 0,
312 0,
313 OC_REGEXP,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000314 xS|'a', xS|'w', xS|'|',
315 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
316 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M',
317 OC_FIELD|xV|P(5),
318 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74),
319 OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
320 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/',
321 OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
322 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-',
323 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
324 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%',
325 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
326 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
327 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
328 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
329 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
330 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
331 OC_COLON|xx|P(67)|':',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000332 OC_IN|SV|P(49),
333 OC_COMMA|SS|P(80),
334 OC_PGETLINE|SV|P(37),
Denis Vlasenkof782f522007-01-01 23:51:30 +0000335 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',
336 OC_UNARY|xV|P(19)|'!',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000337 0,
338 0,
339 0,
340 0,
341 0,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000342 ST_IF, ST_DO, ST_FOR, OC_BREAK,
343 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
344 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
345 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000346 ST_WHILE,
347 0,
348
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000349 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
350 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000351 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
352 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
353 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
354 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
355 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
356 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b),
357 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
358 OC_GETLINE|SV|P(0),
359 0, 0,
360 0,
361 0
362};
363
364/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000365/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000366enum {
Denis Vlasenkof782f522007-01-01 23:51:30 +0000367 CONVFMT=0, OFMT, FS, OFS,
368 ORS, RS, RT, FILENAME,
369 SUBSEP, ARGIND, ARGC, ARGV,
370 ERRNO, FNR,
371 NR, NF, IGNORECASE,
372 ENVIRON, F0, _intvarcount_
Glenn L McGrath545106f2002-11-11 06:21:00 +0000373};
374
Denis Vlasenkof782f522007-01-01 23:51:30 +0000375static const char vNames[] =
376 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
377 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
378 "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0"
379 "ERRNO\0" "FNR\0"
380 "NR\0" "NF\0*" "IGNORECASE\0*"
381 "ENVIRON\0" "$\0*" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000382
Denis Vlasenkof782f522007-01-01 23:51:30 +0000383static const char vValues[] =
384 "%.6g\0" "%.6g\0" " \0" " \0"
385 "\n\0" "\n\0" "\0" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000386 "\034\0"
387 "\377";
388
389/* hash size may grow to these values */
390#define FIRST_PRIME 61;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000391static const unsigned PRIMES[] = { 251, 1021, 4093, 16381, 65521 };
392enum { NPRIMES = sizeof(PRIMES) / sizeof(unsigned) };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000393
394/* globals */
395
396extern char **environ;
397
398static var * V[_intvarcount_];
399static chain beginseq, mainseq, endseq, *seq;
400static int nextrec, nextfile;
401static node *break_ptr, *continue_ptr;
402static rstream *iF;
403static xhash *vhash, *ahash, *fdhash, *fnhash;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000404static const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000405static short lineno;
406static int is_f0_split;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000407static int nfields;
408static var *Fields;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000409static tsplitter fsplitter, rsplitter;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000410static nvblock *cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000411static char *pos;
412static char *buf;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000413static int icase;
414static int exiting;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000415
416static struct {
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000417 uint32_t tclass;
418 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000419 char *string;
420 double number;
421 short lineno;
422 int rollback;
423} t;
424
425/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000426static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000427static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000428static void chain_group(void);
429static var *evaluate(node *, var *);
430static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000431static int fmt_num(char *, int, const char *, double, int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000432static int awk_exit(int) ATTRIBUTE_NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000433
434/* ---- error handling ---- */
435
436static const char EMSG_INTERNAL_ERROR[] = "Internal error";
437static const char EMSG_UNEXP_EOS[] = "Unexpected end of string";
438static const char EMSG_UNEXP_TOKEN[] = "Unexpected token";
439static const char EMSG_DIV_BY_ZERO[] = "Division by zero";
440static const char EMSG_INV_FMT[] = "Invalid format specifier";
441static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin";
442static const char EMSG_NOT_ARRAY[] = "Not an array";
443static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error";
444static const char EMSG_UNDEF_FUNC[] = "Call to undefined function";
Denis Vlasenkof782f522007-01-01 23:51:30 +0000445#if !ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +0000446static const char EMSG_NO_MATH[] = "Math support is not compiled in";
447#endif
448
Denis Vlasenkof782f522007-01-01 23:51:30 +0000449static void zero_out_var(var * vp)
450{
451 memset(vp, 0, sizeof(*vp));
452}
453
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000454static void syntax_error(const char * const message) ATTRIBUTE_NORETURN;
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000455static void syntax_error(const char * const message)
456{
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000457 bb_error_msg_and_die("%s:%i: %s", programname, lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000458}
459
460#define runtime_error(x) syntax_error(x)
461
462
463/* ---- hash stuff ---- */
464
Denis Vlasenkof782f522007-01-01 23:51:30 +0000465static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000466{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000467 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000468
Denis Vlasenkof782f522007-01-01 23:51:30 +0000469 while (*name) idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000470 return idx;
471}
472
473/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000474static xhash *hash_init(void)
475{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000476 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000477
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000478 newhash = xzalloc(sizeof(xhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000479 newhash->csize = FIRST_PRIME;
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000480 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000481
482 return newhash;
483}
484
485/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000486static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000487{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000488 hash_item *hi;
489
490 hi = hash->items [ hashidx(name) % hash->csize ];
491 while (hi) {
492 if (strcmp(hi->name, name) == 0)
493 return &(hi->data);
494 hi = hi->next;
495 }
496 return NULL;
497}
498
499/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000500static void hash_rebuild(xhash *hash)
501{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000502 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000503 hash_item **newitems, *hi, *thi;
504
505 if (hash->nprime == NPRIMES)
506 return;
507
508 newsize = PRIMES[hash->nprime++];
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000509 newitems = xzalloc(newsize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000510
511 for (i=0; i<hash->csize; i++) {
512 hi = hash->items[i];
513 while (hi) {
514 thi = hi;
515 hi = thi->next;
516 idx = hashidx(thi->name) % newsize;
517 thi->next = newitems[idx];
518 newitems[idx] = thi;
519 }
520 }
521
522 free(hash->items);
523 hash->csize = newsize;
524 hash->items = newitems;
525}
526
527/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000528static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000529{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000530 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000531 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000532 int l;
533
534 hi = hash_search(hash, name);
535 if (! hi) {
536 if (++hash->nel / hash->csize > 10)
537 hash_rebuild(hash);
538
Rob Landleya3896512006-05-07 20:20:34 +0000539 l = strlen(name) + 1;
Rob Landley9ffd4232006-05-21 18:30:35 +0000540 hi = xzalloc(sizeof(hash_item) + l);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000541 memcpy(hi->name, name, l);
542
543 idx = hashidx(name) % hash->csize;
544 hi->next = hash->items[idx];
545 hash->items[idx] = hi;
546 hash->glen += l;
547 }
548 return &(hi->data);
549}
550
Denis Vlasenkof782f522007-01-01 23:51:30 +0000551#define findvar(hash, name) ((var*) hash_find((hash) , (name)))
552#define newvar(name) ((var*) hash_find(vhash , (name)))
553#define newfile(name) ((rstream*)hash_find(fdhash ,(name)))
554#define newfunc(name) ((func*) hash_find(fnhash , (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000555
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000556static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000557{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000558 hash_item *hi, **phi;
559
560 phi = &(hash->items[ hashidx(name) % hash->csize ]);
561 while (*phi) {
562 hi = *phi;
563 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000564 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000565 hash->nel--;
566 *phi = hi->next;
567 free(hi);
568 break;
569 }
570 phi = &(hi->next);
571 }
572}
573
574/* ------ some useful functions ------ */
575
Mike Frysinger10a11e22005-09-27 02:23:02 +0000576static void skip_spaces(char **s)
577{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000578 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000579
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000580 while (*p == ' ' || *p == '\t' ||
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000581 (*p == '\\' && *(p+1) == '\n' && (++p, ++t.lineno))) {
Mike Frysingerde2b9382005-09-27 03:18:00 +0000582 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000583 }
584 *s = p;
585}
586
Mike Frysinger10a11e22005-09-27 02:23:02 +0000587static char *nextword(char **s)
588{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000589 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000590
Denis Vlasenkof782f522007-01-01 23:51:30 +0000591 while (*(*s)++) /* */;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000592
593 return p;
594}
595
Mike Frysinger10a11e22005-09-27 02:23:02 +0000596static char nextchar(char **s)
597{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000598 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000599
600 c = *((*s)++);
601 pps = *s;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000602 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000603 if (c == '\\' && *s == pps) c = *((*s)++);
604 return c;
605}
606
Rob Landley88621d72006-08-29 19:41:06 +0000607static int ATTRIBUTE_ALWAYS_INLINE isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000608{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000609 return (isalnum(c) || c == '_');
610}
611
Mike Frysinger10a11e22005-09-27 02:23:02 +0000612static FILE *afopen(const char *path, const char *mode)
613{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000614 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000615}
616
617/* -------- working with variables (set/get/copy/etc) -------- */
618
Mike Frysinger10a11e22005-09-27 02:23:02 +0000619static xhash *iamarray(var *v)
620{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000621 var *a = v;
622
623 while (a->type & VF_CHILD)
624 a = a->x.parent;
625
626 if (! (a->type & VF_ARRAY)) {
627 a->type |= VF_ARRAY;
628 a->x.array = hash_init();
629 }
630 return a->x.array;
631}
632
Mike Frysinger10a11e22005-09-27 02:23:02 +0000633static void clear_array(xhash *array)
634{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000635 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000636 hash_item *hi, *thi;
637
638 for (i=0; i<array->csize; i++) {
639 hi = array->items[i];
640 while (hi) {
641 thi = hi;
642 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000643 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000644 free(thi);
645 }
646 array->items[i] = NULL;
647 }
648 array->glen = array->nel = 0;
649}
650
651/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000652static var *clrvar(var *v)
653{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000654 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000655 free(v->string);
656
657 v->type &= VF_DONTTOUCH;
658 v->type |= VF_DIRTY;
659 v->string = NULL;
660 return v;
661}
662
663/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000664static var *setvar_p(var *v, char *value)
665{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000666 clrvar(v);
667 v->string = value;
668 handle_special(v);
669
670 return v;
671}
672
673/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000674static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000675{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000676 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000677}
678
679/* same as setvar_s but set USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000680static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000681{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000682 setvar_s(v, value);
683 v->type |= VF_USER;
684 return v;
685}
686
687/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000688static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000689{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000690 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000691 static char sidx[12];
692
693 sprintf(sidx, "%d", idx);
694 v = findvar(iamarray(a), sidx);
695 setvar_u(v, s);
696}
697
698/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000699static var *setvar_i(var *v, double value)
700{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000701 clrvar(v);
702 v->type |= VF_NUMBER;
703 v->number = value;
704 handle_special(v);
705 return v;
706}
707
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000708static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000709{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000710 /* if v is numeric and has no cached string, convert it to string */
711 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
712 fmt_num(buf, MAXVARFMT, getvar_s(V[CONVFMT]), v->number, TRUE);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000713 v->string = xstrdup(buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000714 v->type |= VF_CACHED;
715 }
716 return (v->string == NULL) ? "" : v->string;
717}
718
Mike Frysinger10a11e22005-09-27 02:23:02 +0000719static double getvar_i(var *v)
720{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000721 char *s;
722
723 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
724 v->number = 0;
725 s = v->string;
726 if (s && *s) {
727 v->number = strtod(s, &s);
728 if (v->type & VF_USER) {
729 skip_spaces(&s);
730 if (*s != '\0')
731 v->type &= ~VF_USER;
732 }
733 } else {
734 v->type &= ~VF_USER;
735 }
736 v->type |= VF_CACHED;
737 }
738 return v->number;
739}
740
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000741static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000742{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000743 if (dest != src) {
744 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000745 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000746 dest->number = src->number;
747 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000748 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000749 }
750 handle_special(dest);
751 return dest;
752}
753
Mike Frysinger10a11e22005-09-27 02:23:02 +0000754static var *incvar(var *v)
755{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000756 return setvar_i(v, getvar_i(v)+1.);
757}
758
759/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000760static int is_numeric(var *v)
761{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000762 getvar_i(v);
763 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
764}
765
766/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000767static int istrue(var *v)
768{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000769 if (is_numeric(v))
770 return (v->number == 0) ? 0 : 1;
771 else
772 return (v->string && *(v->string)) ? 1 : 0;
773}
774
Eric Andersenaff114c2004-04-14 17:51:38 +0000775/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000776static var *nvalloc(int n)
777{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000778 nvblock *pb = NULL;
779 var *v, *r;
780 int size;
781
782 while (cb) {
783 pb = cb;
784 if ((cb->pos - cb->nv) + n <= cb->size) break;
785 cb = cb->next;
786 }
787
788 if (! cb) {
789 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkob95636c2006-12-19 23:36:04 +0000790 cb = xmalloc(sizeof(nvblock) + size * sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000791 cb->size = size;
792 cb->pos = cb->nv;
793 cb->prev = pb;
794 cb->next = NULL;
795 if (pb) pb->next = cb;
796 }
797
798 v = r = cb->pos;
799 cb->pos += n;
800
801 while (v < cb->pos) {
802 v->type = 0;
803 v->string = NULL;
804 v++;
805 }
806
807 return r;
808}
809
Mike Frysinger10a11e22005-09-27 02:23:02 +0000810static void nvfree(var *v)
811{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000812 var *p;
813
814 if (v < cb->nv || v >= cb->pos)
815 runtime_error(EMSG_INTERNAL_ERROR);
816
817 for (p=v; p<cb->pos; p++) {
818 if ((p->type & (VF_ARRAY|VF_CHILD)) == VF_ARRAY) {
819 clear_array(iamarray(p));
820 free(p->x.array->items);
821 free(p->x.array);
822 }
823 if (p->type & VF_WALK)
824 free(p->x.walker);
825
826 clrvar(p);
827 }
828
829 cb->pos = v;
830 while (cb->prev && cb->pos == cb->nv) {
831 cb = cb->prev;
832 }
833}
834
835/* ------- awk program text parsing ------- */
836
837/* Parse next token pointed by global pos, place results into global t.
838 * If token isn't expected, give away. Return token class
839 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000840static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000841{
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000842 static int concat_inserted;
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000843 static uint32_t save_tclass, save_info;
844 static uint32_t ltclass = TC_OPTERM;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000845
Denis Vlasenkof782f522007-01-01 23:51:30 +0000846 char *p, *pp, *s;
847 const char *tl;
848 uint32_t tc;
849 const uint32_t *ti;
850 int l;
851
Glenn L McGrath545106f2002-11-11 06:21:00 +0000852 if (t.rollback) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000853 t.rollback = FALSE;
854
855 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000856 concat_inserted = FALSE;
857 t.tclass = save_tclass;
858 t.info = save_info;
859
860 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000861 p = pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000862 readnext:
Glenn L McGrath545106f2002-11-11 06:21:00 +0000863 skip_spaces(&p);
864 lineno = t.lineno;
865 if (*p == '#')
866 while (*p != '\n' && *p != '\0') p++;
867
868 if (*p == '\n')
869 t.lineno++;
870
871 if (*p == '\0') {
872 tc = TC_EOF;
873
874 } else if (*p == '\"') {
875 /* it's a string */
876 t.string = s = ++p;
877 while (*p != '\"') {
878 if (*p == '\0' || *p == '\n')
879 syntax_error(EMSG_UNEXP_EOS);
880 *(s++) = nextchar(&p);
881 }
882 p++;
883 *s = '\0';
884 tc = TC_STRING;
885
886 } else if ((expected & TC_REGEXP) && *p == '/') {
887 /* it's regexp */
888 t.string = s = ++p;
889 while (*p != '/') {
890 if (*p == '\0' || *p == '\n')
891 syntax_error(EMSG_UNEXP_EOS);
892 if ((*s++ = *p++) == '\\') {
893 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000894 *(s-1) = bb_process_escape_sequence((const char **)&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000895 if (*pp == '\\') *s++ = '\\';
896 if (p == pp) *s++ = *p++;
897 }
898 }
899 p++;
900 *s = '\0';
901 tc = TC_REGEXP;
902
903 } else if (*p == '.' || isdigit(*p)) {
904 /* it's a number */
905 t.number = strtod(p, &p);
906 if (*p == '.')
907 syntax_error(EMSG_UNEXP_TOKEN);
908 tc = TC_NUMBER;
909
910 } else {
911 /* search for something known */
912 tl = tokenlist;
913 tc = 0x00000001;
914 ti = tokeninfo;
915 while (*tl) {
916 l = *(tl++);
917 if (l == NTCC) {
918 tc <<= 1;
919 continue;
920 }
921 /* if token class is expected, token
922 * matches and it's not a longer word,
923 * then this is what we are looking for
924 */
925 if ((tc & (expected | TC_WORD | TC_NEWLINE)) &&
926 *tl == *p && strncmp(p, tl, l) == 0 &&
927 !((tc & TC_WORD) && isalnum_(*(p + l)))) {
928 t.info = *ti;
929 p += l;
930 break;
931 }
932 ti++;
933 tl += l;
934 }
935
Denis Vlasenkof782f522007-01-01 23:51:30 +0000936 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000937 /* it's a name (var/array/function),
938 * otherwise it's something wrong
939 */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000940 if (!isalnum_(*p))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000941 syntax_error(EMSG_UNEXP_TOKEN);
942
943 t.string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000944 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000945 *(p-1) = *p;
946 }
947 *(p-1) = '\0';
948 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +0000949 /* also consume whitespace between functionname and bracket */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000950 if (!(expected & TC_VARIABLE)) skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000951 if (*p == '(') {
952 tc = TC_FUNCTION;
953 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000954 if (*p == '[') {
955 p++;
956 tc = TC_ARRAY;
957 }
958 }
959 }
960 }
961 pos = p;
962
963 /* skipping newlines in some cases */
964 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
965 goto readnext;
966
967 /* insert concatenation operator when needed */
968 if ((ltclass&TC_CONCAT1) && (tc&TC_CONCAT2) && (expected&TC_BINOP)) {
969 concat_inserted = TRUE;
970 save_tclass = tc;
971 save_info = t.info;
972 tc = TC_BINOP;
973 t.info = OC_CONCAT | SS | P(35);
974 }
975
976 t.tclass = tc;
977 }
978 ltclass = t.tclass;
979
980 /* Are we ready for this? */
981 if (! (ltclass & expected))
982 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
983 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
984
985 return ltclass;
986}
987
988static void rollback_token(void) { t.rollback = TRUE; }
989
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000990static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000991{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000992 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000993
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000994 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000995 n->info = info;
996 n->lineno = lineno;
997 return n;
998}
999
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001000static node *mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001001{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001002 n->info = OC_REGEXP;
1003 n->l.re = re;
1004 n->r.ire = re + 1;
1005 xregcomp(re, s, REG_EXTENDED);
1006 xregcomp(re+1, s, REG_EXTENDED | REG_ICASE);
1007
1008 return n;
1009}
1010
Mike Frysinger10a11e22005-09-27 02:23:02 +00001011static node *condition(void)
1012{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001013 next_token(TC_SEQSTART);
1014 return parse_expr(TC_SEQTERM);
1015}
1016
1017/* parse expression terminated by given argument, return ptr
1018 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001019static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001020{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001021 node sn;
1022 node *cn = &sn;
1023 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001024 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001025 var *v;
1026
1027 sn.info = PRIMASK;
1028 sn.r.n = glptr = NULL;
1029 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1030
1031 while (! ((tc = next_token(xtc)) & iexp)) {
1032 if (glptr && (t.info == (OC_COMPARE|VV|P(39)|2))) {
1033 /* input redirection (<) attached to glptr node */
1034 cn = glptr->l.n = new_node(OC_CONCAT|SS|P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001035 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001036 xtc = TC_OPERAND | TC_UOPPRE;
1037 glptr = NULL;
1038
1039 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1040 /* for binary and postfix-unary operators, jump back over
1041 * previous operators with higher priority */
1042 vn = cn;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001043 while ( ((t.info & PRIMASK) > (vn->a.n->info & PRIMASK2)) ||
Glenn L McGrath545106f2002-11-11 06:21:00 +00001044 ((t.info == vn->info) && ((t.info & OPCLSMASK) == OC_COLON)) )
1045 vn = vn->a.n;
1046 if ((t.info & OPCLSMASK) == OC_TERNARY)
1047 t.info += P(6);
1048 cn = vn->a.n->r.n = new_node(t.info);
1049 cn->a.n = vn->a.n;
1050 if (tc & TC_BINOP) {
1051 cn->l.n = vn;
1052 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1053 if ((t.info & OPCLSMASK) == OC_PGETLINE) {
1054 /* it's a pipe */
1055 next_token(TC_GETLINE);
1056 /* give maximum priority to this pipe */
1057 cn->info &= ~PRIMASK;
1058 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1059 }
1060 } else {
1061 cn->r.n = vn;
1062 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1063 }
1064 vn->a.n = cn;
1065
1066 } else {
1067 /* for operands and prefix-unary operators, attach them
1068 * to last node */
1069 vn = cn;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001070 cn = vn->r.n = new_node(t.info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001071 cn->a.n = vn;
1072 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1073 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001074 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001075 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001076 * only simple tclasses should be used! */
1077 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001078 case TC_VARIABLE:
1079 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001080 cn->info = OC_VAR;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001081 if ((v = hash_search(ahash, t.string)) != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001082 cn->info = OC_FNARG;
1083 cn->l.i = v->x.aidx;
1084 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00001085 cn->l.v = newvar(t.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001086 }
1087 if (tc & TC_ARRAY) {
1088 cn->info |= xS;
1089 cn->r.n = parse_expr(TC_ARRTERM);
1090 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001091 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001092
Denis Vlasenkof782f522007-01-01 23:51:30 +00001093 case TC_NUMBER:
1094 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001095 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001096 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001097 if (tc & TC_NUMBER)
1098 setvar_i(v, t.number);
1099 else
1100 setvar_s(v, t.string);
1101 break;
1102
Denis Vlasenkof782f522007-01-01 23:51:30 +00001103 case TC_REGEXP:
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001104 mk_re_node(t.string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001105 break;
1106
Denis Vlasenkof782f522007-01-01 23:51:30 +00001107 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001108 cn->info = OC_FUNC;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001109 cn->r.f = newfunc(t.string);
1110 cn->l.n = condition();
1111 break;
1112
Denis Vlasenkof782f522007-01-01 23:51:30 +00001113 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001114 cn = vn->r.n = parse_expr(TC_SEQTERM);
1115 cn->a.n = vn;
1116 break;
1117
Denis Vlasenkof782f522007-01-01 23:51:30 +00001118 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001119 glptr = cn;
1120 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1121 break;
1122
Denis Vlasenkof782f522007-01-01 23:51:30 +00001123 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001124 cn->l.n = condition();
1125 break;
1126 }
1127 }
1128 }
1129 }
1130 return sn.r.n;
1131}
1132
1133/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001134static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001135{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001136 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001137
1138 if (! seq->first)
1139 seq->first = seq->last = new_node(0);
1140
1141 if (seq->programname != programname) {
1142 seq->programname = programname;
1143 n = chain_node(OC_NEWSOURCE);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001144 n->l.s = xstrdup(programname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001145 }
1146
1147 n = seq->last;
1148 n->info = info;
1149 seq->last = n->a.n = new_node(OC_DONE);
1150
1151 return n;
1152}
1153
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001154static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001155{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001156 node *n;
1157
1158 n = chain_node(info);
1159 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1160 if (t.tclass & TC_GRPTERM)
1161 rollback_token();
1162}
1163
Mike Frysinger10a11e22005-09-27 02:23:02 +00001164static node *chain_loop(node *nn)
1165{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001166 node *n, *n2, *save_brk, *save_cont;
1167
1168 save_brk = break_ptr;
1169 save_cont = continue_ptr;
1170
1171 n = chain_node(OC_BR | Vx);
1172 continue_ptr = new_node(OC_EXEC);
1173 break_ptr = new_node(OC_EXEC);
1174 chain_group();
1175 n2 = chain_node(OC_EXEC | Vx);
1176 n2->l.n = nn;
1177 n2->a.n = n;
1178 continue_ptr->a.n = n2;
1179 break_ptr->a.n = n->r.n = seq->last;
1180
1181 continue_ptr = save_cont;
1182 break_ptr = save_brk;
1183
1184 return n;
1185}
1186
1187/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001188static void chain_group(void)
1189{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001190 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001191 node *n, *n2, *n3;
1192
1193 do {
1194 c = next_token(TC_GRPSEQ);
1195 } while (c & TC_NEWLINE);
1196
1197 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001198 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Mike Frysingerde2b9382005-09-27 03:18:00 +00001199 if (t.tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001200 rollback_token();
1201 chain_group();
1202 }
1203 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1204 rollback_token();
1205 chain_expr(OC_EXEC | Vx);
1206 } else { /* TC_STATEMNT */
1207 switch (t.info & OPCLSMASK) {
1208 case ST_IF:
1209 n = chain_node(OC_BR | Vx);
1210 n->l.n = condition();
1211 chain_group();
1212 n2 = chain_node(OC_EXEC);
1213 n->r.n = seq->last;
1214 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE)==TC_ELSE) {
1215 chain_group();
1216 n2->a.n = seq->last;
1217 } else {
1218 rollback_token();
1219 }
1220 break;
1221
1222 case ST_WHILE:
1223 n2 = condition();
1224 n = chain_loop(NULL);
1225 n->l.n = n2;
1226 break;
1227
1228 case ST_DO:
1229 n2 = chain_node(OC_EXEC);
1230 n = chain_loop(NULL);
1231 n2->a.n = n->a.n;
1232 next_token(TC_WHILE);
1233 n->l.n = condition();
1234 break;
1235
1236 case ST_FOR:
1237 next_token(TC_SEQSTART);
1238 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001239 if (t.tclass & TC_SEQTERM) { /* for-in */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001240 if ((n2->info & OPCLSMASK) != OC_IN)
1241 syntax_error(EMSG_UNEXP_TOKEN);
1242 n = chain_node(OC_WALKINIT | VV);
1243 n->l.n = n2->l.n;
1244 n->r.n = n2->r.n;
1245 n = chain_loop(NULL);
1246 n->info = OC_WALKNEXT | Vx;
1247 n->l.n = n2->l.n;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001248 } else { /* for (;;) */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001249 n = chain_node(OC_EXEC | Vx);
1250 n->l.n = n2;
1251 n2 = parse_expr(TC_SEMICOL);
1252 n3 = parse_expr(TC_SEQTERM);
1253 n = chain_loop(n3);
1254 n->l.n = n2;
1255 if (! n2)
1256 n->info = OC_EXEC;
1257 }
1258 break;
1259
1260 case OC_PRINT:
1261 case OC_PRINTF:
1262 n = chain_node(t.info);
1263 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
1264 if (t.tclass & TC_OUTRDR) {
1265 n->info |= t.info;
1266 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1267 }
1268 if (t.tclass & TC_GRPTERM)
1269 rollback_token();
1270 break;
1271
1272 case OC_BREAK:
1273 n = chain_node(OC_EXEC);
1274 n->a.n = break_ptr;
1275 break;
1276
1277 case OC_CONTINUE:
1278 n = chain_node(OC_EXEC);
1279 n->a.n = continue_ptr;
1280 break;
1281
1282 /* delete, next, nextfile, return, exit */
1283 default:
1284 chain_expr(t.info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001285 }
1286 }
1287}
1288
Mike Frysinger10a11e22005-09-27 02:23:02 +00001289static void parse_program(char *p)
1290{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001291 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001292 node *cn;
1293 func *f;
1294 var *v;
1295
1296 pos = p;
1297 t.lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001298 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Glenn L McGrath545106f2002-11-11 06:21:00 +00001299 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
1300
1301 if (tclass & TC_OPTERM)
1302 continue;
1303
1304 seq = &mainseq;
1305 if (tclass & TC_BEGIN) {
1306 seq = &beginseq;
1307 chain_group();
1308
1309 } else if (tclass & TC_END) {
1310 seq = &endseq;
1311 chain_group();
1312
1313 } else if (tclass & TC_FUNCDECL) {
1314 next_token(TC_FUNCTION);
1315 pos++;
1316 f = newfunc(t.string);
1317 f->body.first = NULL;
1318 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001319 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001320 v = findvar(ahash, t.string);
1321 v->x.aidx = (f->nargs)++;
1322
1323 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1324 break;
1325 }
1326 seq = &(f->body);
1327 chain_group();
1328 clear_array(ahash);
1329
1330 } else if (tclass & TC_OPSEQ) {
1331 rollback_token();
1332 cn = chain_node(OC_TEST);
1333 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
1334 if (t.tclass & TC_GRPSTART) {
1335 rollback_token();
1336 chain_group();
1337 } else {
1338 chain_node(OC_PRINT);
1339 }
1340 cn->r.n = mainseq.last;
1341
1342 } else /* if (tclass & TC_GRPSTART) */ {
1343 rollback_token();
1344 chain_group();
1345 }
1346 }
1347}
1348
1349
1350/* -------- program execution part -------- */
1351
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001352static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001353{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001354 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001355 node *n;
1356
1357 re = &spl->re[0];
1358 ire = &spl->re[1];
1359 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001360 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001361 regfree(re);
1362 regfree(ire);
1363 }
Rob Landleya3896512006-05-07 20:20:34 +00001364 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001365 mk_re_node(s, n, re);
1366 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001367 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001368 }
1369
1370 return n;
1371}
1372
1373/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001374 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001375 * be later regfree'd manually
1376 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001377static regex_t *as_regex(node *op, regex_t *preg)
1378{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001379 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001380 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001381
1382 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1383 return icase ? op->r.ire : op->l.re;
1384 } else {
1385 v = nvalloc(1);
1386 s = getvar_s(evaluate(op, v));
1387 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1388 nvfree(v);
1389 return preg;
1390 }
1391}
1392
1393/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001394static void qrealloc(char **b, int n, int *size)
1395{
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001396 if (!*b || n >= *size)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001397 *b = xrealloc(*b, *size = n + (n>>1) + 80);
1398}
1399
1400/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001401static void fsrealloc(int size)
1402{
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001403 static int maxfields; /* = 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00001404 int i;
1405
1406 if (size >= maxfields) {
1407 i = maxfields;
1408 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001409 Fields = xrealloc(Fields, maxfields * sizeof(var));
1410 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001411 Fields[i].type = VF_SPECIAL;
1412 Fields[i].string = NULL;
1413 }
1414 }
1415
1416 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001417 for (i = size; i < nfields; i++) {
1418 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001419 }
1420 }
1421 nfields = size;
1422}
1423
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001424static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001425{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001426 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001427 char c[4];
1428 char *s1;
1429 regmatch_t pmatch[2];
1430
1431 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001432 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1433 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001434
1435 c[0] = c[1] = (char)spl->info;
1436 c[2] = c[3] = '\0';
1437 if (*getvar_s(V[RS]) == '\0') c[2] = '\n';
1438
1439 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1440 while (*s) {
1441 l = strcspn(s, c+2);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001442 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1443 && pmatch[0].rm_so <= l
1444 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001445 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) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001460 *s1++ = *s++;
1461 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001462 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))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001471 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001472 n++;
1473 }
1474 } else { /* space split */
1475 while (*s) {
Denis Vlasenkod18a3a22006-10-25 12:46:03 +00001476 s = skip_whitespace(s);
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001477 if (!*s) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001478 n++;
1479 while (*s && !isspace(*s))
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001480 *s1++ = *s++;
1481 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001482 }
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;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001517 char *b;
1518 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001519 int sl, l, len, i, bsize;
1520
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001521 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001522 return;
1523
1524 if (v == V[NF]) {
1525 n = (int)getvar_i(v);
1526 fsrealloc(n);
1527
1528 /* recalculate $0 */
1529 sep = getvar_s(V[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001530 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001531 b = NULL;
1532 len = 0;
1533 for (i=0; i<n; i++) {
1534 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001535 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001536 if (b) {
1537 memcpy(b+len, sep, sl);
1538 len += sl;
1539 }
1540 qrealloc(&b, len+l+sl, &bsize);
1541 memcpy(b+len, s, l);
1542 len += l;
1543 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001544 if (b)
1545 b[len] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001546 setvar_p(V[F0], b);
1547 is_f0_split = TRUE;
1548
1549 } else if (v == V[F0]) {
1550 is_f0_split = FALSE;
1551
1552 } else if (v == V[FS]) {
1553 mk_splitter(getvar_s(v), &fsplitter);
1554
1555 } else if (v == V[RS]) {
1556 mk_splitter(getvar_s(v), &rsplitter);
1557
1558 } else if (v == V[IGNORECASE]) {
1559 icase = istrue(v);
1560
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001561 } else { /* $n */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001562 n = getvar_i(V[NF]);
1563 setvar_i(V[NF], n > v-Fields ? n : v-Fields+1);
1564 /* right here v is invalid. Just to note... */
1565 }
1566}
1567
1568/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001569static node *nextarg(node **pn)
1570{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001571 node *n;
1572
1573 n = *pn;
1574 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1575 *pn = n->r.n;
1576 n = n->l.n;
1577 } else {
1578 *pn = NULL;
1579 }
1580 return n;
1581}
1582
Mike Frysinger10a11e22005-09-27 02:23:02 +00001583static void hashwalk_init(var *v, xhash *array)
1584{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001585 char **w;
1586 hash_item *hi;
1587 int i;
1588
1589 if (v->type & VF_WALK)
1590 free(v->x.walker);
1591
1592 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001593 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001594 *w = *(w+1) = (char *)(w + 2);
1595 for (i=0; i<array->csize; i++) {
1596 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001597 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001598 strcpy(*w, hi->name);
1599 nextword(w);
1600 hi = hi->next;
1601 }
1602 }
1603}
1604
Mike Frysinger10a11e22005-09-27 02:23:02 +00001605static int hashwalk_next(var *v)
1606{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001607 char **w;
1608
1609 w = v->x.walker;
1610 if (*(w+1) == *w)
1611 return FALSE;
1612
1613 setvar_s(v, nextword(w+1));
1614 return TRUE;
1615}
1616
1617/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001618static int ptest(node *pattern)
1619{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001620 static var v; /* static: to save stack space? */
1621
Glenn L McGrath545106f2002-11-11 06:21:00 +00001622 return istrue(evaluate(pattern, &v));
1623}
1624
1625/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001626static int awk_getline(rstream *rsm, var *v)
1627{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001628 char *b;
1629 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001630 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001631 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001632 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001633
1634 /* we're using our own buffer since we need access to accumulating
1635 * characters
1636 */
1637 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001638 m = rsm->buffer;
1639 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001640 p = rsm->pos;
1641 size = rsm->size;
1642 c = (char) rsplitter.n.info;
1643 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001644
1645 if (! m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001646 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001647 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001648 so = eo = p;
1649 r = 1;
1650 if (p > 0) {
1651 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1652 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
1653 b, 1, pmatch, 0) == 0) {
1654 so = pmatch[0].rm_so;
1655 eo = pmatch[0].rm_eo;
1656 if (b[eo] != '\0')
1657 break;
1658 }
1659 } else if (c != '\0') {
1660 s = strchr(b+pp, c);
Rob Landley46e351d2006-02-14 16:05:32 +00001661 if (! s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001662 if (s) {
1663 so = eo = s-b;
1664 eo++;
1665 break;
1666 }
1667 } else {
1668 while (b[rp] == '\n')
1669 rp++;
1670 s = strstr(b+rp, "\n\n");
1671 if (s) {
1672 so = eo = s-b;
1673 while (b[eo] == '\n') eo++;
1674 if (b[eo] != '\0')
1675 break;
1676 }
1677 }
1678 }
1679
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001680 if (a > 0) {
1681 memmove(m, (const void *)(m+a), p+1);
1682 b = m;
1683 a = 0;
1684 }
1685
1686 qrealloc(&m, a+p+128, &size);
1687 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001688 pp = p;
1689 p += safe_read(fd, b+p, size-p-1);
1690 if (p < pp) {
1691 p = 0;
1692 r = 0;
1693 setvar_i(V[ERRNO], errno);
1694 }
1695 b[p] = '\0';
1696
1697 } while (p > pp);
1698
1699 if (p == 0) {
1700 r--;
1701 } else {
1702 c = b[so]; b[so] = '\0';
1703 setvar_s(v, b+rp);
1704 v->type |= VF_USER;
1705 b[so] = c;
1706 c = b[eo]; b[eo] = '\0';
1707 setvar_s(V[RT], b+so);
1708 b[eo] = c;
1709 }
1710
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001711 rsm->buffer = m;
1712 rsm->adv = a + eo;
1713 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001714 rsm->size = size;
1715
1716 return r;
1717}
1718
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001719static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001720{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001721 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001722 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001723 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001724
1725 if (int_as_int && n == (int)n) {
1726 r = snprintf(b, size, "%d", (int)n);
1727 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001728 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001729 if (strchr("diouxX", c)) {
1730 r = snprintf(b, size, format, (int)n);
1731 } else if (strchr("eEfgG", c)) {
1732 r = snprintf(b, size, format, n);
1733 } else {
1734 runtime_error(EMSG_INV_FMT);
1735 }
1736 }
1737 return r;
1738}
1739
1740
1741/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001742static char *awk_printf(node *n)
1743{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001744 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001745 char *fmt, *s, *f;
1746 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001747 int i, j, incr, bsize;
1748 char c, c1;
1749 var *v, *arg;
1750
1751 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001752 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001753
1754 i = 0;
1755 while (*f) {
1756 s = f;
1757 while (*f && (*f != '%' || *(++f) == '%'))
1758 f++;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001759 while (*f && !isalpha(*f))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001760 f++;
1761
1762 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001763 qrealloc(&b, incr + i, &bsize);
1764 c = *f;
1765 if (c != '\0') f++;
1766 c1 = *f;
1767 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001768 arg = evaluate(nextarg(&n), v);
1769
1770 j = i;
1771 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001772 i += sprintf(b+i, s, is_numeric(arg) ?
1773 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001774
1775 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001776 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001777 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001778 i += sprintf(b+i, s, s1);
1779
1780 } else {
1781 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1782 }
1783 *f = c1;
1784
1785 /* if there was an error while sprintf, return value is negative */
1786 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001787 }
1788
Denis Vlasenkof782f522007-01-01 23:51:30 +00001789 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001790 free(fmt);
1791 nvfree(v);
1792 b[i] = '\0';
1793 return b;
1794}
1795
1796/* common substitution routine
1797 * replace (nm) substring of (src) that match (n) with (repl), store
1798 * result into (dest), return number of substitutions. If nm=0, replace
1799 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1800 * subexpression matching (\1-\9)
1801 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001802static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001803{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001804 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001805 const char *s;
1806 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001807 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1808 regmatch_t pmatch[10];
1809 regex_t sreg, *re;
1810
1811 re = as_regex(rn, &sreg);
1812 if (! src) src = V[F0];
1813 if (! dest) dest = V[F0];
1814
1815 i = di = 0;
1816 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001817 rl = strlen(repl);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001818 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0:REG_NOTBOL) == 0) {
1819 so = pmatch[0].rm_so;
1820 eo = pmatch[0].rm_eo;
1821
1822 qrealloc(&ds, di + eo + rl, &dssize);
1823 memcpy(ds + di, sp, eo);
1824 di += eo;
1825 if (++i >= nm) {
1826 /* replace */
1827 di -= (eo - so);
1828 nbs = 0;
1829 for (s = repl; *s; s++) {
1830 ds[di++] = c = *s;
1831 if (c == '\\') {
1832 nbs++;
1833 continue;
1834 }
1835 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1836 di -= ((nbs + 3) >> 1);
1837 j = 0;
1838 if (c != '&') {
1839 j = c - '0';
1840 nbs++;
1841 }
1842 if (nbs % 2) {
1843 ds[di++] = c;
1844 } else {
1845 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1846 qrealloc(&ds, di + rl + n, &dssize);
1847 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1848 di += n;
1849 }
1850 }
1851 nbs = 0;
1852 }
1853 }
1854
1855 sp += eo;
1856 if (i == nm) break;
1857 if (eo == so) {
1858 if (! (ds[di++] = *sp++)) break;
1859 }
1860 }
1861
1862 qrealloc(&ds, di + strlen(sp), &dssize);
1863 strcpy(ds + di, sp);
1864 setvar_p(dest, ds);
1865 if (re == &sreg) regfree(re);
1866 return i;
1867}
1868
Mike Frysinger10a11e22005-09-27 02:23:02 +00001869static var *exec_builtin(node *op, var *res)
1870{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001871 int (*to_xxx)(int);
1872 var *tv;
1873 node *an[4];
1874 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001875 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001876 regmatch_t pmatch[2];
1877 regex_t sreg, *re;
1878 static tsplitter tspl;
1879 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001880 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001881 int nargs;
1882 time_t tt;
1883 char *s, *s1;
1884 int i, l, ll, n;
1885
1886 tv = nvalloc(4);
1887 isr = info = op->info;
1888 op = op->l.n;
1889
1890 av[2] = av[3] = NULL;
1891 for (i=0 ; i<4 && op ; i++) {
1892 an[i] = nextarg(&op);
1893 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
1894 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
1895 isr >>= 1;
1896 }
1897
1898 nargs = i;
1899 if (nargs < (info >> 30))
1900 runtime_error(EMSG_TOO_FEW_ARGS);
1901
1902 switch (info & OPNMASK) {
1903
Denis Vlasenkof782f522007-01-01 23:51:30 +00001904 case B_a2:
1905#if ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +00001906 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
1907#else
1908 runtime_error(EMSG_NO_MATH);
1909#endif
1910 break;
1911
Denis Vlasenkof782f522007-01-01 23:51:30 +00001912 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001913 if (nargs > 2) {
1914 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
1915 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
1916 } else {
1917 spl = &fsplitter.n;
1918 }
1919
1920 n = awk_split(as[0], spl, &s);
1921 s1 = s;
1922 clear_array(iamarray(av[1]));
1923 for (i=1; i<=n; i++)
1924 setari_u(av[1], i, nextword(&s1));
1925 free(s);
1926 setvar_i(res, n);
1927 break;
1928
Denis Vlasenkof782f522007-01-01 23:51:30 +00001929 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00001930 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001931 i = getvar_i(av[1]) - 1;
1932 if (i>l) i=l; if (i<0) i=0;
1933 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
1934 if (n<0) n=0;
1935 s = xmalloc(n+1);
1936 strncpy(s, as[0]+i, n);
1937 s[n] = '\0';
1938 setvar_p(res, s);
1939 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00001940
Denis Vlasenkof782f522007-01-01 23:51:30 +00001941 case B_an:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001942 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
1943 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00001944
Denis Vlasenkof782f522007-01-01 23:51:30 +00001945 case B_co:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001946 setvar_i(res, ~(long)getvar_i(av[0]));
1947 break;
1948
Denis Vlasenkof782f522007-01-01 23:51:30 +00001949 case B_ls:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001950 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
1951 break;
1952
Denis Vlasenkof782f522007-01-01 23:51:30 +00001953 case B_or:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001954 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
1955 break;
1956
Denis Vlasenkof782f522007-01-01 23:51:30 +00001957 case B_rs:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001958 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
1959 break;
1960
Denis Vlasenkof782f522007-01-01 23:51:30 +00001961 case B_xo:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001962 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
1963 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001964
Denis Vlasenkof782f522007-01-01 23:51:30 +00001965 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001966 to_xxx = tolower;
1967 goto lo_cont;
1968
Denis Vlasenkof782f522007-01-01 23:51:30 +00001969 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001970 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001971 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00001972 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001973 while (*s1) {
1974 *s1 = (*to_xxx)(*s1);
1975 s1++;
1976 }
1977 setvar_p(res, s);
1978 break;
1979
Denis Vlasenkof782f522007-01-01 23:51:30 +00001980 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001981 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00001982 ll = strlen(as[1]);
1983 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001984 if (ll > 0 && l >= 0) {
1985 if (! icase) {
1986 s = strstr(as[0], as[1]);
1987 if (s) n = (s - as[0]) + 1;
1988 } else {
1989 /* this piece of code is terribly slow and
1990 * really should be rewritten
1991 */
1992 for (i=0; i<=l; i++) {
1993 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
1994 n = i+1;
1995 break;
1996 }
1997 }
1998 }
1999 }
2000 setvar_i(res, n);
2001 break;
2002
Denis Vlasenkof782f522007-01-01 23:51:30 +00002003 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002004 if (nargs > 1)
2005 tt = getvar_i(av[1]);
2006 else
2007 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002008 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
2009 i = strftime(buf, MAXVARFMT,
2010 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2011 localtime(&tt));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002012 buf[i] = '\0';
2013 setvar_s(res, buf);
2014 break;
2015
Denis Vlasenkof782f522007-01-01 23:51:30 +00002016 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002017 re = as_regex(an[1], &sreg);
2018 n = regexec(re, as[0], 1, pmatch, 0);
2019 if (n == 0) {
2020 pmatch[0].rm_so++;
2021 pmatch[0].rm_eo++;
2022 } else {
2023 pmatch[0].rm_so = 0;
2024 pmatch[0].rm_eo = -1;
2025 }
2026 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2027 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2028 setvar_i(res, pmatch[0].rm_so);
2029 if (re == &sreg) regfree(re);
2030 break;
2031
Denis Vlasenkof782f522007-01-01 23:51:30 +00002032 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002033 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2034 break;
2035
Denis Vlasenkof782f522007-01-01 23:51:30 +00002036 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002037 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2038 break;
2039
Denis Vlasenkof782f522007-01-01 23:51:30 +00002040 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002041 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2042 break;
2043 }
2044
2045 nvfree(tv);
2046 return res;
2047}
2048
2049/*
2050 * Evaluate node - the heart of the program. Supplied with subtree
2051 * and place where to store result. returns ptr to result.
2052 */
2053#define XC(n) ((n) >> 8)
2054
Mike Frysinger10a11e22005-09-27 02:23:02 +00002055static var *evaluate(node *op, var *res)
2056{
Mike Frysingerde2b9382005-09-27 03:18:00 +00002057 /* This procedure is recursive so we should count every byte */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002058 static var *fnargs = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002059 static unsigned seed = 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002060 static regex_t sreg;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002061
Glenn L McGrath545106f2002-11-11 06:21:00 +00002062 node *op1;
2063 var *v1;
2064 union {
2065 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002066 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002067 double d;
2068 int i;
2069 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002070 uint32_t opinfo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002071 short opn;
2072 union {
2073 char *s;
2074 rstream *rsm;
2075 FILE *F;
2076 var *v;
2077 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002078 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002079 } X;
2080
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002081 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002082 return setvar_s(res, NULL);
2083
2084 v1 = nvalloc(2);
2085
2086 while (op) {
2087
2088 opinfo = op->info;
2089 opn = (short)(opinfo & OPNMASK);
2090 lineno = op->lineno;
2091
Mike Frysingerde2b9382005-09-27 03:18:00 +00002092 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002093 op1 = op->l.n;
2094 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2095 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2096 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2097 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2098 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2099
2100 switch (XC(opinfo & OPCLSMASK)) {
2101
2102 /* -- iterative node type -- */
2103
2104 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002105 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002106 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2107 /* it's range pattern */
2108 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2109 op->info |= OF_CHECKED;
2110 if (ptest(op1->r.n))
2111 op->info &= ~OF_CHECKED;
2112
2113 op = op->a.n;
2114 } else {
2115 op = op->r.n;
2116 }
2117 } else {
2118 op = (ptest(op1)) ? op->a.n : op->r.n;
2119 }
2120 break;
2121
2122 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002123 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002124 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002125
2126 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002127 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002128 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002129 break;
2130
2131 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002132 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002133 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002134 break;
2135
2136 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002137 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002138 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2139 break;
2140
Denis Vlasenkof782f522007-01-01 23:51:30 +00002141 case XC( OC_PRINT ):
2142 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002143 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002144 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002145 X.rsm = newfile(R.s);
2146 if (! X.rsm->F) {
2147 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002148 X.rsm->F = popen(R.s, "w");
2149 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002150 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002151 X.rsm->is_pipe = 1;
2152 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002153 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002154 }
2155 }
2156 X.F = X.rsm->F;
2157 }
2158
2159 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002160 if (! op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002161 fputs(getvar_s(V[F0]), X.F);
2162 } else {
2163 while (op1) {
2164 L.v = evaluate(nextarg(&op1), v1);
2165 if (L.v->type & VF_NUMBER) {
2166 fmt_num(buf, MAXVARFMT, getvar_s(V[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002167 getvar_i(L.v), TRUE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002168 fputs(buf, X.F);
2169 } else {
2170 fputs(getvar_s(L.v), X.F);
2171 }
2172
2173 if (op1) fputs(getvar_s(V[OFS]), X.F);
2174 }
2175 }
2176 fputs(getvar_s(V[ORS]), X.F);
2177
2178 } else { /* OC_PRINTF */
2179 L.s = awk_printf(op1);
2180 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002181 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002182 }
2183 fflush(X.F);
2184 break;
2185
Denis Vlasenkof782f522007-01-01 23:51:30 +00002186 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002187 X.info = op1->info & OPCLSMASK;
2188 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002189 R.v = op1->l.v;
2190 } else if (X.info == OC_FNARG) {
2191 R.v = &fnargs[op1->l.i];
2192 } else {
2193 runtime_error(EMSG_NOT_ARRAY);
2194 }
2195
Mike Frysingerde2b9382005-09-27 03:18:00 +00002196 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002197 clrvar(L.v);
2198 L.s = getvar_s(evaluate(op1->r.n, v1));
2199 hash_remove(iamarray(R.v), L.s);
2200 } else {
2201 clear_array(iamarray(R.v));
2202 }
2203 break;
2204
Denis Vlasenkof782f522007-01-01 23:51:30 +00002205 case XC( OC_NEWSOURCE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002206 programname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002207 break;
2208
Denis Vlasenkof782f522007-01-01 23:51:30 +00002209 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002210 copyvar(res, L.v);
2211 break;
2212
Denis Vlasenkof782f522007-01-01 23:51:30 +00002213 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002214 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002215 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002216 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002217 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002218 clrvar(res);
2219 break;
2220
Denis Vlasenkof782f522007-01-01 23:51:30 +00002221 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002222 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002223
2224 /* -- recursive node type -- */
2225
Denis Vlasenkof782f522007-01-01 23:51:30 +00002226 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002227 L.v = op->l.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002228 if (L.v == V[NF])
2229 split_f0();
2230 goto v_cont;
2231
Denis Vlasenkof782f522007-01-01 23:51:30 +00002232 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002233 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002234 v_cont:
2235 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002236 break;
2237
Denis Vlasenkof782f522007-01-01 23:51:30 +00002238 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002239 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2240 break;
2241
Denis Vlasenkof782f522007-01-01 23:51:30 +00002242 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002243 op1 = op;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002244 L.s = getvar_s(V[F0]);
2245 goto re_cont;
2246
Denis Vlasenkof782f522007-01-01 23:51:30 +00002247 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002248 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002249 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002250 X.re = as_regex(op1, &sreg);
2251 R.i = regexec(X.re, L.s, 0, NULL, 0);
2252 if (X.re == &sreg) regfree(X.re);
2253 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2254 break;
2255
Denis Vlasenkof782f522007-01-01 23:51:30 +00002256 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002257 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002258 if (R.v == v1+1 && R.v->string) {
2259 res = setvar_p(L.v, R.v->string);
2260 R.v->string = NULL;
2261 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002262 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002263 }
2264 break;
2265
Denis Vlasenkof782f522007-01-01 23:51:30 +00002266 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002267 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002268 runtime_error(EMSG_POSSIBLE_ERROR);
2269 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2270 break;
2271
Denis Vlasenkof782f522007-01-01 23:51:30 +00002272 case XC( OC_FUNC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002273 if (! op->r.f->body.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002274 runtime_error(EMSG_UNDEF_FUNC);
2275
2276 X.v = R.v = nvalloc(op->r.f->nargs+1);
2277 while (op1) {
2278 L.v = evaluate(nextarg(&op1), v1);
2279 copyvar(R.v, L.v);
2280 R.v->type |= VF_CHILD;
2281 R.v->x.parent = L.v;
2282 if (++R.v - X.v >= op->r.f->nargs)
2283 break;
2284 }
2285
2286 R.v = fnargs;
2287 fnargs = X.v;
2288
2289 L.s = programname;
2290 res = evaluate(op->r.f->body.first, res);
2291 programname = L.s;
2292
2293 nvfree(fnargs);
2294 fnargs = R.v;
2295 break;
2296
Denis Vlasenkof782f522007-01-01 23:51:30 +00002297 case XC( OC_GETLINE ):
2298 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002299 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002300 X.rsm = newfile(L.s);
2301 if (! X.rsm->F) {
2302 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2303 X.rsm->F = popen(L.s, "r");
2304 X.rsm->is_pipe = TRUE;
2305 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002306 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002307 }
2308 }
2309 } else {
2310 if (! iF) iF = next_input_file();
2311 X.rsm = iF;
2312 }
2313
2314 if (! X.rsm->F) {
2315 setvar_i(V[ERRNO], errno);
2316 setvar_i(res, -1);
2317 break;
2318 }
2319
2320 if (! op->r.n)
2321 R.v = V[F0];
2322
2323 L.i = awk_getline(X.rsm, R.v);
2324 if (L.i > 0) {
2325 if (! op1) {
2326 incvar(V[FNR]);
2327 incvar(V[NR]);
2328 }
2329 }
2330 setvar_i(res, L.i);
2331 break;
2332
Mike Frysingerde2b9382005-09-27 03:18:00 +00002333 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002334 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002335 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002336
Denis Vlasenkof782f522007-01-01 23:51:30 +00002337 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002338 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002339 break;
2340
Denis Vlasenkof782f522007-01-01 23:51:30 +00002341 case F_rn:
2342 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002343 break;
2344
Denis Vlasenkof782f522007-01-01 23:51:30 +00002345#if ENABLE_FEATURE_AWK_MATH
2346 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002347 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002348 break;
2349
Denis Vlasenkof782f522007-01-01 23:51:30 +00002350 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002351 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002352 break;
2353
Denis Vlasenkof782f522007-01-01 23:51:30 +00002354 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002355 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002356 break;
2357
Denis Vlasenkof782f522007-01-01 23:51:30 +00002358 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002359 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002360 break;
2361
Denis Vlasenkof782f522007-01-01 23:51:30 +00002362 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002363 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002364 break;
2365#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002366 case F_co:
2367 case F_ex:
2368 case F_lg:
2369 case F_si:
2370 case F_sq:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002371 runtime_error(EMSG_NO_MATH);
2372 break;
2373#endif
2374
Denis Vlasenkof782f522007-01-01 23:51:30 +00002375 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002376 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002377 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002378 srand(seed);
2379 break;
2380
Denis Vlasenkof782f522007-01-01 23:51:30 +00002381 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002382 R.d = time(NULL);
2383 break;
2384
Denis Vlasenkof782f522007-01-01 23:51:30 +00002385 case F_le:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002386 if (! op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002387 L.s = getvar_s(V[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002388 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002389 break;
2390
Denis Vlasenkof782f522007-01-01 23:51:30 +00002391 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002392 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002393 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2394 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002395 break;
2396
Denis Vlasenkof782f522007-01-01 23:51:30 +00002397 case F_ff:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002398 if (! op1)
2399 fflush(stdout);
2400 else {
2401 if (L.s && *L.s) {
2402 X.rsm = newfile(L.s);
2403 fflush(X.rsm->F);
2404 } else {
2405 fflush(NULL);
2406 }
2407 }
2408 break;
2409
Denis Vlasenkof782f522007-01-01 23:51:30 +00002410 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002411 X.rsm = (rstream *)hash_search(fdhash, L.s);
2412 if (X.rsm) {
2413 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002414 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002415 hash_remove(fdhash, L.s);
2416 }
2417 if (R.i != 0)
2418 setvar_i(V[ERRNO], errno);
2419 R.d = (double)R.i;
2420 break;
2421 }
2422 setvar_i(res, R.d);
2423 break;
2424
Denis Vlasenkof782f522007-01-01 23:51:30 +00002425 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002426 res = exec_builtin(op, res);
2427 break;
2428
Denis Vlasenkof782f522007-01-01 23:51:30 +00002429 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002430 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002431 break;
2432
Denis Vlasenkof782f522007-01-01 23:51:30 +00002433 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002434 X.v = R.v;
2435 L.d = R.d = getvar_i(R.v);
2436 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002437 case 'P':
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 'p':
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 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002444 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002445 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002446 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002447 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002448 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002449 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002450 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002451 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002452 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002453 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002454 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002455 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002456 setvar_i(X.v, R.d);
2457 }
2458 setvar_i(res, L.d);
2459 break;
2460
Denis Vlasenkof782f522007-01-01 23:51:30 +00002461 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002462 R.i = (int)getvar_i(R.v);
2463 if (R.i == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002464 res = V[F0];
2465 } else {
2466 split_f0();
2467 if (R.i > nfields)
2468 fsrealloc(R.i);
2469
2470 res = &Fields[R.i-1];
2471 }
2472 break;
2473
2474 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002475 case XC( OC_CONCAT ):
2476 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002477 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002478 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002479 strcpy(X.s, L.s);
2480 if ((opinfo & OPCLSMASK) == OC_COMMA) {
2481 L.s = getvar_s(V[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002482 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002483 strcat(X.s, L.s);
2484 }
2485 strcat(X.s, R.s);
2486 setvar_p(res, X.s);
2487 break;
2488
Denis Vlasenkof782f522007-01-01 23:51:30 +00002489 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002490 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2491 break;
2492
Denis Vlasenkof782f522007-01-01 23:51:30 +00002493 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002494 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2495 break;
2496
Denis Vlasenkof782f522007-01-01 23:51:30 +00002497 case XC( OC_BINARY ):
2498 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002499 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002500 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002501 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002502 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002503 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002504 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002505 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002506 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002507 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002508 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002509 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002510 case '/':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002511 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2512 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002513 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002514 case '&':
2515#if ENABLE_FEATURE_AWK_MATH
Mike Frysingerde2b9382005-09-27 03:18:00 +00002516 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002517#else
2518 runtime_error(EMSG_NO_MATH);
2519#endif
2520 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002521 case '%':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002522 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2523 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002524 break;
2525 }
2526 res = setvar_i(((opinfo&OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
2527 break;
2528
Denis Vlasenkof782f522007-01-01 23:51:30 +00002529 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002530 if (is_numeric(L.v) && is_numeric(R.v)) {
2531 L.d = getvar_i(L.v) - getvar_i(R.v);
2532 } else {
2533 L.s = getvar_s(L.v);
2534 R.s = getvar_s(R.v);
2535 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2536 }
2537 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002538 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002539 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002540 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002541 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002542 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002543 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002544 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002545 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002546 break;
2547 }
2548 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2549 break;
2550
Denis Vlasenkof782f522007-01-01 23:51:30 +00002551 default:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002552 runtime_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002553 }
2554 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2555 op = op->a.n;
2556 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2557 break;
2558 if (nextrec)
2559 break;
2560 }
2561 nvfree(v1);
2562 return res;
2563}
2564
2565
2566/* -------- main & co. -------- */
2567
Mike Frysinger10a11e22005-09-27 02:23:02 +00002568static int awk_exit(int r)
2569{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002570 var tv;
2571 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002572 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002573
Denis Vlasenkof782f522007-01-01 23:51:30 +00002574 zero_out_var(&tv);
2575
2576 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002577 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002578 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002579 evaluate(endseq.first, &tv);
2580 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002581
2582 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002583 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002584 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002585 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002586 if (hi->data.rs.F && hi->data.rs.is_pipe)
2587 pclose(hi->data.rs.F);
2588 hi = hi->next;
2589 }
2590 }
2591
2592 exit(r);
2593}
2594
2595/* if expr looks like "var=value", perform assignment and return 1,
2596 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002597static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002598{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002599 char *exprc, *s, *s0, *s1;
2600
Rob Landleyd921b2e2006-08-03 15:41:12 +00002601 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002602 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2603 free(exprc);
2604 return FALSE;
2605 }
2606
2607 *(s++) = '\0';
2608 s0 = s1 = s;
2609 while (*s)
2610 *(s1++) = nextchar(&s);
2611
2612 *s1 = '\0';
2613 setvar_u(newvar(exprc), s0);
2614 free(exprc);
2615 return TRUE;
2616}
2617
2618/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002619static rstream *next_input_file(void)
2620{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002621 static rstream rsm;
2622 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002623 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002624 static int files_happen = FALSE;
2625
2626 if (rsm.F) fclose(rsm.F);
2627 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002628 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002629
2630 do {
2631 if (getvar_i(V[ARGIND])+1 >= getvar_i(V[ARGC])) {
2632 if (files_happen)
2633 return NULL;
2634 fname = "-";
2635 F = stdin;
2636 } else {
2637 ind = getvar_s(incvar(V[ARGIND]));
2638 fname = getvar_s(findvar(iamarray(V[ARGV]), ind));
2639 if (fname && *fname && !is_assignment(fname))
2640 F = afopen(fname, "r");
2641 }
2642 } while (!F);
2643
2644 files_happen = TRUE;
2645 setvar_s(V[FILENAME], fname);
2646 rsm.F = F;
2647 return &rsm;
2648}
2649
Denis Vlasenko06af2162007-02-03 17:28:39 +00002650int awk_main(int argc, char **argv);
Rob Landleydfba7412006-03-06 20:47:33 +00002651int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002652{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002653 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002654 char *opt_F, *opt_W;
2655 llist_t *opt_v = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002656 int i, j, flen;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002657 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002658 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002659 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002660 char *vnames = (char *)vNames; /* cheat */
2661 char *vvalues = (char *)vValues;
2662
Denis Vlasenko150f4022007-01-13 21:06:21 +00002663 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002664 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2665 if (ENABLE_LOCALE_SUPPORT)
2666 setlocale(LC_NUMERIC, "C");
2667
Denis Vlasenkof782f522007-01-01 23:51:30 +00002668 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002669
2670 /* allocate global buffer */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002671 buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002672
2673 vhash = hash_init();
2674 ahash = hash_init();
2675 fdhash = hash_init();
2676 fnhash = hash_init();
2677
2678 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002679 for (i = 0; *vnames; i++) {
2680 V[i] = v = newvar(nextword(&vnames));
2681 if (*vvalues != '\377')
2682 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002683 else
2684 setvar_i(v, 0);
2685
Denis Vlasenkof782f522007-01-01 23:51:30 +00002686 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002687 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002688 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002689 }
2690 }
2691
2692 handle_special(V[FS]);
2693 handle_special(V[RS]);
2694
Denis Vlasenkof782f522007-01-01 23:51:30 +00002695 newfile("/dev/stdin")->F = stdin;
2696 newfile("/dev/stdout")->F = stdout;
2697 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002698
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002699 /* Huh, people report that sometimes environ is NULL. Oh well. */
2700 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002701 char *s = xstrdup(*envp);
2702 char *s1 = strchr(s, '=');
2703 if (s1) {
2704 *s1++ = '\0';
2705 setvar_u(findvar(iamarray(V[ENVIRON]), s), s1);
Eric Andersen67776be2004-07-30 23:52:08 +00002706 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002707 free(s);
2708 }
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002709 opt_complementary = "v::";
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002710 opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &programname, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002711 argv += optind;
2712 argc -= optind;
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002713 if (opt & 0x1) setvar_s(V[FS], opt_F); // -F
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002714 while (opt_v) { /* -v */
2715 if (!is_assignment(llist_pop(&opt_v)))
2716 bb_show_usage();
2717 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002718 if (opt & 0x4) { // -f
Denis Vlasenkof782f522007-01-01 23:51:30 +00002719 char *s = s; /* die, gcc, die */
2720 FILE *from_file = afopen(programname, "r");
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002721 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002722 if (fseek(from_file, 0, SEEK_END) == 0) {
2723 flen = ftell(from_file);
2724 s = xmalloc(flen + 4);
2725 fseek(from_file, 0, SEEK_SET);
2726 i = 1 + fread(s + 1, 1, flen, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002727 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002728 for (i = j = 1; j > 0; i += j) {
2729 s = xrealloc(s, i + 4096);
2730 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002731 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002732 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002733 s[i] = '\0';
Denis Vlasenkof782f522007-01-01 23:51:30 +00002734 fclose(from_file);
2735 parse_program(s + 1);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002736 free(s);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002737 } else { // no -f: take program from 1st parameter
2738 if (!argc)
2739 bb_show_usage();
2740 programname = "cmd. line";
2741 parse_program(*argv++);
2742 argc--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002743 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002744 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002745 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002746
Glenn L McGrath545106f2002-11-11 06:21:00 +00002747 /* fill in ARGV array */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002748 setvar_i(V[ARGC], argc + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002749 setari_u(V[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002750 i = 0;
2751 while (*argv)
2752 setari_u(V[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002753
2754 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002755 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002756 awk_exit(EXIT_SUCCESS);
2757
2758 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002759 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002760
2761 /* passing through input files */
2762 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002763 nextfile = FALSE;
2764 setvar_i(V[FNR], 0);
2765
Denis Vlasenkof782f522007-01-01 23:51:30 +00002766 while ((i = awk_getline(iF, V[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002767 nextrec = FALSE;
2768 incvar(V[NR]);
2769 incvar(V[FNR]);
2770 evaluate(mainseq.first, &tv);
2771
2772 if (nextfile)
2773 break;
2774 }
2775
Denis Vlasenkof782f522007-01-01 23:51:30 +00002776 if (i < 0)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002777 runtime_error(strerror(errno));
2778
2779 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002780 }
2781
Glenn L McGrath545106f2002-11-11 06:21:00 +00002782 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002783 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002784}