blob: 1bdb9b924e724e665a5b0fb10a6ab48c61d5fff2 [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 == '|') {
2148 if((X.rsm->F = popen(R.s, "w")) == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002149 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002150 X.rsm->is_pipe = 1;
2151 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002152 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002153 }
2154 }
2155 X.F = X.rsm->F;
2156 }
2157
2158 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002159 if (! op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002160 fputs(getvar_s(V[F0]), X.F);
2161 } else {
2162 while (op1) {
2163 L.v = evaluate(nextarg(&op1), v1);
2164 if (L.v->type & VF_NUMBER) {
2165 fmt_num(buf, MAXVARFMT, getvar_s(V[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002166 getvar_i(L.v), TRUE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002167 fputs(buf, X.F);
2168 } else {
2169 fputs(getvar_s(L.v), X.F);
2170 }
2171
2172 if (op1) fputs(getvar_s(V[OFS]), X.F);
2173 }
2174 }
2175 fputs(getvar_s(V[ORS]), X.F);
2176
2177 } else { /* OC_PRINTF */
2178 L.s = awk_printf(op1);
2179 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002180 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002181 }
2182 fflush(X.F);
2183 break;
2184
Denis Vlasenkof782f522007-01-01 23:51:30 +00002185 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002186 X.info = op1->info & OPCLSMASK;
2187 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002188 R.v = op1->l.v;
2189 } else if (X.info == OC_FNARG) {
2190 R.v = &fnargs[op1->l.i];
2191 } else {
2192 runtime_error(EMSG_NOT_ARRAY);
2193 }
2194
Mike Frysingerde2b9382005-09-27 03:18:00 +00002195 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002196 clrvar(L.v);
2197 L.s = getvar_s(evaluate(op1->r.n, v1));
2198 hash_remove(iamarray(R.v), L.s);
2199 } else {
2200 clear_array(iamarray(R.v));
2201 }
2202 break;
2203
Denis Vlasenkof782f522007-01-01 23:51:30 +00002204 case XC( OC_NEWSOURCE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002205 programname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002206 break;
2207
Denis Vlasenkof782f522007-01-01 23:51:30 +00002208 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002209 copyvar(res, L.v);
2210 break;
2211
Denis Vlasenkof782f522007-01-01 23:51:30 +00002212 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002213 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002214 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002215 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002216 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002217 clrvar(res);
2218 break;
2219
Denis Vlasenkof782f522007-01-01 23:51:30 +00002220 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002221 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002222
2223 /* -- recursive node type -- */
2224
Denis Vlasenkof782f522007-01-01 23:51:30 +00002225 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002226 L.v = op->l.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002227 if (L.v == V[NF])
2228 split_f0();
2229 goto v_cont;
2230
Denis Vlasenkof782f522007-01-01 23:51:30 +00002231 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002232 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002233 v_cont:
2234 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002235 break;
2236
Denis Vlasenkof782f522007-01-01 23:51:30 +00002237 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002238 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2239 break;
2240
Denis Vlasenkof782f522007-01-01 23:51:30 +00002241 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002242 op1 = op;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002243 L.s = getvar_s(V[F0]);
2244 goto re_cont;
2245
Denis Vlasenkof782f522007-01-01 23:51:30 +00002246 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002247 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002248 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002249 X.re = as_regex(op1, &sreg);
2250 R.i = regexec(X.re, L.s, 0, NULL, 0);
2251 if (X.re == &sreg) regfree(X.re);
2252 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2253 break;
2254
Denis Vlasenkof782f522007-01-01 23:51:30 +00002255 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002256 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002257 if (R.v == v1+1 && R.v->string) {
2258 res = setvar_p(L.v, R.v->string);
2259 R.v->string = NULL;
2260 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002261 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002262 }
2263 break;
2264
Denis Vlasenkof782f522007-01-01 23:51:30 +00002265 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002266 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002267 runtime_error(EMSG_POSSIBLE_ERROR);
2268 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2269 break;
2270
Denis Vlasenkof782f522007-01-01 23:51:30 +00002271 case XC( OC_FUNC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002272 if (! op->r.f->body.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002273 runtime_error(EMSG_UNDEF_FUNC);
2274
2275 X.v = R.v = nvalloc(op->r.f->nargs+1);
2276 while (op1) {
2277 L.v = evaluate(nextarg(&op1), v1);
2278 copyvar(R.v, L.v);
2279 R.v->type |= VF_CHILD;
2280 R.v->x.parent = L.v;
2281 if (++R.v - X.v >= op->r.f->nargs)
2282 break;
2283 }
2284
2285 R.v = fnargs;
2286 fnargs = X.v;
2287
2288 L.s = programname;
2289 res = evaluate(op->r.f->body.first, res);
2290 programname = L.s;
2291
2292 nvfree(fnargs);
2293 fnargs = R.v;
2294 break;
2295
Denis Vlasenkof782f522007-01-01 23:51:30 +00002296 case XC( OC_GETLINE ):
2297 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002298 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002299 X.rsm = newfile(L.s);
2300 if (! X.rsm->F) {
2301 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2302 X.rsm->F = popen(L.s, "r");
2303 X.rsm->is_pipe = TRUE;
2304 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002305 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002306 }
2307 }
2308 } else {
2309 if (! iF) iF = next_input_file();
2310 X.rsm = iF;
2311 }
2312
2313 if (! X.rsm->F) {
2314 setvar_i(V[ERRNO], errno);
2315 setvar_i(res, -1);
2316 break;
2317 }
2318
2319 if (! op->r.n)
2320 R.v = V[F0];
2321
2322 L.i = awk_getline(X.rsm, R.v);
2323 if (L.i > 0) {
2324 if (! op1) {
2325 incvar(V[FNR]);
2326 incvar(V[NR]);
2327 }
2328 }
2329 setvar_i(res, L.i);
2330 break;
2331
Mike Frysingerde2b9382005-09-27 03:18:00 +00002332 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002333 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002334 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002335
Denis Vlasenkof782f522007-01-01 23:51:30 +00002336 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002337 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002338 break;
2339
Denis Vlasenkof782f522007-01-01 23:51:30 +00002340 case F_rn:
2341 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002342 break;
2343
Denis Vlasenkof782f522007-01-01 23:51:30 +00002344#if ENABLE_FEATURE_AWK_MATH
2345 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002346 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002347 break;
2348
Denis Vlasenkof782f522007-01-01 23:51:30 +00002349 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002350 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002351 break;
2352
Denis Vlasenkof782f522007-01-01 23:51:30 +00002353 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002354 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002355 break;
2356
Denis Vlasenkof782f522007-01-01 23:51:30 +00002357 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002358 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002359 break;
2360
Denis Vlasenkof782f522007-01-01 23:51:30 +00002361 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002362 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002363 break;
2364#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002365 case F_co:
2366 case F_ex:
2367 case F_lg:
2368 case F_si:
2369 case F_sq:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002370 runtime_error(EMSG_NO_MATH);
2371 break;
2372#endif
2373
Denis Vlasenkof782f522007-01-01 23:51:30 +00002374 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002375 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002376 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002377 srand(seed);
2378 break;
2379
Denis Vlasenkof782f522007-01-01 23:51:30 +00002380 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002381 R.d = time(NULL);
2382 break;
2383
Denis Vlasenkof782f522007-01-01 23:51:30 +00002384 case F_le:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002385 if (! op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002386 L.s = getvar_s(V[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002387 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002388 break;
2389
Denis Vlasenkof782f522007-01-01 23:51:30 +00002390 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002391 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002392 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2393 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002394 break;
2395
Denis Vlasenkof782f522007-01-01 23:51:30 +00002396 case F_ff:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002397 if (! op1)
2398 fflush(stdout);
2399 else {
2400 if (L.s && *L.s) {
2401 X.rsm = newfile(L.s);
2402 fflush(X.rsm->F);
2403 } else {
2404 fflush(NULL);
2405 }
2406 }
2407 break;
2408
Denis Vlasenkof782f522007-01-01 23:51:30 +00002409 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002410 X.rsm = (rstream *)hash_search(fdhash, L.s);
2411 if (X.rsm) {
2412 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002413 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002414 hash_remove(fdhash, L.s);
2415 }
2416 if (R.i != 0)
2417 setvar_i(V[ERRNO], errno);
2418 R.d = (double)R.i;
2419 break;
2420 }
2421 setvar_i(res, R.d);
2422 break;
2423
Denis Vlasenkof782f522007-01-01 23:51:30 +00002424 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002425 res = exec_builtin(op, res);
2426 break;
2427
Denis Vlasenkof782f522007-01-01 23:51:30 +00002428 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002429 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002430 break;
2431
Denis Vlasenkof782f522007-01-01 23:51:30 +00002432 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002433 X.v = R.v;
2434 L.d = R.d = getvar_i(R.v);
2435 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002436 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002437 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002438 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002439 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002440 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002441 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002442 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002443 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002444 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002445 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002446 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002447 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002448 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002449 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002450 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002451 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002452 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002453 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002454 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002455 setvar_i(X.v, R.d);
2456 }
2457 setvar_i(res, L.d);
2458 break;
2459
Denis Vlasenkof782f522007-01-01 23:51:30 +00002460 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002461 R.i = (int)getvar_i(R.v);
2462 if (R.i == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002463 res = V[F0];
2464 } else {
2465 split_f0();
2466 if (R.i > nfields)
2467 fsrealloc(R.i);
2468
2469 res = &Fields[R.i-1];
2470 }
2471 break;
2472
2473 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002474 case XC( OC_CONCAT ):
2475 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002476 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002477 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002478 strcpy(X.s, L.s);
2479 if ((opinfo & OPCLSMASK) == OC_COMMA) {
2480 L.s = getvar_s(V[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002481 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002482 strcat(X.s, L.s);
2483 }
2484 strcat(X.s, R.s);
2485 setvar_p(res, X.s);
2486 break;
2487
Denis Vlasenkof782f522007-01-01 23:51:30 +00002488 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002489 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2490 break;
2491
Denis Vlasenkof782f522007-01-01 23:51:30 +00002492 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002493 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2494 break;
2495
Denis Vlasenkof782f522007-01-01 23:51:30 +00002496 case XC( OC_BINARY ):
2497 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002498 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002499 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002500 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002501 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002502 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002503 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002504 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002505 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002506 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002507 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002508 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002509 case '/':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002510 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2511 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002512 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002513 case '&':
2514#if ENABLE_FEATURE_AWK_MATH
Mike Frysingerde2b9382005-09-27 03:18:00 +00002515 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002516#else
2517 runtime_error(EMSG_NO_MATH);
2518#endif
2519 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002520 case '%':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002521 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2522 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002523 break;
2524 }
2525 res = setvar_i(((opinfo&OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
2526 break;
2527
Denis Vlasenkof782f522007-01-01 23:51:30 +00002528 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002529 if (is_numeric(L.v) && is_numeric(R.v)) {
2530 L.d = getvar_i(L.v) - getvar_i(R.v);
2531 } else {
2532 L.s = getvar_s(L.v);
2533 R.s = getvar_s(R.v);
2534 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2535 }
2536 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002537 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002538 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002539 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002540 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002541 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002542 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002543 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002544 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002545 break;
2546 }
2547 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2548 break;
2549
Denis Vlasenkof782f522007-01-01 23:51:30 +00002550 default:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002551 runtime_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002552 }
2553 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2554 op = op->a.n;
2555 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2556 break;
2557 if (nextrec)
2558 break;
2559 }
2560 nvfree(v1);
2561 return res;
2562}
2563
2564
2565/* -------- main & co. -------- */
2566
Mike Frysinger10a11e22005-09-27 02:23:02 +00002567static int awk_exit(int r)
2568{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002569 var tv;
2570 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002571 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002572
Denis Vlasenkof782f522007-01-01 23:51:30 +00002573 zero_out_var(&tv);
2574
2575 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002576 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002577 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002578 evaluate(endseq.first, &tv);
2579 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002580
2581 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002582 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002583 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002584 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002585 if (hi->data.rs.F && hi->data.rs.is_pipe)
2586 pclose(hi->data.rs.F);
2587 hi = hi->next;
2588 }
2589 }
2590
2591 exit(r);
2592}
2593
2594/* if expr looks like "var=value", perform assignment and return 1,
2595 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002596static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002597{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002598 char *exprc, *s, *s0, *s1;
2599
Rob Landleyd921b2e2006-08-03 15:41:12 +00002600 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002601 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2602 free(exprc);
2603 return FALSE;
2604 }
2605
2606 *(s++) = '\0';
2607 s0 = s1 = s;
2608 while (*s)
2609 *(s1++) = nextchar(&s);
2610
2611 *s1 = '\0';
2612 setvar_u(newvar(exprc), s0);
2613 free(exprc);
2614 return TRUE;
2615}
2616
2617/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002618static rstream *next_input_file(void)
2619{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002620 static rstream rsm;
2621 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002622 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002623 static int files_happen = FALSE;
2624
2625 if (rsm.F) fclose(rsm.F);
2626 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002627 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002628
2629 do {
2630 if (getvar_i(V[ARGIND])+1 >= getvar_i(V[ARGC])) {
2631 if (files_happen)
2632 return NULL;
2633 fname = "-";
2634 F = stdin;
2635 } else {
2636 ind = getvar_s(incvar(V[ARGIND]));
2637 fname = getvar_s(findvar(iamarray(V[ARGV]), ind));
2638 if (fname && *fname && !is_assignment(fname))
2639 F = afopen(fname, "r");
2640 }
2641 } while (!F);
2642
2643 files_happen = TRUE;
2644 setvar_s(V[FILENAME], fname);
2645 rsm.F = F;
2646 return &rsm;
2647}
2648
Denis Vlasenko06af2162007-02-03 17:28:39 +00002649int awk_main(int argc, char **argv);
Rob Landleydfba7412006-03-06 20:47:33 +00002650int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002651{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002652 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002653 char *opt_F, *opt_W;
2654 llist_t *opt_v = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002655 int i, j, flen;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002656 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002657 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002658 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002659 char *vnames = (char *)vNames; /* cheat */
2660 char *vvalues = (char *)vValues;
2661
Denis Vlasenko150f4022007-01-13 21:06:21 +00002662 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002663 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2664 if (ENABLE_LOCALE_SUPPORT)
2665 setlocale(LC_NUMERIC, "C");
2666
Denis Vlasenkof782f522007-01-01 23:51:30 +00002667 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002668
2669 /* allocate global buffer */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002670 buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002671
2672 vhash = hash_init();
2673 ahash = hash_init();
2674 fdhash = hash_init();
2675 fnhash = hash_init();
2676
2677 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002678 for (i = 0; *vnames; i++) {
2679 V[i] = v = newvar(nextword(&vnames));
2680 if (*vvalues != '\377')
2681 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002682 else
2683 setvar_i(v, 0);
2684
Denis Vlasenkof782f522007-01-01 23:51:30 +00002685 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002686 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002687 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002688 }
2689 }
2690
2691 handle_special(V[FS]);
2692 handle_special(V[RS]);
2693
Denis Vlasenkof782f522007-01-01 23:51:30 +00002694 newfile("/dev/stdin")->F = stdin;
2695 newfile("/dev/stdout")->F = stdout;
2696 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002697
Denis Vlasenkof782f522007-01-01 23:51:30 +00002698 for (envp = environ; *envp; envp++) {
2699 char *s = xstrdup(*envp);
2700 char *s1 = strchr(s, '=');
2701 if (s1) {
2702 *s1++ = '\0';
2703 setvar_u(findvar(iamarray(V[ENVIRON]), s), s1);
Eric Andersen67776be2004-07-30 23:52:08 +00002704 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002705 free(s);
2706 }
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002707 opt_complementary = "v::";
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002708 opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &programname, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002709 argv += optind;
2710 argc -= optind;
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002711 if (opt & 0x1) setvar_s(V[FS], opt_F); // -F
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002712 while (opt_v) { /* -v */
2713 if (!is_assignment(llist_pop(&opt_v)))
2714 bb_show_usage();
2715 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002716 if (opt & 0x4) { // -f
Denis Vlasenkof782f522007-01-01 23:51:30 +00002717 char *s = s; /* die, gcc, die */
2718 FILE *from_file = afopen(programname, "r");
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002719 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002720 if (fseek(from_file, 0, SEEK_END) == 0) {
2721 flen = ftell(from_file);
2722 s = xmalloc(flen + 4);
2723 fseek(from_file, 0, SEEK_SET);
2724 i = 1 + fread(s + 1, 1, flen, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002725 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002726 for (i = j = 1; j > 0; i += j) {
2727 s = xrealloc(s, i + 4096);
2728 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002729 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002730 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002731 s[i] = '\0';
Denis Vlasenkof782f522007-01-01 23:51:30 +00002732 fclose(from_file);
2733 parse_program(s + 1);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002734 free(s);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002735 } else { // no -f: take program from 1st parameter
2736 if (!argc)
2737 bb_show_usage();
2738 programname = "cmd. line";
2739 parse_program(*argv++);
2740 argc--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002741 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002742 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002743 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002744
Glenn L McGrath545106f2002-11-11 06:21:00 +00002745 /* fill in ARGV array */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002746 setvar_i(V[ARGC], argc + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002747 setari_u(V[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002748 i = 0;
2749 while (*argv)
2750 setari_u(V[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002751
2752 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002753 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002754 awk_exit(EXIT_SUCCESS);
2755
2756 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002757 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002758
2759 /* passing through input files */
2760 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002761 nextfile = FALSE;
2762 setvar_i(V[FNR], 0);
2763
Denis Vlasenkof782f522007-01-01 23:51:30 +00002764 while ((i = awk_getline(iF, V[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002765 nextrec = FALSE;
2766 incvar(V[NR]);
2767 incvar(V[FNR]);
2768 evaluate(mainseq.first, &tv);
2769
2770 if (nextfile)
2771 break;
2772 }
2773
Denis Vlasenkof782f522007-01-01 23:51:30 +00002774 if (i < 0)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002775 runtime_error(strerror(errno));
2776
2777 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002778 }
2779
Glenn L McGrath545106f2002-11-11 06:21:00 +00002780 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002781 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002782}