blob: ea326ecdf65ae1739e47b256a7bba866b1d8edaf [file] [log] [blame]
Glenn L McGrath545106f2002-11-11 06:21:00 +00001/* vi: set sw=4 ts=4: */
2/*
3 * awk implementation for busybox
4 *
5 * Copyright (C) 2002 by Dmitry Zakharov <dmit@crp.bank.gov.ua>
6 *
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00007 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Glenn L McGrath545106f2002-11-11 06:21:00 +00008 */
9
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000010#include "libbb.h"
Rob Landleyd921b2e2006-08-03 15:41:12 +000011#include "xregex.h"
12#include <math.h>
Denis Vlasenko5b340832007-05-17 23:02:14 +000013extern char **environ;
Glenn L McGrath545106f2002-11-11 06:21:00 +000014
Denis Vlasenko99912ca2007-04-10 15:43:37 +000015/* This is a NOEXEC applet. Be very careful! */
16
Glenn L McGrath545106f2002-11-11 06:21:00 +000017
Denis Vlasenko629563b2007-02-24 17:05:52 +000018#define MAXVARFMT 240
19#define MINNVBLOCK 64
Glenn L McGrath545106f2002-11-11 06:21:00 +000020
21/* variable flags */
Denis Vlasenko629563b2007-02-24 17:05:52 +000022#define VF_NUMBER 0x0001 /* 1 = primary type is number */
23#define VF_ARRAY 0x0002 /* 1 = it's an array */
Glenn L McGrath545106f2002-11-11 06:21:00 +000024
Denis Vlasenko629563b2007-02-24 17:05:52 +000025#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
26#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
27#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
28#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
29#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
30#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
31#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
Glenn L McGrath545106f2002-11-11 06:21:00 +000032
33/* these flags are static, don't change them when value is changed */
Denis Vlasenko629563b2007-02-24 17:05:52 +000034#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
Glenn L McGrath545106f2002-11-11 06:21:00 +000035
36/* Variable */
37typedef struct var_s {
Denis Vlasenko629563b2007-02-24 17:05:52 +000038 unsigned short type; /* flags */
Glenn L McGrath545106f2002-11-11 06:21:00 +000039 double number;
40 char *string;
41 union {
Denis Vlasenko629563b2007-02-24 17:05:52 +000042 int aidx; /* func arg idx (for compilation stage) */
43 struct xhash_s *array; /* array ptr */
44 struct var_s *parent; /* for func args, ptr to actual parameter */
45 char **walker; /* list of array elements (for..in) */
Glenn L McGrath545106f2002-11-11 06:21:00 +000046 } x;
47} var;
48
49/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
50typedef struct chain_s {
51 struct node_s *first;
52 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +000053 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +000054} chain;
55
56/* Function */
57typedef struct func_s {
58 unsigned short nargs;
59 struct chain_s body;
60} func;
61
62/* I/O stream */
63typedef struct rstream_s {
64 FILE *F;
65 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +000066 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +000067 int size;
68 int pos;
69 unsigned short is_pipe;
70} rstream;
71
72typedef struct hash_item_s {
73 union {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000074 struct var_s v; /* variable/array hash */
75 struct rstream_s rs; /* redirect streams hash */
76 struct func_s f; /* functions hash */
Glenn L McGrath545106f2002-11-11 06:21:00 +000077 } data;
Denis Vlasenkoffba9412007-05-17 23:03:35 +000078 struct hash_item_s *next; /* next in chain */
79 char name[1]; /* really it's longer */
Glenn L McGrath545106f2002-11-11 06:21:00 +000080} hash_item;
81
82typedef struct xhash_s {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000083 unsigned nel; /* num of elements */
84 unsigned csize; /* current hash size */
85 unsigned nprime; /* next hash size in PRIMES[] */
86 unsigned glen; /* summary length of item names */
Glenn L McGrath545106f2002-11-11 06:21:00 +000087 struct hash_item_s **items;
88} xhash;
89
90/* Tree node */
91typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +000092 uint32_t info;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +000093 unsigned lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +000094 union {
95 struct node_s *n;
96 var *v;
97 int i;
98 char *s;
99 regex_t *re;
100 } l;
101 union {
102 struct node_s *n;
103 regex_t *ire;
104 func *f;
105 int argno;
106 } r;
107 union {
108 struct node_s *n;
109 } a;
110} node;
111
112/* Block of temporary variables */
113typedef struct nvblock_s {
114 int size;
115 var *pos;
116 struct nvblock_s *prev;
117 struct nvblock_s *next;
118 var nv[0];
119} nvblock;
120
121typedef struct tsplitter_s {
122 node n;
123 regex_t re[2];
124} tsplitter;
125
126/* simple token classes */
127/* Order and hex values are very important!!! See next_token() */
128#define TC_SEQSTART 1 /* ( */
129#define TC_SEQTERM (1 << 1) /* ) */
130#define TC_REGEXP (1 << 2) /* /.../ */
131#define TC_OUTRDR (1 << 3) /* | > >> */
132#define TC_UOPPOST (1 << 4) /* unary postfix operator */
133#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
134#define TC_BINOPX (1 << 6) /* two-opnd operator */
135#define TC_IN (1 << 7)
136#define TC_COMMA (1 << 8)
137#define TC_PIPE (1 << 9) /* input redirection pipe */
138#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
139#define TC_ARRTERM (1 << 11) /* ] */
140#define TC_GRPSTART (1 << 12) /* { */
141#define TC_GRPTERM (1 << 13) /* } */
142#define TC_SEMICOL (1 << 14)
143#define TC_NEWLINE (1 << 15)
144#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
145#define TC_WHILE (1 << 17)
146#define TC_ELSE (1 << 18)
147#define TC_BUILTIN (1 << 19)
148#define TC_GETLINE (1 << 20)
149#define TC_FUNCDECL (1 << 21) /* `function' `func' */
150#define TC_BEGIN (1 << 22)
151#define TC_END (1 << 23)
152#define TC_EOF (1 << 24)
153#define TC_VARIABLE (1 << 25)
154#define TC_ARRAY (1 << 26)
155#define TC_FUNCTION (1 << 27)
156#define TC_STRING (1 << 28)
157#define TC_NUMBER (1 << 29)
158
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000159#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000160
161/* combined token classes */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000162#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
163#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
164#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
165 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000166
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000167#define TC_STATEMNT (TC_STATX | TC_WHILE)
168#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000169
170/* word tokens, cannot mean something else if not expected */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000171#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
172 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000173
174/* discard newlines after these */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000175#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
176 | TC_BINOP | TC_OPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000177
178/* what can expression begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000179#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000180/* what can group begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000181#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000182
183/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
184/* operator is inserted between them */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000185#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
186 | TC_STRING | TC_NUMBER | TC_UOPPOST)
187#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000188
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000189#define OF_RES1 0x010000
190#define OF_RES2 0x020000
191#define OF_STR1 0x040000
192#define OF_STR2 0x080000
193#define OF_NUM1 0x100000
194#define OF_CHECKED 0x200000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000195
196/* combined operator flags */
197#define xx 0
198#define xV OF_RES2
199#define xS (OF_RES2 | OF_STR2)
200#define Vx OF_RES1
201#define VV (OF_RES1 | OF_RES2)
202#define Nx (OF_RES1 | OF_NUM1)
203#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
204#define Sx (OF_RES1 | OF_STR1)
205#define SV (OF_RES1 | OF_STR1 | OF_RES2)
206#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
207
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000208#define OPCLSMASK 0xFF00
209#define OPNMASK 0x007F
Glenn L McGrath545106f2002-11-11 06:21:00 +0000210
211/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
212 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
213 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
214 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000215#define P(x) (x << 24)
216#define PRIMASK 0x7F000000
217#define PRIMASK2 0x7E000000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000218
219/* Operation classes */
220
221#define SHIFT_TIL_THIS 0x0600
222#define RECUR_FROM_THIS 0x1000
223
224enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000225 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
226 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000227
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000228 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
229 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
230 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000231
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000232 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
233 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
234 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
235 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
236 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
237 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
238 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
239 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
240 OC_DONE = 0x2800,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000241
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000242 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
243 ST_WHILE = 0x3300
Glenn L McGrath545106f2002-11-11 06:21:00 +0000244};
245
246/* simple builtins */
247enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000248 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000249 F_ti, F_le, F_sy, F_ff, F_cl
250};
251
252/* builtins */
253enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000254 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up,
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000255 B_ge, B_gs, B_su,
256 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000257};
258
259/* tokens and their corresponding info values */
260
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000261#define NTC "\377" /* switch to next token class (tc<<1) */
262#define NTCC '\377'
Glenn L McGrath545106f2002-11-11 06:21:00 +0000263
264#define OC_B OC_BUILTIN
265
Denis Vlasenkof782f522007-01-01 23:51:30 +0000266static const char tokenlist[] =
267 "\1(" NTC
268 "\1)" NTC
269 "\1/" NTC /* REGEXP */
270 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
271 "\2++" "\2--" NTC /* UOPPOST */
272 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
273 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
274 "\2*=" "\2/=" "\2%=" "\2^="
275 "\1+" "\1-" "\3**=" "\2**"
276 "\1/" "\1%" "\1^" "\1*"
277 "\2!=" "\2>=" "\2<=" "\1>"
278 "\1<" "\2!~" "\1~" "\2&&"
279 "\2||" "\1?" "\1:" NTC
280 "\2in" NTC
281 "\1," NTC
282 "\1|" NTC
283 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
284 "\1]" NTC
285 "\1{" NTC
286 "\1}" NTC
287 "\1;" NTC
288 "\1\n" NTC
289 "\2if" "\2do" "\3for" "\5break" /* STATX */
290 "\10continue" "\6delete" "\5print"
291 "\6printf" "\4next" "\10nextfile"
292 "\6return" "\4exit" NTC
293 "\5while" NTC
294 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000295
Denis Vlasenkof782f522007-01-01 23:51:30 +0000296 "\3and" "\5compl" "\6lshift" "\2or"
297 "\6rshift" "\3xor"
298 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
299 "\3cos" "\3exp" "\3int" "\3log"
300 "\4rand" "\3sin" "\4sqrt" "\5srand"
301 "\6gensub" "\4gsub" "\5index" "\6length"
302 "\5match" "\5split" "\7sprintf" "\3sub"
303 "\6substr" "\7systime" "\10strftime"
304 "\7tolower" "\7toupper" NTC
305 "\7getline" NTC
306 "\4func" "\10function" NTC
307 "\5BEGIN" NTC
308 "\3END" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000309 ;
310
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000311static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000312 0,
313 0,
314 OC_REGEXP,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000315 xS|'a', xS|'w', xS|'|',
316 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
317 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M',
318 OC_FIELD|xV|P(5),
319 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|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_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
323 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-',
324 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
325 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%',
326 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
327 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
328 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
329 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
330 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
331 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
332 OC_COLON|xx|P(67)|':',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000333 OC_IN|SV|P(49),
334 OC_COMMA|SS|P(80),
335 OC_PGETLINE|SV|P(37),
Denis Vlasenkof782f522007-01-01 23:51:30 +0000336 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',
337 OC_UNARY|xV|P(19)|'!',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000338 0,
339 0,
340 0,
341 0,
342 0,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000343 ST_IF, ST_DO, ST_FOR, OC_BREAK,
344 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
345 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
346 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000347 ST_WHILE,
348 0,
349
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000350 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
351 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000352 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
353 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
354 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
355 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
356 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
357 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b),
358 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
359 OC_GETLINE|SV|P(0),
360 0, 0,
361 0,
362 0
363};
364
365/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000366/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000367enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000368 CONVFMT, OFMT, FS, OFS,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000369 ORS, RS, RT, FILENAME,
370 SUBSEP, ARGIND, ARGC, ARGV,
371 ERRNO, FNR,
372 NR, NF, IGNORECASE,
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000373 ENVIRON, F0, NUM_INTERNAL_VARS
Glenn L McGrath545106f2002-11-11 06:21:00 +0000374};
375
Denis Vlasenkof782f522007-01-01 23:51:30 +0000376static const char vNames[] =
377 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
378 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
379 "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0"
380 "ERRNO\0" "FNR\0"
381 "NR\0" "NF\0*" "IGNORECASE\0*"
382 "ENVIRON\0" "$\0*" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000383
Denis Vlasenkof782f522007-01-01 23:51:30 +0000384static const char vValues[] =
385 "%.6g\0" "%.6g\0" " \0" " \0"
386 "\n\0" "\n\0" "\0" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000387 "\034\0"
388 "\377";
389
390/* hash size may grow to these values */
391#define FIRST_PRIME 61;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000392static const unsigned PRIMES[] = { 251, 1021, 4093, 16381, 65521 };
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000393enum { NPRIMES = sizeof(PRIMES) / sizeof(PRIMES[0]) };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000394
395/* globals */
396
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000397static var *intvar[NUM_INTERNAL_VARS];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000398static chain beginseq, mainseq, endseq, *seq;
399static int nextrec, nextfile;
400static node *break_ptr, *continue_ptr;
401static rstream *iF;
402static xhash *vhash, *ahash, *fdhash, *fnhash;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000403static const char *programname;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000404static int lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000405static int is_f0_split;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000406static int nfields;
407static var *Fields;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000408static tsplitter fsplitter, rsplitter;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000409static nvblock *cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000410static char *pos;
411static char *buf;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000412static int icase;
413static int exiting;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000414
415static struct {
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000416 uint32_t tclass;
417 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000418 char *string;
419 double number;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000420 int lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000421 int rollback;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000422} ttt;
423/* It had even better name: 't'. Whoever knows what is it, please rename! */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000424/* (actually it looks like unrelated stuff lumped together...) */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000425
426/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000427static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000428static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000429static void chain_group(void);
430static var *evaluate(node *, var *);
431static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000432static int fmt_num(char *, int, const char *, double, int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000433static int awk_exit(int) ATTRIBUTE_NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000434
435/* ---- error handling ---- */
436
437static const char EMSG_INTERNAL_ERROR[] = "Internal error";
438static const char EMSG_UNEXP_EOS[] = "Unexpected end of string";
439static const char EMSG_UNEXP_TOKEN[] = "Unexpected token";
440static const char EMSG_DIV_BY_ZERO[] = "Division by zero";
441static const char EMSG_INV_FMT[] = "Invalid format specifier";
442static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin";
443static const char EMSG_NOT_ARRAY[] = "Not an array";
444static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error";
445static const char EMSG_UNDEF_FUNC[] = "Call to undefined function";
Denis Vlasenkof782f522007-01-01 23:51:30 +0000446#if !ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +0000447static const char EMSG_NO_MATH[] = "Math support is not compiled in";
448#endif
449
Denis Vlasenkof782f522007-01-01 23:51:30 +0000450static void zero_out_var(var * vp)
451{
452 memset(vp, 0, sizeof(*vp));
453}
454
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000455static void syntax_error(const char * const message) ATTRIBUTE_NORETURN;
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000456static void syntax_error(const char * const message)
457{
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000458 bb_error_msg_and_die("%s:%i: %s", programname, lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000459}
460
461#define runtime_error(x) syntax_error(x)
462
463
464/* ---- hash stuff ---- */
465
Denis Vlasenkof782f522007-01-01 23:51:30 +0000466static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000467{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000468 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000469
Denis Vlasenkof782f522007-01-01 23:51:30 +0000470 while (*name) idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000471 return idx;
472}
473
474/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000475static xhash *hash_init(void)
476{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000477 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000478
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000479 newhash = xzalloc(sizeof(xhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000480 newhash->csize = FIRST_PRIME;
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000481 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000482
483 return newhash;
484}
485
486/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000487static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000488{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000489 hash_item *hi;
490
491 hi = hash->items [ hashidx(name) % hash->csize ];
492 while (hi) {
493 if (strcmp(hi->name, name) == 0)
494 return &(hi->data);
495 hi = hi->next;
496 }
497 return NULL;
498}
499
500/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000501static void hash_rebuild(xhash *hash)
502{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000503 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000504 hash_item **newitems, *hi, *thi;
505
506 if (hash->nprime == NPRIMES)
507 return;
508
509 newsize = PRIMES[hash->nprime++];
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000510 newitems = xzalloc(newsize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000511
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000512 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000513 hi = hash->items[i];
514 while (hi) {
515 thi = hi;
516 hi = thi->next;
517 idx = hashidx(thi->name) % newsize;
518 thi->next = newitems[idx];
519 newitems[idx] = thi;
520 }
521 }
522
523 free(hash->items);
524 hash->csize = newsize;
525 hash->items = newitems;
526}
527
528/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000529static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000530{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000531 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000532 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000533 int l;
534
535 hi = hash_search(hash, name);
536 if (! hi) {
537 if (++hash->nel / hash->csize > 10)
538 hash_rebuild(hash);
539
Rob Landleya3896512006-05-07 20:20:34 +0000540 l = strlen(name) + 1;
Rob Landley9ffd4232006-05-21 18:30:35 +0000541 hi = xzalloc(sizeof(hash_item) + l);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000542 memcpy(hi->name, name, l);
543
544 idx = hashidx(name) % hash->csize;
545 hi->next = hash->items[idx];
546 hash->items[idx] = hi;
547 hash->glen += l;
548 }
549 return &(hi->data);
550}
551
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000552#define findvar(hash, name) ((var*) hash_find((hash), (name)))
553#define newvar(name) ((var*) hash_find(vhash, (name)))
554#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
555#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000556
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000557static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000558{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000559 hash_item *hi, **phi;
560
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000561 phi = &(hash->items[hashidx(name) % hash->csize]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000562 while (*phi) {
563 hi = *phi;
564 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000565 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000566 hash->nel--;
567 *phi = hi->next;
568 free(hi);
569 break;
570 }
571 phi = &(hi->next);
572 }
573}
574
575/* ------ some useful functions ------ */
576
Mike Frysinger10a11e22005-09-27 02:23:02 +0000577static void skip_spaces(char **s)
578{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000579 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000580
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000581 while (1) {
582 if (*p == '\\' && p[1] == '\n') {
583 p++;
584 ttt.lineno++;
585 } else if (*p != ' ' && *p != '\t') {
586 break;
587 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000588 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000589 }
590 *s = p;
591}
592
Mike Frysinger10a11e22005-09-27 02:23:02 +0000593static char *nextword(char **s)
594{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000595 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000596
Denis Vlasenkof782f522007-01-01 23:51:30 +0000597 while (*(*s)++) /* */;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000598
599 return p;
600}
601
Mike Frysinger10a11e22005-09-27 02:23:02 +0000602static char nextchar(char **s)
603{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000604 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000605
606 c = *((*s)++);
607 pps = *s;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000608 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000609 if (c == '\\' && *s == pps) c = *((*s)++);
610 return c;
611}
612
Rob Landley88621d72006-08-29 19:41:06 +0000613static int ATTRIBUTE_ALWAYS_INLINE isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000614{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000615 return (isalnum(c) || c == '_');
616}
617
Mike Frysinger10a11e22005-09-27 02:23:02 +0000618static FILE *afopen(const char *path, const char *mode)
619{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000620 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000621}
622
623/* -------- working with variables (set/get/copy/etc) -------- */
624
Mike Frysinger10a11e22005-09-27 02:23:02 +0000625static xhash *iamarray(var *v)
626{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000627 var *a = v;
628
629 while (a->type & VF_CHILD)
630 a = a->x.parent;
631
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000632 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000633 a->type |= VF_ARRAY;
634 a->x.array = hash_init();
635 }
636 return a->x.array;
637}
638
Mike Frysinger10a11e22005-09-27 02:23:02 +0000639static void clear_array(xhash *array)
640{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000641 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000642 hash_item *hi, *thi;
643
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000644 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000645 hi = array->items[i];
646 while (hi) {
647 thi = hi;
648 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000649 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000650 free(thi);
651 }
652 array->items[i] = NULL;
653 }
654 array->glen = array->nel = 0;
655}
656
657/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000658static var *clrvar(var *v)
659{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000660 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000661 free(v->string);
662
663 v->type &= VF_DONTTOUCH;
664 v->type |= VF_DIRTY;
665 v->string = NULL;
666 return v;
667}
668
669/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000670static var *setvar_p(var *v, char *value)
671{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000672 clrvar(v);
673 v->string = value;
674 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000675 return v;
676}
677
678/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000679static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000680{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000681 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000682}
683
684/* same as setvar_s but set USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000685static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000686{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000687 setvar_s(v, value);
688 v->type |= VF_USER;
689 return v;
690}
691
692/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000693static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000694{
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000695 char sidx[sizeof(int)*3 + 1];
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000696 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000697
698 sprintf(sidx, "%d", idx);
699 v = findvar(iamarray(a), sidx);
700 setvar_u(v, s);
701}
702
703/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000704static var *setvar_i(var *v, double value)
705{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000706 clrvar(v);
707 v->type |= VF_NUMBER;
708 v->number = value;
709 handle_special(v);
710 return v;
711}
712
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000713static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000714{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000715 /* if v is numeric and has no cached string, convert it to string */
716 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000717 fmt_num(buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000718 v->string = xstrdup(buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000719 v->type |= VF_CACHED;
720 }
721 return (v->string == NULL) ? "" : v->string;
722}
723
Mike Frysinger10a11e22005-09-27 02:23:02 +0000724static double getvar_i(var *v)
725{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000726 char *s;
727
728 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
729 v->number = 0;
730 s = v->string;
731 if (s && *s) {
732 v->number = strtod(s, &s);
733 if (v->type & VF_USER) {
734 skip_spaces(&s);
735 if (*s != '\0')
736 v->type &= ~VF_USER;
737 }
738 } else {
739 v->type &= ~VF_USER;
740 }
741 v->type |= VF_CACHED;
742 }
743 return v->number;
744}
745
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000746static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000747{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000748 if (dest != src) {
749 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000750 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000751 dest->number = src->number;
752 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000753 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000754 }
755 handle_special(dest);
756 return dest;
757}
758
Mike Frysinger10a11e22005-09-27 02:23:02 +0000759static var *incvar(var *v)
760{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000761 return setvar_i(v, getvar_i(v)+1.);
762}
763
764/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000765static int is_numeric(var *v)
766{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000767 getvar_i(v);
768 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
769}
770
771/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000772static int istrue(var *v)
773{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000774 if (is_numeric(v))
775 return (v->number == 0) ? 0 : 1;
776 else
777 return (v->string && *(v->string)) ? 1 : 0;
778}
779
Eric Andersenaff114c2004-04-14 17:51:38 +0000780/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000781static var *nvalloc(int n)
782{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000783 nvblock *pb = NULL;
784 var *v, *r;
785 int size;
786
787 while (cb) {
788 pb = cb;
789 if ((cb->pos - cb->nv) + n <= cb->size) break;
790 cb = cb->next;
791 }
792
793 if (! cb) {
794 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkob95636c2006-12-19 23:36:04 +0000795 cb = xmalloc(sizeof(nvblock) + size * sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000796 cb->size = size;
797 cb->pos = cb->nv;
798 cb->prev = pb;
799 cb->next = NULL;
800 if (pb) pb->next = cb;
801 }
802
803 v = r = cb->pos;
804 cb->pos += n;
805
806 while (v < cb->pos) {
807 v->type = 0;
808 v->string = NULL;
809 v++;
810 }
811
812 return r;
813}
814
Mike Frysinger10a11e22005-09-27 02:23:02 +0000815static void nvfree(var *v)
816{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000817 var *p;
818
819 if (v < cb->nv || v >= cb->pos)
820 runtime_error(EMSG_INTERNAL_ERROR);
821
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000822 for (p = v; p < cb->pos; p++) {
823 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000824 clear_array(iamarray(p));
825 free(p->x.array->items);
826 free(p->x.array);
827 }
828 if (p->type & VF_WALK)
829 free(p->x.walker);
830
831 clrvar(p);
832 }
833
834 cb->pos = v;
835 while (cb->prev && cb->pos == cb->nv) {
836 cb = cb->prev;
837 }
838}
839
840/* ------- awk program text parsing ------- */
841
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000842/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000843 * If token isn't expected, give away. Return token class
844 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000845static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000846{
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000847 static int concat_inserted;
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000848 static uint32_t save_tclass, save_info;
849 static uint32_t ltclass = TC_OPTERM;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000850
Denis Vlasenkof782f522007-01-01 23:51:30 +0000851 char *p, *pp, *s;
852 const char *tl;
853 uint32_t tc;
854 const uint32_t *ti;
855 int l;
856
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000857 if (ttt.rollback) {
858 ttt.rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000859
860 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000861 concat_inserted = FALSE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000862 ttt.tclass = save_tclass;
863 ttt.info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000864
865 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000866 p = pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000867 readnext:
Glenn L McGrath545106f2002-11-11 06:21:00 +0000868 skip_spaces(&p);
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000869 lineno = ttt.lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000870 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000871 while (*p != '\n' && *p != '\0')
872 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000873
874 if (*p == '\n')
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000875 ttt.lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000876
877 if (*p == '\0') {
878 tc = TC_EOF;
879
880 } else if (*p == '\"') {
881 /* it's a string */
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000882 ttt.string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000883 while (*p != '\"') {
884 if (*p == '\0' || *p == '\n')
885 syntax_error(EMSG_UNEXP_EOS);
886 *(s++) = nextchar(&p);
887 }
888 p++;
889 *s = '\0';
890 tc = TC_STRING;
891
892 } else if ((expected & TC_REGEXP) && *p == '/') {
893 /* it's regexp */
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000894 ttt.string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000895 while (*p != '/') {
896 if (*p == '\0' || *p == '\n')
897 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +0000898 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000899 if (*s++ == '\\') {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000900 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000901 *(s-1) = bb_process_escape_sequence((const char **)&p);
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000902 if (*pp == '\\')
903 *s++ = '\\';
904 if (p == pp)
905 *s++ = *p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000906 }
907 }
908 p++;
909 *s = '\0';
910 tc = TC_REGEXP;
911
912 } else if (*p == '.' || isdigit(*p)) {
913 /* it's a number */
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000914 ttt.number = strtod(p, &p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000915 if (*p == '.')
916 syntax_error(EMSG_UNEXP_TOKEN);
917 tc = TC_NUMBER;
918
919 } else {
920 /* search for something known */
921 tl = tokenlist;
922 tc = 0x00000001;
923 ti = tokeninfo;
924 while (*tl) {
925 l = *(tl++);
926 if (l == NTCC) {
927 tc <<= 1;
928 continue;
929 }
930 /* if token class is expected, token
931 * matches and it's not a longer word,
932 * then this is what we are looking for
933 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000934 if ((tc & (expected | TC_WORD | TC_NEWLINE))
935 && *tl == *p && strncmp(p, tl, l) == 0
936 && !((tc & TC_WORD) && isalnum_(p[l]))
937 ) {
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000938 ttt.info = *ti;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000939 p += l;
940 break;
941 }
942 ti++;
943 tl += l;
944 }
945
Denis Vlasenkof782f522007-01-01 23:51:30 +0000946 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000947 /* it's a name (var/array/function),
948 * otherwise it's something wrong
949 */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000950 if (!isalnum_(*p))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000951 syntax_error(EMSG_UNEXP_TOKEN);
952
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000953 ttt.string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000954 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000955 *(p-1) = *p;
956 }
957 *(p-1) = '\0';
958 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +0000959 /* also consume whitespace between functionname and bracket */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000960 if (!(expected & TC_VARIABLE))
961 skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000962 if (*p == '(') {
963 tc = TC_FUNCTION;
964 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000965 if (*p == '[') {
966 p++;
967 tc = TC_ARRAY;
968 }
969 }
970 }
971 }
972 pos = p;
973
974 /* skipping newlines in some cases */
975 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
976 goto readnext;
977
978 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000979 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000980 concat_inserted = TRUE;
981 save_tclass = tc;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000982 save_info = ttt.info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000983 tc = TC_BINOP;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000984 ttt.info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000985 }
986
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000987 ttt.tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000988 }
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000989 ltclass = ttt.tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000990
991 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000992 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000993 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000994 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000995
996 return ltclass;
997}
998
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000999static void rollback_token(void)
1000{
1001 ttt.rollback = TRUE;
1002}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001003
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001004static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001005{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001006 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001007
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001008 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001009 n->info = info;
1010 n->lineno = lineno;
1011 return n;
1012}
1013
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001014static node *mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001015{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001016 n->info = OC_REGEXP;
1017 n->l.re = re;
1018 n->r.ire = re + 1;
1019 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001020 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001021
1022 return n;
1023}
1024
Mike Frysinger10a11e22005-09-27 02:23:02 +00001025static node *condition(void)
1026{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001027 next_token(TC_SEQSTART);
1028 return parse_expr(TC_SEQTERM);
1029}
1030
1031/* parse expression terminated by given argument, return ptr
1032 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001033static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001034{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001035 node sn;
1036 node *cn = &sn;
1037 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001038 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001039 var *v;
1040
1041 sn.info = PRIMASK;
1042 sn.r.n = glptr = NULL;
1043 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1044
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001045 while (!((tc = next_token(xtc)) & iexp)) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001046 if (glptr && (ttt.info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001047 /* input redirection (<) attached to glptr node */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001048 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001049 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001050 xtc = TC_OPERAND | TC_UOPPRE;
1051 glptr = NULL;
1052
1053 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1054 /* for binary and postfix-unary operators, jump back over
1055 * previous operators with higher priority */
1056 vn = cn;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001057 while ( ((ttt.info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1058 || ((ttt.info == vn->info) && ((ttt.info & OPCLSMASK) == OC_COLON)) )
Glenn L McGrath545106f2002-11-11 06:21:00 +00001059 vn = vn->a.n;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001060 if ((ttt.info & OPCLSMASK) == OC_TERNARY)
1061 ttt.info += P(6);
1062 cn = vn->a.n->r.n = new_node(ttt.info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001063 cn->a.n = vn->a.n;
1064 if (tc & TC_BINOP) {
1065 cn->l.n = vn;
1066 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001067 if ((ttt.info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001068 /* it's a pipe */
1069 next_token(TC_GETLINE);
1070 /* give maximum priority to this pipe */
1071 cn->info &= ~PRIMASK;
1072 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1073 }
1074 } else {
1075 cn->r.n = vn;
1076 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1077 }
1078 vn->a.n = cn;
1079
1080 } else {
1081 /* for operands and prefix-unary operators, attach them
1082 * to last node */
1083 vn = cn;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001084 cn = vn->r.n = new_node(ttt.info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001085 cn->a.n = vn;
1086 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1087 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001088 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001089 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001090 * only simple tclasses should be used! */
1091 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001092 case TC_VARIABLE:
1093 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001094 cn->info = OC_VAR;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001095 v = hash_search(ahash, ttt.string);
1096 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001097 cn->info = OC_FNARG;
1098 cn->l.i = v->x.aidx;
1099 } else {
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001100 cn->l.v = newvar(ttt.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001101 }
1102 if (tc & TC_ARRAY) {
1103 cn->info |= xS;
1104 cn->r.n = parse_expr(TC_ARRTERM);
1105 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001106 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001107
Denis Vlasenkof782f522007-01-01 23:51:30 +00001108 case TC_NUMBER:
1109 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001110 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001111 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001112 if (tc & TC_NUMBER)
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001113 setvar_i(v, ttt.number);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001114 else
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001115 setvar_s(v, ttt.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001116 break;
1117
Denis Vlasenkof782f522007-01-01 23:51:30 +00001118 case TC_REGEXP:
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001119 mk_re_node(ttt.string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001120 break;
1121
Denis Vlasenkof782f522007-01-01 23:51:30 +00001122 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001123 cn->info = OC_FUNC;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001124 cn->r.f = newfunc(ttt.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001125 cn->l.n = condition();
1126 break;
1127
Denis Vlasenkof782f522007-01-01 23:51:30 +00001128 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001129 cn = vn->r.n = parse_expr(TC_SEQTERM);
1130 cn->a.n = vn;
1131 break;
1132
Denis Vlasenkof782f522007-01-01 23:51:30 +00001133 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001134 glptr = cn;
1135 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1136 break;
1137
Denis Vlasenkof782f522007-01-01 23:51:30 +00001138 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001139 cn->l.n = condition();
1140 break;
1141 }
1142 }
1143 }
1144 }
1145 return sn.r.n;
1146}
1147
1148/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001149static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001150{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001151 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001152
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001153 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001154 seq->first = seq->last = new_node(0);
1155
1156 if (seq->programname != programname) {
1157 seq->programname = programname;
1158 n = chain_node(OC_NEWSOURCE);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001159 n->l.s = xstrdup(programname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001160 }
1161
1162 n = seq->last;
1163 n->info = info;
1164 seq->last = n->a.n = new_node(OC_DONE);
1165
1166 return n;
1167}
1168
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001169static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001170{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001171 node *n;
1172
1173 n = chain_node(info);
1174 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001175 if (ttt.tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001176 rollback_token();
1177}
1178
Mike Frysinger10a11e22005-09-27 02:23:02 +00001179static node *chain_loop(node *nn)
1180{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001181 node *n, *n2, *save_brk, *save_cont;
1182
1183 save_brk = break_ptr;
1184 save_cont = continue_ptr;
1185
1186 n = chain_node(OC_BR | Vx);
1187 continue_ptr = new_node(OC_EXEC);
1188 break_ptr = new_node(OC_EXEC);
1189 chain_group();
1190 n2 = chain_node(OC_EXEC | Vx);
1191 n2->l.n = nn;
1192 n2->a.n = n;
1193 continue_ptr->a.n = n2;
1194 break_ptr->a.n = n->r.n = seq->last;
1195
1196 continue_ptr = save_cont;
1197 break_ptr = save_brk;
1198
1199 return n;
1200}
1201
1202/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001203static void chain_group(void)
1204{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001205 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001206 node *n, *n2, *n3;
1207
1208 do {
1209 c = next_token(TC_GRPSEQ);
1210 } while (c & TC_NEWLINE);
1211
1212 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001213 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001214 if (ttt.tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001215 rollback_token();
1216 chain_group();
1217 }
1218 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1219 rollback_token();
1220 chain_expr(OC_EXEC | Vx);
1221 } else { /* TC_STATEMNT */
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001222 switch (ttt.info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001223 case ST_IF:
1224 n = chain_node(OC_BR | Vx);
1225 n->l.n = condition();
1226 chain_group();
1227 n2 = chain_node(OC_EXEC);
1228 n->r.n = seq->last;
1229 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001230 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001231 n2->a.n = seq->last;
1232 } else {
1233 rollback_token();
1234 }
1235 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001236
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001237 case ST_WHILE:
1238 n2 = condition();
1239 n = chain_loop(NULL);
1240 n->l.n = n2;
1241 break;
1242
1243 case ST_DO:
1244 n2 = chain_node(OC_EXEC);
1245 n = chain_loop(NULL);
1246 n2->a.n = n->a.n;
1247 next_token(TC_WHILE);
1248 n->l.n = condition();
1249 break;
1250
1251 case ST_FOR:
1252 next_token(TC_SEQSTART);
1253 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
1254 if (ttt.tclass & TC_SEQTERM) { /* for-in */
1255 if ((n2->info & OPCLSMASK) != OC_IN)
1256 syntax_error(EMSG_UNEXP_TOKEN);
1257 n = chain_node(OC_WALKINIT | VV);
1258 n->l.n = n2->l.n;
1259 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001260 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001261 n->info = OC_WALKNEXT | Vx;
1262 n->l.n = n2->l.n;
1263 } else { /* for (;;) */
1264 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001265 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001266 n2 = parse_expr(TC_SEMICOL);
1267 n3 = parse_expr(TC_SEQTERM);
1268 n = chain_loop(n3);
1269 n->l.n = n2;
1270 if (! n2)
1271 n->info = OC_EXEC;
1272 }
1273 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001274
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001275 case OC_PRINT:
1276 case OC_PRINTF:
1277 n = chain_node(ttt.info);
1278 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
1279 if (ttt.tclass & TC_OUTRDR) {
1280 n->info |= ttt.info;
1281 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1282 }
1283 if (ttt.tclass & TC_GRPTERM)
1284 rollback_token();
1285 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001286
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001287 case OC_BREAK:
1288 n = chain_node(OC_EXEC);
1289 n->a.n = break_ptr;
1290 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001291
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001292 case OC_CONTINUE:
1293 n = chain_node(OC_EXEC);
1294 n->a.n = continue_ptr;
1295 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001296
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001297 /* delete, next, nextfile, return, exit */
1298 default:
1299 chain_expr(ttt.info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001300 }
1301 }
1302}
1303
Mike Frysinger10a11e22005-09-27 02:23:02 +00001304static void parse_program(char *p)
1305{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001306 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001307 node *cn;
1308 func *f;
1309 var *v;
1310
1311 pos = p;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001312 ttt.lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001313 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001314 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001315
1316 if (tclass & TC_OPTERM)
1317 continue;
1318
1319 seq = &mainseq;
1320 if (tclass & TC_BEGIN) {
1321 seq = &beginseq;
1322 chain_group();
1323
1324 } else if (tclass & TC_END) {
1325 seq = &endseq;
1326 chain_group();
1327
1328 } else if (tclass & TC_FUNCDECL) {
1329 next_token(TC_FUNCTION);
1330 pos++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001331 f = newfunc(ttt.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001332 f->body.first = NULL;
1333 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001334 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001335 v = findvar(ahash, ttt.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001336 v->x.aidx = (f->nargs)++;
1337
1338 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1339 break;
1340 }
1341 seq = &(f->body);
1342 chain_group();
1343 clear_array(ahash);
1344
1345 } else if (tclass & TC_OPSEQ) {
1346 rollback_token();
1347 cn = chain_node(OC_TEST);
1348 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001349 if (ttt.tclass & TC_GRPSTART) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001350 rollback_token();
1351 chain_group();
1352 } else {
1353 chain_node(OC_PRINT);
1354 }
1355 cn->r.n = mainseq.last;
1356
1357 } else /* if (tclass & TC_GRPSTART) */ {
1358 rollback_token();
1359 chain_group();
1360 }
1361 }
1362}
1363
1364
1365/* -------- program execution part -------- */
1366
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001367static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001368{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001369 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001370 node *n;
1371
1372 re = &spl->re[0];
1373 ire = &spl->re[1];
1374 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001375 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001376 regfree(re);
1377 regfree(ire);
1378 }
Rob Landleya3896512006-05-07 20:20:34 +00001379 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001380 mk_re_node(s, n, re);
1381 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001382 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001383 }
1384
1385 return n;
1386}
1387
1388/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001389 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001390 * be later regfree'd manually
1391 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001392static regex_t *as_regex(node *op, regex_t *preg)
1393{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001394 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001395 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001396
1397 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1398 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001399 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001400 v = nvalloc(1);
1401 s = getvar_s(evaluate(op, v));
1402 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1403 nvfree(v);
1404 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001405}
1406
1407/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001408static void qrealloc(char **b, int n, int *size)
1409{
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001410 if (!*b || n >= *size)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001411 *b = xrealloc(*b, *size = n + (n>>1) + 80);
1412}
1413
1414/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001415static void fsrealloc(int size)
1416{
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001417 static int maxfields; /* = 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00001418 int i;
1419
1420 if (size >= maxfields) {
1421 i = maxfields;
1422 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001423 Fields = xrealloc(Fields, maxfields * sizeof(var));
1424 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001425 Fields[i].type = VF_SPECIAL;
1426 Fields[i].string = NULL;
1427 }
1428 }
1429
1430 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001431 for (i = size; i < nfields; i++) {
1432 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001433 }
1434 }
1435 nfields = size;
1436}
1437
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001438static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001439{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001440 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001441 char c[4];
1442 char *s1;
1443 regmatch_t pmatch[2];
1444
1445 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001446 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1447 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001448
1449 c[0] = c[1] = (char)spl->info;
1450 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001451 if (*getvar_s(intvar[RS]) == '\0')
1452 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001453
1454 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1455 while (*s) {
1456 l = strcspn(s, c+2);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001457 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1458 && pmatch[0].rm_so <= l
1459 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001460 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001461 if (pmatch[0].rm_eo == 0) {
1462 l++;
1463 pmatch[0].rm_eo++;
1464 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001465 } else {
1466 pmatch[0].rm_eo = l;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001467 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001468 }
1469
1470 memcpy(s1, s, l);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001471 s1[l] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001472 nextword(&s1);
1473 s += pmatch[0].rm_eo;
1474 n++;
1475 }
1476 } else if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001477 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001478 *s1++ = *s++;
1479 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001480 n++;
1481 }
1482 } else if (c[0] != ' ') { /* single-character split */
1483 if (icase) {
1484 c[0] = toupper(c[0]);
1485 c[1] = tolower(c[1]);
1486 }
1487 if (*s1) n++;
1488 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001489 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001490 n++;
1491 }
1492 } else { /* space split */
1493 while (*s) {
Denis Vlasenkod18a3a22006-10-25 12:46:03 +00001494 s = skip_whitespace(s);
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001495 if (!*s) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001496 n++;
1497 while (*s && !isspace(*s))
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001498 *s1++ = *s++;
1499 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001500 }
1501 }
1502 return n;
1503}
1504
Mike Frysinger10a11e22005-09-27 02:23:02 +00001505static void split_f0(void)
1506{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001507 static char *fstrings = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001508
Glenn L McGrath545106f2002-11-11 06:21:00 +00001509 int i, n;
1510 char *s;
1511
1512 if (is_f0_split)
1513 return;
1514
1515 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001516 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001517 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001518 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001519 fsrealloc(n);
1520 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001521 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001522 Fields[i].string = nextword(&s);
1523 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1524 }
1525
1526 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001527 clrvar(intvar[NF]);
1528 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1529 intvar[NF]->number = nfields;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001530}
1531
1532/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001533static void handle_special(var *v)
1534{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001535 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001536 char *b;
1537 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001538 int sl, l, len, i, bsize;
1539
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001540 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001541 return;
1542
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001543 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001544 n = (int)getvar_i(v);
1545 fsrealloc(n);
1546
1547 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001548 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001549 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001550 b = NULL;
1551 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001552 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001553 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001554 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001555 if (b) {
1556 memcpy(b+len, sep, sl);
1557 len += sl;
1558 }
1559 qrealloc(&b, len+l+sl, &bsize);
1560 memcpy(b+len, s, l);
1561 len += l;
1562 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001563 if (b)
1564 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001565 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001566 is_f0_split = TRUE;
1567
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001568 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001569 is_f0_split = FALSE;
1570
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001571 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001572 mk_splitter(getvar_s(v), &fsplitter);
1573
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001574 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001575 mk_splitter(getvar_s(v), &rsplitter);
1576
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001577 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001578 icase = istrue(v);
1579
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001580 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001581 n = getvar_i(intvar[NF]);
1582 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001583 /* right here v is invalid. Just to note... */
1584 }
1585}
1586
1587/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001588static node *nextarg(node **pn)
1589{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001590 node *n;
1591
1592 n = *pn;
1593 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1594 *pn = n->r.n;
1595 n = n->l.n;
1596 } else {
1597 *pn = NULL;
1598 }
1599 return n;
1600}
1601
Mike Frysinger10a11e22005-09-27 02:23:02 +00001602static void hashwalk_init(var *v, xhash *array)
1603{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001604 char **w;
1605 hash_item *hi;
1606 int i;
1607
1608 if (v->type & VF_WALK)
1609 free(v->x.walker);
1610
1611 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001612 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001613 w[0] = w[1] = (char *)(w + 2);
1614 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001615 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001616 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001617 strcpy(*w, hi->name);
1618 nextword(w);
1619 hi = hi->next;
1620 }
1621 }
1622}
1623
Mike Frysinger10a11e22005-09-27 02:23:02 +00001624static int hashwalk_next(var *v)
1625{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001626 char **w;
1627
1628 w = v->x.walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001629 if (w[1] == w[0])
Glenn L McGrath545106f2002-11-11 06:21:00 +00001630 return FALSE;
1631
1632 setvar_s(v, nextword(w+1));
1633 return TRUE;
1634}
1635
1636/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001637static int ptest(node *pattern)
1638{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001639 static var v; /* static: to save stack space? */
1640
Glenn L McGrath545106f2002-11-11 06:21:00 +00001641 return istrue(evaluate(pattern, &v));
1642}
1643
1644/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001645static int awk_getline(rstream *rsm, var *v)
1646{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001647 char *b;
1648 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001649 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001650 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001651 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001652
1653 /* we're using our own buffer since we need access to accumulating
1654 * characters
1655 */
1656 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001657 m = rsm->buffer;
1658 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001659 p = rsm->pos;
1660 size = rsm->size;
1661 c = (char) rsplitter.n.info;
1662 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001663
1664 if (! m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001665 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001666 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001667 so = eo = p;
1668 r = 1;
1669 if (p > 0) {
1670 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1671 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001672 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001673 so = pmatch[0].rm_so;
1674 eo = pmatch[0].rm_eo;
1675 if (b[eo] != '\0')
1676 break;
1677 }
1678 } else if (c != '\0') {
1679 s = strchr(b+pp, c);
Rob Landley46e351d2006-02-14 16:05:32 +00001680 if (! s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001681 if (s) {
1682 so = eo = s-b;
1683 eo++;
1684 break;
1685 }
1686 } else {
1687 while (b[rp] == '\n')
1688 rp++;
1689 s = strstr(b+rp, "\n\n");
1690 if (s) {
1691 so = eo = s-b;
1692 while (b[eo] == '\n') eo++;
1693 if (b[eo] != '\0')
1694 break;
1695 }
1696 }
1697 }
1698
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001699 if (a > 0) {
1700 memmove(m, (const void *)(m+a), p+1);
1701 b = m;
1702 a = 0;
1703 }
1704
1705 qrealloc(&m, a+p+128, &size);
1706 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001707 pp = p;
1708 p += safe_read(fd, b+p, size-p-1);
1709 if (p < pp) {
1710 p = 0;
1711 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001712 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001713 }
1714 b[p] = '\0';
1715
1716 } while (p > pp);
1717
1718 if (p == 0) {
1719 r--;
1720 } else {
1721 c = b[so]; b[so] = '\0';
1722 setvar_s(v, b+rp);
1723 v->type |= VF_USER;
1724 b[so] = c;
1725 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001726 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001727 b[eo] = c;
1728 }
1729
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001730 rsm->buffer = m;
1731 rsm->adv = a + eo;
1732 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001733 rsm->size = size;
1734
1735 return r;
1736}
1737
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001738static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001739{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001740 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001741 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001742 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001743
1744 if (int_as_int && n == (int)n) {
1745 r = snprintf(b, size, "%d", (int)n);
1746 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001747 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001748 if (strchr("diouxX", c)) {
1749 r = snprintf(b, size, format, (int)n);
1750 } else if (strchr("eEfgG", c)) {
1751 r = snprintf(b, size, format, n);
1752 } else {
1753 runtime_error(EMSG_INV_FMT);
1754 }
1755 }
1756 return r;
1757}
1758
1759
1760/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001761static char *awk_printf(node *n)
1762{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001763 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001764 char *fmt, *s, *f;
1765 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001766 int i, j, incr, bsize;
1767 char c, c1;
1768 var *v, *arg;
1769
1770 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001771 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001772
1773 i = 0;
1774 while (*f) {
1775 s = f;
1776 while (*f && (*f != '%' || *(++f) == '%'))
1777 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001778 while (*f && !isalpha(*f)) {
1779 if (*f == '*')
1780 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001781 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001782 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001783
1784 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001785 qrealloc(&b, incr + i, &bsize);
1786 c = *f;
1787 if (c != '\0') f++;
1788 c1 = *f;
1789 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001790 arg = evaluate(nextarg(&n), v);
1791
1792 j = i;
1793 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001794 i += sprintf(b+i, s, is_numeric(arg) ?
1795 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001796 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001797 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001798 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001799 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001800 } else {
1801 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1802 }
1803 *f = c1;
1804
1805 /* if there was an error while sprintf, return value is negative */
1806 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001807 }
1808
Denis Vlasenkof782f522007-01-01 23:51:30 +00001809 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001810 free(fmt);
1811 nvfree(v);
1812 b[i] = '\0';
1813 return b;
1814}
1815
1816/* common substitution routine
1817 * replace (nm) substring of (src) that match (n) with (repl), store
1818 * result into (dest), return number of substitutions. If nm=0, replace
1819 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1820 * subexpression matching (\1-\9)
1821 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001822static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001823{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001824 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001825 const char *s;
1826 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001827 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1828 regmatch_t pmatch[10];
1829 regex_t sreg, *re;
1830
1831 re = as_regex(rn, &sreg);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001832 if (! src) src = intvar[F0];
1833 if (! dest) dest = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001834
1835 i = di = 0;
1836 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001837 rl = strlen(repl);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001838 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001839 so = pmatch[0].rm_so;
1840 eo = pmatch[0].rm_eo;
1841
1842 qrealloc(&ds, di + eo + rl, &dssize);
1843 memcpy(ds + di, sp, eo);
1844 di += eo;
1845 if (++i >= nm) {
1846 /* replace */
1847 di -= (eo - so);
1848 nbs = 0;
1849 for (s = repl; *s; s++) {
1850 ds[di++] = c = *s;
1851 if (c == '\\') {
1852 nbs++;
1853 continue;
1854 }
1855 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1856 di -= ((nbs + 3) >> 1);
1857 j = 0;
1858 if (c != '&') {
1859 j = c - '0';
1860 nbs++;
1861 }
1862 if (nbs % 2) {
1863 ds[di++] = c;
1864 } else {
1865 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1866 qrealloc(&ds, di + rl + n, &dssize);
1867 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1868 di += n;
1869 }
1870 }
1871 nbs = 0;
1872 }
1873 }
1874
1875 sp += eo;
1876 if (i == nm) break;
1877 if (eo == so) {
1878 if (! (ds[di++] = *sp++)) break;
1879 }
1880 }
1881
1882 qrealloc(&ds, di + strlen(sp), &dssize);
1883 strcpy(ds + di, sp);
1884 setvar_p(dest, ds);
1885 if (re == &sreg) regfree(re);
1886 return i;
1887}
1888
Mike Frysinger10a11e22005-09-27 02:23:02 +00001889static var *exec_builtin(node *op, var *res)
1890{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001891 int (*to_xxx)(int);
1892 var *tv;
1893 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001894 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001895 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001896 regmatch_t pmatch[2];
1897 regex_t sreg, *re;
1898 static tsplitter tspl;
1899 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001900 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001901 int nargs;
1902 time_t tt;
1903 char *s, *s1;
1904 int i, l, ll, n;
1905
1906 tv = nvalloc(4);
1907 isr = info = op->info;
1908 op = op->l.n;
1909
1910 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001911 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001912 an[i] = nextarg(&op);
1913 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
1914 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
1915 isr >>= 1;
1916 }
1917
1918 nargs = i;
1919 if (nargs < (info >> 30))
1920 runtime_error(EMSG_TOO_FEW_ARGS);
1921
1922 switch (info & OPNMASK) {
1923
Denis Vlasenkof782f522007-01-01 23:51:30 +00001924 case B_a2:
1925#if ENABLE_FEATURE_AWK_MATH
Glenn L McGrath545106f2002-11-11 06:21:00 +00001926 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
1927#else
1928 runtime_error(EMSG_NO_MATH);
1929#endif
1930 break;
1931
Denis Vlasenkof782f522007-01-01 23:51:30 +00001932 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001933 if (nargs > 2) {
1934 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
1935 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
1936 } else {
1937 spl = &fsplitter.n;
1938 }
1939
1940 n = awk_split(as[0], spl, &s);
1941 s1 = s;
1942 clear_array(iamarray(av[1]));
1943 for (i=1; i<=n; i++)
1944 setari_u(av[1], i, nextword(&s1));
1945 free(s);
1946 setvar_i(res, n);
1947 break;
1948
Denis Vlasenkof782f522007-01-01 23:51:30 +00001949 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00001950 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001951 i = getvar_i(av[1]) - 1;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001952 if (i > l) i = l;
1953 if (i < 0) i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001954 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001955 if (n < 0) n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001956 s = xmalloc(n+1);
1957 strncpy(s, as[0]+i, n);
1958 s[n] = '\0';
1959 setvar_p(res, s);
1960 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00001961
Denis Vlasenkof782f522007-01-01 23:51:30 +00001962 case B_an:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001963 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
1964 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00001965
Denis Vlasenkof782f522007-01-01 23:51:30 +00001966 case B_co:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001967 setvar_i(res, ~(long)getvar_i(av[0]));
1968 break;
1969
Denis Vlasenkof782f522007-01-01 23:51:30 +00001970 case B_ls:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001971 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
1972 break;
1973
Denis Vlasenkof782f522007-01-01 23:51:30 +00001974 case B_or:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001975 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
1976 break;
1977
Denis Vlasenkof782f522007-01-01 23:51:30 +00001978 case B_rs:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001979 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
1980 break;
1981
Denis Vlasenkof782f522007-01-01 23:51:30 +00001982 case B_xo:
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001983 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
1984 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001985
Denis Vlasenkof782f522007-01-01 23:51:30 +00001986 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001987 to_xxx = tolower;
1988 goto lo_cont;
1989
Denis Vlasenkof782f522007-01-01 23:51:30 +00001990 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001991 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001992 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00001993 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001994 while (*s1) {
1995 *s1 = (*to_xxx)(*s1);
1996 s1++;
1997 }
1998 setvar_p(res, s);
1999 break;
2000
Denis Vlasenkof782f522007-01-01 23:51:30 +00002001 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002002 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002003 ll = strlen(as[1]);
2004 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002005 if (ll > 0 && l >= 0) {
2006 if (! icase) {
2007 s = strstr(as[0], as[1]);
2008 if (s) n = (s - as[0]) + 1;
2009 } else {
2010 /* this piece of code is terribly slow and
2011 * really should be rewritten
2012 */
2013 for (i=0; i<=l; i++) {
2014 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2015 n = i+1;
2016 break;
2017 }
2018 }
2019 }
2020 }
2021 setvar_i(res, n);
2022 break;
2023
Denis Vlasenkof782f522007-01-01 23:51:30 +00002024 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002025 if (nargs > 1)
2026 tt = getvar_i(av[1]);
2027 else
2028 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002029 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
2030 i = strftime(buf, MAXVARFMT,
2031 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2032 localtime(&tt));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002033 buf[i] = '\0';
2034 setvar_s(res, buf);
2035 break;
2036
Denis Vlasenkof782f522007-01-01 23:51:30 +00002037 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002038 re = as_regex(an[1], &sreg);
2039 n = regexec(re, as[0], 1, pmatch, 0);
2040 if (n == 0) {
2041 pmatch[0].rm_so++;
2042 pmatch[0].rm_eo++;
2043 } else {
2044 pmatch[0].rm_so = 0;
2045 pmatch[0].rm_eo = -1;
2046 }
2047 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2048 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2049 setvar_i(res, pmatch[0].rm_so);
2050 if (re == &sreg) regfree(re);
2051 break;
2052
Denis Vlasenkof782f522007-01-01 23:51:30 +00002053 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002054 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2055 break;
2056
Denis Vlasenkof782f522007-01-01 23:51:30 +00002057 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002058 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2059 break;
2060
Denis Vlasenkof782f522007-01-01 23:51:30 +00002061 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002062 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2063 break;
2064 }
2065
2066 nvfree(tv);
2067 return res;
2068}
2069
2070/*
2071 * Evaluate node - the heart of the program. Supplied with subtree
2072 * and place where to store result. returns ptr to result.
2073 */
2074#define XC(n) ((n) >> 8)
2075
Mike Frysinger10a11e22005-09-27 02:23:02 +00002076static var *evaluate(node *op, var *res)
2077{
Mike Frysingerde2b9382005-09-27 03:18:00 +00002078 /* This procedure is recursive so we should count every byte */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002079 static var *fnargs = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002080 static unsigned seed = 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002081 static regex_t sreg;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002082
Glenn L McGrath545106f2002-11-11 06:21:00 +00002083 node *op1;
2084 var *v1;
2085 union {
2086 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002087 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002088 double d;
2089 int i;
2090 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002091 uint32_t opinfo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002092 short opn;
2093 union {
2094 char *s;
2095 rstream *rsm;
2096 FILE *F;
2097 var *v;
2098 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002099 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002100 } X;
2101
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002102 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002103 return setvar_s(res, NULL);
2104
2105 v1 = nvalloc(2);
2106
2107 while (op) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002108 opinfo = op->info;
2109 opn = (short)(opinfo & OPNMASK);
2110 lineno = op->lineno;
2111
Mike Frysingerde2b9382005-09-27 03:18:00 +00002112 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002113 op1 = op->l.n;
2114 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2115 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2116 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2117 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2118 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2119
2120 switch (XC(opinfo & OPCLSMASK)) {
2121
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002122 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002123
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002124 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002125 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002126 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2127 /* it's range pattern */
2128 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2129 op->info |= OF_CHECKED;
2130 if (ptest(op1->r.n))
2131 op->info &= ~OF_CHECKED;
2132
2133 op = op->a.n;
2134 } else {
2135 op = op->r.n;
2136 }
2137 } else {
2138 op = (ptest(op1)) ? op->a.n : op->r.n;
2139 }
2140 break;
2141
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002142 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002143 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002144 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002145
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002146 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002147 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002148 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002149 break;
2150
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002151 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002152 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002153 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002154 break;
2155
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002156 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002157 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002158 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2159 break;
2160
Denis Vlasenkof782f522007-01-01 23:51:30 +00002161 case XC( OC_PRINT ):
2162 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002163 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002164 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002165 X.rsm = newfile(R.s);
2166 if (! X.rsm->F) {
2167 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002168 X.rsm->F = popen(R.s, "w");
2169 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002170 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002171 X.rsm->is_pipe = 1;
2172 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002173 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002174 }
2175 }
2176 X.F = X.rsm->F;
2177 }
2178
2179 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002180 if (! op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002181 fputs(getvar_s(intvar[F0]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002182 } else {
2183 while (op1) {
2184 L.v = evaluate(nextarg(&op1), v1);
2185 if (L.v->type & VF_NUMBER) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002186 fmt_num(buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002187 getvar_i(L.v), TRUE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002188 fputs(buf, X.F);
2189 } else {
2190 fputs(getvar_s(L.v), X.F);
2191 }
2192
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002193 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002194 }
2195 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002196 fputs(getvar_s(intvar[ORS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002197
2198 } else { /* OC_PRINTF */
2199 L.s = awk_printf(op1);
2200 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002201 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002202 }
2203 fflush(X.F);
2204 break;
2205
Denis Vlasenkof782f522007-01-01 23:51:30 +00002206 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002207 X.info = op1->info & OPCLSMASK;
2208 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002209 R.v = op1->l.v;
2210 } else if (X.info == OC_FNARG) {
2211 R.v = &fnargs[op1->l.i];
2212 } else {
2213 runtime_error(EMSG_NOT_ARRAY);
2214 }
2215
Mike Frysingerde2b9382005-09-27 03:18:00 +00002216 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002217 clrvar(L.v);
2218 L.s = getvar_s(evaluate(op1->r.n, v1));
2219 hash_remove(iamarray(R.v), L.s);
2220 } else {
2221 clear_array(iamarray(R.v));
2222 }
2223 break;
2224
Denis Vlasenkof782f522007-01-01 23:51:30 +00002225 case XC( OC_NEWSOURCE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002226 programname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002227 break;
2228
Denis Vlasenkof782f522007-01-01 23:51:30 +00002229 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002230 copyvar(res, L.v);
2231 break;
2232
Denis Vlasenkof782f522007-01-01 23:51:30 +00002233 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002234 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002235 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002236 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002237 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002238 clrvar(res);
2239 break;
2240
Denis Vlasenkof782f522007-01-01 23:51:30 +00002241 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002242 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002243
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002244 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002245
Denis Vlasenkof782f522007-01-01 23:51:30 +00002246 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002247 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002248 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002249 split_f0();
2250 goto v_cont;
2251
Denis Vlasenkof782f522007-01-01 23:51:30 +00002252 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002253 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002254 v_cont:
2255 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002256 break;
2257
Denis Vlasenkof782f522007-01-01 23:51:30 +00002258 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002259 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2260 break;
2261
Denis Vlasenkof782f522007-01-01 23:51:30 +00002262 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002263 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002264 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002265 goto re_cont;
2266
Denis Vlasenkof782f522007-01-01 23:51:30 +00002267 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002268 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002269 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002270 X.re = as_regex(op1, &sreg);
2271 R.i = regexec(X.re, L.s, 0, NULL, 0);
2272 if (X.re == &sreg) regfree(X.re);
2273 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2274 break;
2275
Denis Vlasenkof782f522007-01-01 23:51:30 +00002276 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002277 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002278 if (R.v == v1+1 && R.v->string) {
2279 res = setvar_p(L.v, R.v->string);
2280 R.v->string = NULL;
2281 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002282 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002283 }
2284 break;
2285
Denis Vlasenkof782f522007-01-01 23:51:30 +00002286 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002287 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002288 runtime_error(EMSG_POSSIBLE_ERROR);
2289 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2290 break;
2291
Denis Vlasenkof782f522007-01-01 23:51:30 +00002292 case XC( OC_FUNC ):
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002293 if (!op->r.f->body.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002294 runtime_error(EMSG_UNDEF_FUNC);
2295
2296 X.v = R.v = nvalloc(op->r.f->nargs+1);
2297 while (op1) {
2298 L.v = evaluate(nextarg(&op1), v1);
2299 copyvar(R.v, L.v);
2300 R.v->type |= VF_CHILD;
2301 R.v->x.parent = L.v;
2302 if (++R.v - X.v >= op->r.f->nargs)
2303 break;
2304 }
2305
2306 R.v = fnargs;
2307 fnargs = X.v;
2308
2309 L.s = programname;
2310 res = evaluate(op->r.f->body.first, res);
2311 programname = L.s;
2312
2313 nvfree(fnargs);
2314 fnargs = R.v;
2315 break;
2316
Denis Vlasenkof782f522007-01-01 23:51:30 +00002317 case XC( OC_GETLINE ):
2318 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002319 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002320 X.rsm = newfile(L.s);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002321 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002322 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2323 X.rsm->F = popen(L.s, "r");
2324 X.rsm->is_pipe = TRUE;
2325 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002326 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002327 }
2328 }
2329 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002330 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002331 X.rsm = iF;
2332 }
2333
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002334 if (!X.rsm->F) {
2335 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002336 setvar_i(res, -1);
2337 break;
2338 }
2339
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002340 if (!op->r.n)
2341 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002342
2343 L.i = awk_getline(X.rsm, R.v);
2344 if (L.i > 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002345 if (!op1) {
2346 incvar(intvar[FNR]);
2347 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002348 }
2349 }
2350 setvar_i(res, L.i);
2351 break;
2352
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002353 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002354 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002355 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002356
Denis Vlasenkof782f522007-01-01 23:51:30 +00002357 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002358 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002359 break;
2360
Denis Vlasenkof782f522007-01-01 23:51:30 +00002361 case F_rn:
2362 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002363 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002364#if ENABLE_FEATURE_AWK_MATH
2365 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002366 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002367 break;
2368
Denis Vlasenkof782f522007-01-01 23:51:30 +00002369 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002370 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002371 break;
2372
Denis Vlasenkof782f522007-01-01 23:51:30 +00002373 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002374 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002375 break;
2376
Denis Vlasenkof782f522007-01-01 23:51:30 +00002377 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002378 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002379 break;
2380
Denis Vlasenkof782f522007-01-01 23:51:30 +00002381 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002382 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002383 break;
2384#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002385 case F_co:
2386 case F_ex:
2387 case F_lg:
2388 case F_si:
2389 case F_sq:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002390 runtime_error(EMSG_NO_MATH);
2391 break;
2392#endif
Denis Vlasenkof782f522007-01-01 23:51:30 +00002393 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002394 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002395 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002396 srand(seed);
2397 break;
2398
Denis Vlasenkof782f522007-01-01 23:51:30 +00002399 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002400 R.d = time(NULL);
2401 break;
2402
Denis Vlasenkof782f522007-01-01 23:51:30 +00002403 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002404 if (!op1)
2405 L.s = getvar_s(intvar[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002406 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002407 break;
2408
Denis Vlasenkof782f522007-01-01 23:51:30 +00002409 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002410 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002411 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2412 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002413 break;
2414
Denis Vlasenkof782f522007-01-01 23:51:30 +00002415 case F_ff:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002416 if (!op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002417 fflush(stdout);
2418 else {
2419 if (L.s && *L.s) {
2420 X.rsm = newfile(L.s);
2421 fflush(X.rsm->F);
2422 } else {
2423 fflush(NULL);
2424 }
2425 }
2426 break;
2427
Denis Vlasenkof782f522007-01-01 23:51:30 +00002428 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002429 X.rsm = (rstream *)hash_search(fdhash, L.s);
2430 if (X.rsm) {
2431 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002432 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002433 hash_remove(fdhash, L.s);
2434 }
2435 if (R.i != 0)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002436 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002437 R.d = (double)R.i;
2438 break;
2439 }
2440 setvar_i(res, R.d);
2441 break;
2442
Denis Vlasenkof782f522007-01-01 23:51:30 +00002443 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002444 res = exec_builtin(op, res);
2445 break;
2446
Denis Vlasenkof782f522007-01-01 23:51:30 +00002447 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002448 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002449 break;
2450
Denis Vlasenkof782f522007-01-01 23:51:30 +00002451 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002452 X.v = R.v;
2453 L.d = R.d = getvar_i(R.v);
2454 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002455 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002456 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002457 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002458 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002459 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002460 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002461 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002462 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002463 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002464 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002465 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002466 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002467 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002468 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002469 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002470 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002471 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002472 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002473 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002474 setvar_i(X.v, R.d);
2475 }
2476 setvar_i(res, L.d);
2477 break;
2478
Denis Vlasenkof782f522007-01-01 23:51:30 +00002479 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002480 R.i = (int)getvar_i(R.v);
2481 if (R.i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002482 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002483 } else {
2484 split_f0();
2485 if (R.i > nfields)
2486 fsrealloc(R.i);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002487 res = &Fields[R.i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002488 }
2489 break;
2490
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002491 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002492 case XC( OC_CONCAT ):
2493 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002494 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002495 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002496 strcpy(X.s, L.s);
2497 if ((opinfo & OPCLSMASK) == OC_COMMA) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002498 L.s = getvar_s(intvar[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002499 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002500 strcat(X.s, L.s);
2501 }
2502 strcat(X.s, R.s);
2503 setvar_p(res, X.s);
2504 break;
2505
Denis Vlasenkof782f522007-01-01 23:51:30 +00002506 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002507 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2508 break;
2509
Denis Vlasenkof782f522007-01-01 23:51:30 +00002510 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002511 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2512 break;
2513
Denis Vlasenkof782f522007-01-01 23:51:30 +00002514 case XC( OC_BINARY ):
2515 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002516 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002517 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002518 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002519 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002520 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002521 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002522 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002523 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002524 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002525 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002526 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002527 case '/':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002528 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2529 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002530 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002531 case '&':
2532#if ENABLE_FEATURE_AWK_MATH
Mike Frysingerde2b9382005-09-27 03:18:00 +00002533 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002534#else
2535 runtime_error(EMSG_NO_MATH);
2536#endif
2537 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002538 case '%':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002539 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
2540 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002541 break;
2542 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002543 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002544 break;
2545
Denis Vlasenkof782f522007-01-01 23:51:30 +00002546 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002547 if (is_numeric(L.v) && is_numeric(R.v)) {
2548 L.d = getvar_i(L.v) - getvar_i(R.v);
2549 } else {
2550 L.s = getvar_s(L.v);
2551 R.s = getvar_s(R.v);
2552 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2553 }
2554 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002555 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002556 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002557 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002558 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002559 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002560 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002561 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002562 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002563 break;
2564 }
2565 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2566 break;
2567
Denis Vlasenkof782f522007-01-01 23:51:30 +00002568 default:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002569 runtime_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002570 }
2571 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2572 op = op->a.n;
2573 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2574 break;
2575 if (nextrec)
2576 break;
2577 }
2578 nvfree(v1);
2579 return res;
2580}
2581
2582
2583/* -------- main & co. -------- */
2584
Mike Frysinger10a11e22005-09-27 02:23:02 +00002585static int awk_exit(int r)
2586{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002587 var tv;
2588 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002589 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002590
Denis Vlasenkof782f522007-01-01 23:51:30 +00002591 zero_out_var(&tv);
2592
2593 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002594 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002595 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002596 evaluate(endseq.first, &tv);
2597 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002598
2599 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002600 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002601 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002602 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002603 if (hi->data.rs.F && hi->data.rs.is_pipe)
2604 pclose(hi->data.rs.F);
2605 hi = hi->next;
2606 }
2607 }
2608
2609 exit(r);
2610}
2611
2612/* if expr looks like "var=value", perform assignment and return 1,
2613 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002614static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002615{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002616 char *exprc, *s, *s0, *s1;
2617
Rob Landleyd921b2e2006-08-03 15:41:12 +00002618 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002619 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2620 free(exprc);
2621 return FALSE;
2622 }
2623
2624 *(s++) = '\0';
2625 s0 = s1 = s;
2626 while (*s)
2627 *(s1++) = nextchar(&s);
2628
2629 *s1 = '\0';
2630 setvar_u(newvar(exprc), s0);
2631 free(exprc);
2632 return TRUE;
2633}
2634
2635/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002636static rstream *next_input_file(void)
2637{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002638 static rstream rsm;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002639 static int files_happen = FALSE;
2640
Glenn L McGrath545106f2002-11-11 06:21:00 +00002641 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002642 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002643
2644 if (rsm.F) fclose(rsm.F);
2645 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002646 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002647
2648 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002649 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002650 if (files_happen)
2651 return NULL;
2652 fname = "-";
2653 F = stdin;
2654 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002655 ind = getvar_s(incvar(intvar[ARGIND]));
2656 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002657 if (fname && *fname && !is_assignment(fname))
2658 F = afopen(fname, "r");
2659 }
2660 } while (!F);
2661
2662 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002663 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002664 rsm.F = F;
2665 return &rsm;
2666}
2667
Denis Vlasenko06af2162007-02-03 17:28:39 +00002668int awk_main(int argc, char **argv);
Rob Landleydfba7412006-03-06 20:47:33 +00002669int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002670{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002671 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002672 char *opt_F, *opt_W;
2673 llist_t *opt_v = NULL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002674 int i, j, flen;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002675 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002676 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002677 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002678 char *vnames = (char *)vNames; /* cheat */
2679 char *vvalues = (char *)vValues;
2680
Denis Vlasenko150f4022007-01-13 21:06:21 +00002681 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002682 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2683 if (ENABLE_LOCALE_SUPPORT)
2684 setlocale(LC_NUMERIC, "C");
2685
Denis Vlasenkof782f522007-01-01 23:51:30 +00002686 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002687
2688 /* allocate global buffer */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002689 buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002690
2691 vhash = hash_init();
2692 ahash = hash_init();
2693 fdhash = hash_init();
2694 fnhash = hash_init();
2695
2696 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002697 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002698 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00002699 if (*vvalues != '\377')
2700 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002701 else
2702 setvar_i(v, 0);
2703
Denis Vlasenkof782f522007-01-01 23:51:30 +00002704 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002705 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002706 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002707 }
2708 }
2709
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002710 handle_special(intvar[FS]);
2711 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002712
Denis Vlasenkof782f522007-01-01 23:51:30 +00002713 newfile("/dev/stdin")->F = stdin;
2714 newfile("/dev/stdout")->F = stdout;
2715 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002716
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002717 /* Huh, people report that sometimes environ is NULL. Oh well. */
2718 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002719 char *s = xstrdup(*envp);
2720 char *s1 = strchr(s, '=');
2721 if (s1) {
2722 *s1++ = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002723 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1);
Eric Andersen67776be2004-07-30 23:52:08 +00002724 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002725 free(s);
2726 }
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002727 opt_complementary = "v::";
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002728 opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &programname, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002729 argv += optind;
2730 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002731 if (opt & 0x1)
2732 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002733 while (opt_v) { /* -v */
2734 if (!is_assignment(llist_pop(&opt_v)))
2735 bb_show_usage();
2736 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002737 if (opt & 0x4) { // -f
Denis Vlasenkof782f522007-01-01 23:51:30 +00002738 char *s = s; /* die, gcc, die */
2739 FILE *from_file = afopen(programname, "r");
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002740 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002741 if (fseek(from_file, 0, SEEK_END) == 0) {
2742 flen = ftell(from_file);
2743 s = xmalloc(flen + 4);
2744 fseek(from_file, 0, SEEK_SET);
2745 i = 1 + fread(s + 1, 1, flen, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002746 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002747 for (i = j = 1; j > 0; i += j) {
2748 s = xrealloc(s, i + 4096);
2749 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002750 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002751 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002752 s[i] = '\0';
Denis Vlasenkof782f522007-01-01 23:51:30 +00002753 fclose(from_file);
2754 parse_program(s + 1);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002755 free(s);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002756 } else { // no -f: take program from 1st parameter
2757 if (!argc)
2758 bb_show_usage();
2759 programname = "cmd. line";
2760 parse_program(*argv++);
2761 argc--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002762 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002763 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002764 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002765
Glenn L McGrath545106f2002-11-11 06:21:00 +00002766 /* fill in ARGV array */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002767 setvar_i(intvar[ARGC], argc + 1);
2768 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002769 i = 0;
2770 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002771 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002772
2773 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002774 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002775 awk_exit(EXIT_SUCCESS);
2776
2777 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002778 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002779
2780 /* passing through input files */
2781 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002782 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002783 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002784
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002785 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002786 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002787 incvar(intvar[NR]);
2788 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002789 evaluate(mainseq.first, &tv);
2790
2791 if (nextfile)
2792 break;
2793 }
2794
Denis Vlasenkof782f522007-01-01 23:51:30 +00002795 if (i < 0)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002796 runtime_error(strerror(errno));
2797
2798 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002799 }
2800
Glenn L McGrath545106f2002-11-11 06:21:00 +00002801 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002802 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002803}