blob: cef73342c2d71a03f3590309a2e5a2d5c0c2cec7 [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>
Glenn L McGrath545106f2002-11-11 06:21:00 +000013
Denis Vlasenko99912ca2007-04-10 15:43:37 +000014/* This is a NOEXEC applet. Be very careful! */
15
Glenn L McGrath545106f2002-11-11 06:21:00 +000016
Denis Vlasenko629563b2007-02-24 17:05:52 +000017#define MAXVARFMT 240
18#define MINNVBLOCK 64
Glenn L McGrath545106f2002-11-11 06:21:00 +000019
20/* variable flags */
Denis Vlasenko629563b2007-02-24 17:05:52 +000021#define VF_NUMBER 0x0001 /* 1 = primary type is number */
22#define VF_ARRAY 0x0002 /* 1 = it's an array */
Glenn L McGrath545106f2002-11-11 06:21:00 +000023
Denis Vlasenko629563b2007-02-24 17:05:52 +000024#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
25#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
26#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
27#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
28#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
29#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
30#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
Glenn L McGrath545106f2002-11-11 06:21:00 +000031
32/* these flags are static, don't change them when value is changed */
Denis Vlasenko629563b2007-02-24 17:05:52 +000033#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
Glenn L McGrath545106f2002-11-11 06:21:00 +000034
35/* Variable */
36typedef struct var_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000037 unsigned type; /* flags */
Glenn L McGrath545106f2002-11-11 06:21:00 +000038 double number;
39 char *string;
40 union {
Denis Vlasenko629563b2007-02-24 17:05:52 +000041 int aidx; /* func arg idx (for compilation stage) */
42 struct xhash_s *array; /* array ptr */
43 struct var_s *parent; /* for func args, ptr to actual parameter */
44 char **walker; /* list of array elements (for..in) */
Glenn L McGrath545106f2002-11-11 06:21:00 +000045 } x;
46} var;
47
48/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
49typedef struct chain_s {
50 struct node_s *first;
51 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +000052 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +000053} chain;
54
55/* Function */
56typedef struct func_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000057 unsigned nargs;
Glenn L McGrath545106f2002-11-11 06:21:00 +000058 struct chain_s body;
59} func;
60
61/* I/O stream */
62typedef struct rstream_s {
63 FILE *F;
64 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +000065 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +000066 int size;
67 int pos;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000068 smallint is_pipe;
Glenn L McGrath545106f2002-11-11 06:21:00 +000069} rstream;
70
71typedef struct hash_item_s {
72 union {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000073 struct var_s v; /* variable/array hash */
74 struct rstream_s rs; /* redirect streams hash */
75 struct func_s f; /* functions hash */
Glenn L McGrath545106f2002-11-11 06:21:00 +000076 } data;
Denis Vlasenkoffba9412007-05-17 23:03:35 +000077 struct hash_item_s *next; /* next in chain */
78 char name[1]; /* really it's longer */
Glenn L McGrath545106f2002-11-11 06:21:00 +000079} hash_item;
80
81typedef struct xhash_s {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000082 unsigned nel; /* num of elements */
83 unsigned csize; /* current hash size */
84 unsigned nprime; /* next hash size in PRIMES[] */
85 unsigned glen; /* summary length of item names */
Glenn L McGrath545106f2002-11-11 06:21:00 +000086 struct hash_item_s **items;
87} xhash;
88
89/* Tree node */
90typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +000091 uint32_t info;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +000092 unsigned lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +000093 union {
94 struct node_s *n;
95 var *v;
96 int i;
97 char *s;
98 regex_t *re;
99 } l;
100 union {
101 struct node_s *n;
102 regex_t *ire;
103 func *f;
104 int argno;
105 } r;
106 union {
107 struct node_s *n;
108 } a;
109} node;
110
111/* Block of temporary variables */
112typedef struct nvblock_s {
113 int size;
114 var *pos;
115 struct nvblock_s *prev;
116 struct nvblock_s *next;
117 var nv[0];
118} nvblock;
119
120typedef struct tsplitter_s {
121 node n;
122 regex_t re[2];
123} tsplitter;
124
125/* simple token classes */
126/* Order and hex values are very important!!! See next_token() */
127#define TC_SEQSTART 1 /* ( */
128#define TC_SEQTERM (1 << 1) /* ) */
129#define TC_REGEXP (1 << 2) /* /.../ */
130#define TC_OUTRDR (1 << 3) /* | > >> */
131#define TC_UOPPOST (1 << 4) /* unary postfix operator */
132#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
133#define TC_BINOPX (1 << 6) /* two-opnd operator */
134#define TC_IN (1 << 7)
135#define TC_COMMA (1 << 8)
136#define TC_PIPE (1 << 9) /* input redirection pipe */
137#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
138#define TC_ARRTERM (1 << 11) /* ] */
139#define TC_GRPSTART (1 << 12) /* { */
140#define TC_GRPTERM (1 << 13) /* } */
141#define TC_SEMICOL (1 << 14)
142#define TC_NEWLINE (1 << 15)
143#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
144#define TC_WHILE (1 << 17)
145#define TC_ELSE (1 << 18)
146#define TC_BUILTIN (1 << 19)
147#define TC_GETLINE (1 << 20)
148#define TC_FUNCDECL (1 << 21) /* `function' `func' */
149#define TC_BEGIN (1 << 22)
150#define TC_END (1 << 23)
151#define TC_EOF (1 << 24)
152#define TC_VARIABLE (1 << 25)
153#define TC_ARRAY (1 << 26)
154#define TC_FUNCTION (1 << 27)
155#define TC_STRING (1 << 28)
156#define TC_NUMBER (1 << 29)
157
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000158#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000159
160/* combined token classes */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000161#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
162#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
163#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
164 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000165
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000166#define TC_STATEMNT (TC_STATX | TC_WHILE)
167#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000168
169/* word tokens, cannot mean something else if not expected */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000170#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
171 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000172
173/* discard newlines after these */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000174#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
175 | TC_BINOP | TC_OPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000176
177/* what can expression begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000178#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000179/* what can group begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000180#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000181
182/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
183/* operator is inserted between them */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000184#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
185 | TC_STRING | TC_NUMBER | TC_UOPPOST)
186#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000187
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000188#define OF_RES1 0x010000
189#define OF_RES2 0x020000
190#define OF_STR1 0x040000
191#define OF_STR2 0x080000
192#define OF_NUM1 0x100000
193#define OF_CHECKED 0x200000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000194
195/* combined operator flags */
196#define xx 0
197#define xV OF_RES2
198#define xS (OF_RES2 | OF_STR2)
199#define Vx OF_RES1
200#define VV (OF_RES1 | OF_RES2)
201#define Nx (OF_RES1 | OF_NUM1)
202#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
203#define Sx (OF_RES1 | OF_STR1)
204#define SV (OF_RES1 | OF_STR1 | OF_RES2)
205#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
206
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000207#define OPCLSMASK 0xFF00
208#define OPNMASK 0x007F
Glenn L McGrath545106f2002-11-11 06:21:00 +0000209
210/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
211 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
212 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
213 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000214#define P(x) (x << 24)
215#define PRIMASK 0x7F000000
216#define PRIMASK2 0x7E000000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000217
218/* Operation classes */
219
220#define SHIFT_TIL_THIS 0x0600
221#define RECUR_FROM_THIS 0x1000
222
223enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000224 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
225 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000226
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000227 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
228 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
229 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000230
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000231 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
232 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
233 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
234 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
235 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
236 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
237 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
238 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
239 OC_DONE = 0x2800,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000240
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000241 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
242 ST_WHILE = 0x3300
Glenn L McGrath545106f2002-11-11 06:21:00 +0000243};
244
245/* simple builtins */
246enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000247 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000248 F_ti, F_le, F_sy, F_ff, F_cl
249};
250
251/* builtins */
252enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000253 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up,
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000254 B_ge, B_gs, B_su,
255 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000256};
257
258/* tokens and their corresponding info values */
259
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000260#define NTC "\377" /* switch to next token class (tc<<1) */
261#define NTCC '\377'
Glenn L McGrath545106f2002-11-11 06:21:00 +0000262
263#define OC_B OC_BUILTIN
264
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000265static const char tokenlist[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000266 "\1(" NTC
267 "\1)" NTC
268 "\1/" NTC /* REGEXP */
269 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
270 "\2++" "\2--" NTC /* UOPPOST */
271 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
272 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
273 "\2*=" "\2/=" "\2%=" "\2^="
274 "\1+" "\1-" "\3**=" "\2**"
275 "\1/" "\1%" "\1^" "\1*"
276 "\2!=" "\2>=" "\2<=" "\1>"
277 "\1<" "\2!~" "\1~" "\2&&"
278 "\2||" "\1?" "\1:" NTC
279 "\2in" NTC
280 "\1," NTC
281 "\1|" NTC
282 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
283 "\1]" NTC
284 "\1{" NTC
285 "\1}" NTC
286 "\1;" NTC
287 "\1\n" NTC
288 "\2if" "\2do" "\3for" "\5break" /* STATX */
289 "\10continue" "\6delete" "\5print"
290 "\6printf" "\4next" "\10nextfile"
291 "\6return" "\4exit" NTC
292 "\5while" NTC
293 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000294
Denis Vlasenkof782f522007-01-01 23:51:30 +0000295 "\3and" "\5compl" "\6lshift" "\2or"
296 "\6rshift" "\3xor"
297 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
298 "\3cos" "\3exp" "\3int" "\3log"
299 "\4rand" "\3sin" "\4sqrt" "\5srand"
300 "\6gensub" "\4gsub" "\5index" "\6length"
301 "\5match" "\5split" "\7sprintf" "\3sub"
302 "\6substr" "\7systime" "\10strftime"
303 "\7tolower" "\7toupper" NTC
304 "\7getline" NTC
305 "\4func" "\10function" NTC
306 "\5BEGIN" NTC
307 "\3END" "\0"
Glenn L McGrath545106f2002-11-11 06:21:00 +0000308 ;
309
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000310static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000311 0,
312 0,
313 OC_REGEXP,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000314 xS|'a', xS|'w', xS|'|',
315 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
316 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M',
317 OC_FIELD|xV|P(5),
318 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74),
319 OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
320 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/',
321 OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
322 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-',
323 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
324 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%',
325 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
326 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
327 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
328 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
329 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
330 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
331 OC_COLON|xx|P(67)|':',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000332 OC_IN|SV|P(49),
333 OC_COMMA|SS|P(80),
334 OC_PGETLINE|SV|P(37),
Denis Vlasenkof782f522007-01-01 23:51:30 +0000335 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',
336 OC_UNARY|xV|P(19)|'!',
Glenn L McGrath545106f2002-11-11 06:21:00 +0000337 0,
338 0,
339 0,
340 0,
341 0,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000342 ST_IF, ST_DO, ST_FOR, OC_BREAK,
343 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
344 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
345 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000346 ST_WHILE,
347 0,
348
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000349 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
350 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000351 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
352 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
353 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
354 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
355 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
356 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b),
357 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
358 OC_GETLINE|SV|P(0),
359 0, 0,
360 0,
361 0
362};
363
364/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000365/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000366enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000367 CONVFMT, OFMT, FS, OFS,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000368 ORS, RS, RT, FILENAME,
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000369 SUBSEP, F0, ARGIND, ARGC,
370 ARGV, ERRNO, FNR, NR,
371 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS
Glenn L McGrath545106f2002-11-11 06:21:00 +0000372};
373
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000374static const char vNames[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000375 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
376 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000377 "SUBSEP\0" "$\0*" "ARGIND\0" "ARGC\0"
378 "ARGV\0" "ERRNO\0" "FNR\0" "NR\0"
379 "NF\0*" "IGNORECASE\0*" "ENVIRON\0" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000380
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000381static const char vValues[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000382 "%.6g\0" "%.6g\0" " \0" " \0"
383 "\n\0" "\n\0" "\0" "\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000384 "\034\0" "\0" "\377";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000385
386/* hash size may grow to these values */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000387#define FIRST_PRIME 61
388static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000389
Glenn L McGrath545106f2002-11-11 06:21:00 +0000390
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000391/* Globals. Split in two parts so that first one is addressed
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000392 * with (mostly short) negative offsets.
393 * NB: it's unsafe to put members of type "double"
394 * into globals2 (gcc may fail to align them).
395 */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000396struct globals {
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000397 double t_double;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000398 chain beginseq, mainseq, endseq;
399 chain *seq;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000400 node *break_ptr, *continue_ptr;
401 rstream *iF;
402 xhash *vhash, *ahash, *fdhash, *fnhash;
403 const char *g_progname;
404 int g_lineno;
405 int nfields;
406 int maxfields; /* used in fsrealloc() only */
407 var *Fields;
408 nvblock *g_cb;
409 char *g_pos;
410 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000411 smallint icase;
412 smallint exiting;
413 smallint nextrec;
414 smallint nextfile;
415 smallint is_f0_split;
416};
417struct globals2 {
418 uint32_t t_info; /* often used */
419 uint32_t t_tclass;
420 char *t_string;
421 int t_lineno;
422 int t_rollback;
423
424 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000425
426 /* former statics from various functions */
427 char *split_f0__fstrings;
428
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000429 uint32_t next_token__save_tclass;
430 uint32_t next_token__save_info;
431 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000432 smallint next_token__concat_inserted;
433
434 smallint next_input_file__files_happen;
435 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000436
437 var *evaluate__fnargs;
438 unsigned evaluate__seed;
439 regex_t evaluate__sreg;
440
441 var ptest__v;
442
443 tsplitter exec_builtin__tspl;
444
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000445 /* biggest and least used members go last */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000446 tsplitter fsplitter, rsplitter;
447};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000448#define G1 (ptr_to_globals[-1])
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000449#define G (*(struct globals2 *)ptr_to_globals)
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000450/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000451/*char G1size[sizeof(G1)]; - 0x74 */
452/*char Gsize[sizeof(G)]; - 0x1c4 */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000453/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000454/*char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
455#define t_double (G1.t_double )
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000456#define beginseq (G1.beginseq )
457#define mainseq (G1.mainseq )
458#define endseq (G1.endseq )
459#define seq (G1.seq )
460#define break_ptr (G1.break_ptr )
461#define continue_ptr (G1.continue_ptr)
462#define iF (G1.iF )
463#define vhash (G1.vhash )
464#define ahash (G1.ahash )
465#define fdhash (G1.fdhash )
466#define fnhash (G1.fnhash )
467#define g_progname (G1.g_progname )
468#define g_lineno (G1.g_lineno )
469#define nfields (G1.nfields )
470#define maxfields (G1.maxfields )
471#define Fields (G1.Fields )
472#define g_cb (G1.g_cb )
473#define g_pos (G1.g_pos )
474#define g_buf (G1.g_buf )
475#define icase (G1.icase )
476#define exiting (G1.exiting )
477#define nextrec (G1.nextrec )
478#define nextfile (G1.nextfile )
479#define is_f0_split (G1.is_f0_split )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000480#define t_info (G.t_info )
481#define t_tclass (G.t_tclass )
482#define t_string (G.t_string )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000483#define t_lineno (G.t_lineno )
484#define t_rollback (G.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000485#define intvar (G.intvar )
486#define fsplitter (G.fsplitter )
487#define rsplitter (G.rsplitter )
488#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000489 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1)); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000490 G.next_token__ltclass = TC_OPTERM; \
491 G.evaluate__seed = 1; \
492} while (0)
493
Glenn L McGrath545106f2002-11-11 06:21:00 +0000494
495/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000496static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000497static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000498static void chain_group(void);
499static var *evaluate(node *, var *);
500static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000501static int fmt_num(char *, int, const char *, double, int);
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000502static int awk_exit(int) NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000503
504/* ---- error handling ---- */
505
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000506static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
507static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
508static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
509static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
510static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
511static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
512static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
513static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
514static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
Denis Vlasenko2d5bd802008-10-24 10:49:49 +0000515#if !ENABLE_FEATURE_AWK_LIBM
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000516static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000517#endif
518
Denis Vlasenkof782f522007-01-01 23:51:30 +0000519static void zero_out_var(var * vp)
520{
521 memset(vp, 0, sizeof(*vp));
522}
523
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000524static void syntax_error(const char *message) NORETURN;
525static void syntax_error(const char *message)
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000526{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000527 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000528}
529
Glenn L McGrath545106f2002-11-11 06:21:00 +0000530/* ---- hash stuff ---- */
531
Denis Vlasenkof782f522007-01-01 23:51:30 +0000532static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000533{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000534 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000535
Denis Vlasenkof782f522007-01-01 23:51:30 +0000536 while (*name) idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000537 return idx;
538}
539
540/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000541static xhash *hash_init(void)
542{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000543 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000544
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000545 newhash = xzalloc(sizeof(xhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000546 newhash->csize = FIRST_PRIME;
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000547 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000548
549 return newhash;
550}
551
552/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000553static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000554{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000555 hash_item *hi;
556
557 hi = hash->items [ hashidx(name) % hash->csize ];
558 while (hi) {
559 if (strcmp(hi->name, name) == 0)
560 return &(hi->data);
561 hi = hi->next;
562 }
563 return NULL;
564}
565
566/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000567static void hash_rebuild(xhash *hash)
568{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000569 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000570 hash_item **newitems, *hi, *thi;
571
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000572 if (hash->nprime == ARRAY_SIZE(PRIMES))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000573 return;
574
575 newsize = PRIMES[hash->nprime++];
Denis Vlasenko4cccc032006-12-22 18:37:07 +0000576 newitems = xzalloc(newsize * sizeof(hash_item *));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000577
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000578 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000579 hi = hash->items[i];
580 while (hi) {
581 thi = hi;
582 hi = thi->next;
583 idx = hashidx(thi->name) % newsize;
584 thi->next = newitems[idx];
585 newitems[idx] = thi;
586 }
587 }
588
589 free(hash->items);
590 hash->csize = newsize;
591 hash->items = newitems;
592}
593
594/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000595static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000596{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000597 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000598 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000599 int l;
600
601 hi = hash_search(hash, name);
Denis Vlasenkob78c7822007-07-18 18:31:11 +0000602 if (!hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000603 if (++hash->nel / hash->csize > 10)
604 hash_rebuild(hash);
605
Rob Landleya3896512006-05-07 20:20:34 +0000606 l = strlen(name) + 1;
Denis Vlasenko7a676642009-03-15 22:20:31 +0000607 hi = xzalloc(sizeof(*hi) + l);
608 strcpy(hi->name, name);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000609
610 idx = hashidx(name) % hash->csize;
611 hi->next = hash->items[idx];
612 hash->items[idx] = hi;
613 hash->glen += l;
614 }
615 return &(hi->data);
616}
617
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000618#define findvar(hash, name) ((var*) hash_find((hash), (name)))
619#define newvar(name) ((var*) hash_find(vhash, (name)))
620#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
621#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000622
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000623static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000624{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000625 hash_item *hi, **phi;
626
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000627 phi = &(hash->items[hashidx(name) % hash->csize]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000628 while (*phi) {
629 hi = *phi;
630 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000631 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000632 hash->nel--;
633 *phi = hi->next;
634 free(hi);
635 break;
636 }
637 phi = &(hi->next);
638 }
639}
640
641/* ------ some useful functions ------ */
642
Mike Frysinger10a11e22005-09-27 02:23:02 +0000643static void skip_spaces(char **s)
644{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000645 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000646
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000647 while (1) {
648 if (*p == '\\' && p[1] == '\n') {
649 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000650 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000651 } else if (*p != ' ' && *p != '\t') {
652 break;
653 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000654 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000655 }
656 *s = p;
657}
658
Mike Frysinger10a11e22005-09-27 02:23:02 +0000659static char *nextword(char **s)
660{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000661 char *p = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000662
Denis Vlasenkof782f522007-01-01 23:51:30 +0000663 while (*(*s)++) /* */;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000664
665 return p;
666}
667
Mike Frysinger10a11e22005-09-27 02:23:02 +0000668static char nextchar(char **s)
669{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000670 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000671
672 c = *((*s)++);
673 pps = *s;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000674 if (c == '\\') c = bb_process_escape_sequence((const char**)s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000675 if (c == '\\' && *s == pps) c = *((*s)++);
676 return c;
677}
678
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000679static ALWAYS_INLINE int isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000680{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000681 return (isalnum(c) || c == '_');
682}
683
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000684static double my_strtod(char **pp)
685{
686#if ENABLE_DESKTOP
687 if ((*pp)[0] == '0'
688 && ((((*pp)[1] | 0x20) == 'x') || isdigit((*pp)[1]))
689 ) {
690 return strtoull(*pp, pp, 0);
691 }
692#endif
693 return strtod(*pp, pp);
694}
695
Glenn L McGrath545106f2002-11-11 06:21:00 +0000696/* -------- working with variables (set/get/copy/etc) -------- */
697
Mike Frysinger10a11e22005-09-27 02:23:02 +0000698static xhash *iamarray(var *v)
699{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000700 var *a = v;
701
702 while (a->type & VF_CHILD)
703 a = a->x.parent;
704
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000705 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000706 a->type |= VF_ARRAY;
707 a->x.array = hash_init();
708 }
709 return a->x.array;
710}
711
Mike Frysinger10a11e22005-09-27 02:23:02 +0000712static void clear_array(xhash *array)
713{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000714 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000715 hash_item *hi, *thi;
716
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000717 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000718 hi = array->items[i];
719 while (hi) {
720 thi = hi;
721 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000722 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000723 free(thi);
724 }
725 array->items[i] = NULL;
726 }
727 array->glen = array->nel = 0;
728}
729
730/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000731static var *clrvar(var *v)
732{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000733 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000734 free(v->string);
735
736 v->type &= VF_DONTTOUCH;
737 v->type |= VF_DIRTY;
738 v->string = NULL;
739 return v;
740}
741
742/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000743static var *setvar_p(var *v, char *value)
744{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000745 clrvar(v);
746 v->string = value;
747 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000748 return v;
749}
750
751/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000752static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000753{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000754 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000755}
756
757/* same as setvar_s but set USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000758static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000759{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000760 setvar_s(v, value);
761 v->type |= VF_USER;
762 return v;
763}
764
765/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000766static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000767{
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000768 char sidx[sizeof(int)*3 + 1];
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000769 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000770
771 sprintf(sidx, "%d", idx);
772 v = findvar(iamarray(a), sidx);
773 setvar_u(v, s);
774}
775
776/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000777static var *setvar_i(var *v, double value)
778{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000779 clrvar(v);
780 v->type |= VF_NUMBER;
781 v->number = value;
782 handle_special(v);
783 return v;
784}
785
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000786static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000787{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000788 /* if v is numeric and has no cached string, convert it to string */
789 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000790 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
791 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000792 v->type |= VF_CACHED;
793 }
794 return (v->string == NULL) ? "" : v->string;
795}
796
Mike Frysinger10a11e22005-09-27 02:23:02 +0000797static double getvar_i(var *v)
798{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000799 char *s;
800
801 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
802 v->number = 0;
803 s = v->string;
804 if (s && *s) {
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000805 v->number = my_strtod(&s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000806 if (v->type & VF_USER) {
807 skip_spaces(&s);
808 if (*s != '\0')
809 v->type &= ~VF_USER;
810 }
811 } else {
812 v->type &= ~VF_USER;
813 }
814 v->type |= VF_CACHED;
815 }
816 return v->number;
817}
818
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000819/* Used for operands of bitwise ops */
820static unsigned long getvar_i_int(var *v)
821{
822 double d = getvar_i(v);
823
824 /* Casting doubles to longs is undefined for values outside
825 * of target type range. Try to widen it as much as possible */
826 if (d >= 0)
827 return (unsigned long)d;
Denis Vlasenko665eaff2008-09-05 04:59:02 +0000828 /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000829 return - (long) (unsigned long) (-d);
830}
831
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000832static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000833{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000834 if (dest != src) {
835 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000836 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000837 dest->number = src->number;
838 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000839 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000840 }
841 handle_special(dest);
842 return dest;
843}
844
Mike Frysinger10a11e22005-09-27 02:23:02 +0000845static var *incvar(var *v)
846{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000847 return setvar_i(v, getvar_i(v) + 1.);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000848}
849
850/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000851static int is_numeric(var *v)
852{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000853 getvar_i(v);
854 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
855}
856
857/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000858static int istrue(var *v)
859{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000860 if (is_numeric(v))
861 return (v->number == 0) ? 0 : 1;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000862 return (v->string && *(v->string)) ? 1 : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000863}
864
Eric Andersenaff114c2004-04-14 17:51:38 +0000865/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000866static var *nvalloc(int n)
867{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000868 nvblock *pb = NULL;
869 var *v, *r;
870 int size;
871
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000872 while (g_cb) {
873 pb = g_cb;
874 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break;
875 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000876 }
877
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000878 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000879 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000880 g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000881 g_cb->size = size;
882 g_cb->pos = g_cb->nv;
883 g_cb->prev = pb;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000884 /*g_cb->next = NULL; - xzalloc did it */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000885 if (pb) pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000886 }
887
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000888 v = r = g_cb->pos;
889 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000890
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000891 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000892 v->type = 0;
893 v->string = NULL;
894 v++;
895 }
896
897 return r;
898}
899
Mike Frysinger10a11e22005-09-27 02:23:02 +0000900static void nvfree(var *v)
901{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000902 var *p;
903
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000904 if (v < g_cb->nv || v >= g_cb->pos)
905 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000906
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000907 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000908 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000909 clear_array(iamarray(p));
910 free(p->x.array->items);
911 free(p->x.array);
912 }
913 if (p->type & VF_WALK)
914 free(p->x.walker);
915
916 clrvar(p);
917 }
918
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000919 g_cb->pos = v;
920 while (g_cb->prev && g_cb->pos == g_cb->nv) {
921 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000922 }
923}
924
925/* ------- awk program text parsing ------- */
926
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000927/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000928 * If token isn't expected, give away. Return token class
929 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000930static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000931{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000932#define concat_inserted (G.next_token__concat_inserted)
933#define save_tclass (G.next_token__save_tclass)
934#define save_info (G.next_token__save_info)
935/* Initialized to TC_OPTERM: */
936#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000937
Denis Vlasenkof782f522007-01-01 23:51:30 +0000938 char *p, *pp, *s;
939 const char *tl;
940 uint32_t tc;
941 const uint32_t *ti;
942 int l;
943
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000944 if (t_rollback) {
945 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000946
947 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000948 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000949 t_tclass = save_tclass;
950 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000951
952 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000953 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000954 readnext:
Glenn L McGrath545106f2002-11-11 06:21:00 +0000955 skip_spaces(&p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000956 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000957 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000958 while (*p != '\n' && *p != '\0')
959 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000960
961 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000962 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000963
964 if (*p == '\0') {
965 tc = TC_EOF;
966
967 } else if (*p == '\"') {
968 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000969 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000970 while (*p != '\"') {
971 if (*p == '\0' || *p == '\n')
972 syntax_error(EMSG_UNEXP_EOS);
973 *(s++) = nextchar(&p);
974 }
975 p++;
976 *s = '\0';
977 tc = TC_STRING;
978
979 } else if ((expected & TC_REGEXP) && *p == '/') {
980 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000981 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000982 while (*p != '/') {
983 if (*p == '\0' || *p == '\n')
984 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +0000985 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000986 if (*s++ == '\\') {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000987 pp = p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000988 *(s-1) = bb_process_escape_sequence((const char **)&p);
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000989 if (*pp == '\\')
990 *s++ = '\\';
991 if (p == pp)
992 *s++ = *p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000993 }
994 }
995 p++;
996 *s = '\0';
997 tc = TC_REGEXP;
998
999 } else if (*p == '.' || isdigit(*p)) {
1000 /* it's a number */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00001001 t_double = my_strtod(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001002 if (*p == '.')
1003 syntax_error(EMSG_UNEXP_TOKEN);
1004 tc = TC_NUMBER;
1005
1006 } else {
1007 /* search for something known */
1008 tl = tokenlist;
1009 tc = 0x00000001;
1010 ti = tokeninfo;
1011 while (*tl) {
1012 l = *(tl++);
1013 if (l == NTCC) {
1014 tc <<= 1;
1015 continue;
1016 }
1017 /* if token class is expected, token
1018 * matches and it's not a longer word,
1019 * then this is what we are looking for
1020 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001021 if ((tc & (expected | TC_WORD | TC_NEWLINE))
1022 && *tl == *p && strncmp(p, tl, l) == 0
1023 && !((tc & TC_WORD) && isalnum_(p[l]))
1024 ) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001025 t_info = *ti;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001026 p += l;
1027 break;
1028 }
1029 ti++;
1030 tl += l;
1031 }
1032
Denis Vlasenkof782f522007-01-01 23:51:30 +00001033 if (!*tl) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001034 /* it's a name (var/array/function),
1035 * otherwise it's something wrong
1036 */
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001037 if (!isalnum_(*p))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001038 syntax_error(EMSG_UNEXP_TOKEN);
1039
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001040 t_string = --p;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001041 while (isalnum_(*(++p))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001042 *(p-1) = *p;
1043 }
1044 *(p-1) = '\0';
1045 tc = TC_VARIABLE;
Bernhard Reutner-Fischerbb204622005-10-17 14:21:06 +00001046 /* also consume whitespace between functionname and bracket */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001047 if (!(expected & TC_VARIABLE))
1048 skip_spaces(&p);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001049 if (*p == '(') {
1050 tc = TC_FUNCTION;
1051 } else {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001052 if (*p == '[') {
1053 p++;
1054 tc = TC_ARRAY;
1055 }
1056 }
1057 }
1058 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001059 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001060
1061 /* skipping newlines in some cases */
1062 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1063 goto readnext;
1064
1065 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001066 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001067 concat_inserted = TRUE;
1068 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001069 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001070 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001071 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001072 }
1073
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001074 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001075 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001076 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001077
1078 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001079 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001080 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001081 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001082
1083 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001084#undef concat_inserted
1085#undef save_tclass
1086#undef save_info
1087#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001088}
1089
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001090static void rollback_token(void)
1091{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001092 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001093}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001094
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001095static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001096{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001097 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001098
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001099 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001100 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001101 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001102 return n;
1103}
1104
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001105static node *mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001106{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001107 n->info = OC_REGEXP;
1108 n->l.re = re;
1109 n->r.ire = re + 1;
1110 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001111 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001112
1113 return n;
1114}
1115
Mike Frysinger10a11e22005-09-27 02:23:02 +00001116static node *condition(void)
1117{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001118 next_token(TC_SEQSTART);
1119 return parse_expr(TC_SEQTERM);
1120}
1121
1122/* parse expression terminated by given argument, return ptr
1123 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001124static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001125{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001126 node sn;
1127 node *cn = &sn;
1128 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001129 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001130 var *v;
1131
1132 sn.info = PRIMASK;
1133 sn.r.n = glptr = NULL;
1134 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1135
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001136 while (!((tc = next_token(xtc)) & iexp)) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001137 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001138 /* input redirection (<) attached to glptr node */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001139 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001140 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001141 xtc = TC_OPERAND | TC_UOPPRE;
1142 glptr = NULL;
1143
1144 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1145 /* for binary and postfix-unary operators, jump back over
1146 * previous operators with higher priority */
1147 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001148 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1149 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) )
Glenn L McGrath545106f2002-11-11 06:21:00 +00001150 vn = vn->a.n;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001151 if ((t_info & OPCLSMASK) == OC_TERNARY)
1152 t_info += P(6);
1153 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001154 cn->a.n = vn->a.n;
1155 if (tc & TC_BINOP) {
1156 cn->l.n = vn;
1157 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001158 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001159 /* it's a pipe */
1160 next_token(TC_GETLINE);
1161 /* give maximum priority to this pipe */
1162 cn->info &= ~PRIMASK;
1163 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1164 }
1165 } else {
1166 cn->r.n = vn;
1167 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1168 }
1169 vn->a.n = cn;
1170
1171 } else {
1172 /* for operands and prefix-unary operators, attach them
1173 * to last node */
1174 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001175 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001176 cn->a.n = vn;
1177 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1178 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001179 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001180 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001181 * only simple tclasses should be used! */
1182 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001183 case TC_VARIABLE:
1184 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001185 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001186 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001187 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001188 cn->info = OC_FNARG;
1189 cn->l.i = v->x.aidx;
1190 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001191 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001192 }
1193 if (tc & TC_ARRAY) {
1194 cn->info |= xS;
1195 cn->r.n = parse_expr(TC_ARRTERM);
1196 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001197 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001198
Denis Vlasenkof782f522007-01-01 23:51:30 +00001199 case TC_NUMBER:
1200 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001201 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001202 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001203 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001204 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001205 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001206 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001207 break;
1208
Denis Vlasenkof782f522007-01-01 23:51:30 +00001209 case TC_REGEXP:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001210 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001211 break;
1212
Denis Vlasenkof782f522007-01-01 23:51:30 +00001213 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001214 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001215 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001216 cn->l.n = condition();
1217 break;
1218
Denis Vlasenkof782f522007-01-01 23:51:30 +00001219 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001220 cn = vn->r.n = parse_expr(TC_SEQTERM);
1221 cn->a.n = vn;
1222 break;
1223
Denis Vlasenkof782f522007-01-01 23:51:30 +00001224 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001225 glptr = cn;
1226 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1227 break;
1228
Denis Vlasenkof782f522007-01-01 23:51:30 +00001229 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001230 cn->l.n = condition();
1231 break;
1232 }
1233 }
1234 }
1235 }
1236 return sn.r.n;
1237}
1238
1239/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001240static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001241{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001242 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001243
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001244 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001245 seq->first = seq->last = new_node(0);
1246
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001247 if (seq->programname != g_progname) {
1248 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001249 n = chain_node(OC_NEWSOURCE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001250 n->l.s = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001251 }
1252
1253 n = seq->last;
1254 n->info = info;
1255 seq->last = n->a.n = new_node(OC_DONE);
1256
1257 return n;
1258}
1259
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001260static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001261{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001262 node *n;
1263
1264 n = chain_node(info);
1265 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001266 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001267 rollback_token();
1268}
1269
Mike Frysinger10a11e22005-09-27 02:23:02 +00001270static node *chain_loop(node *nn)
1271{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001272 node *n, *n2, *save_brk, *save_cont;
1273
1274 save_brk = break_ptr;
1275 save_cont = continue_ptr;
1276
1277 n = chain_node(OC_BR | Vx);
1278 continue_ptr = new_node(OC_EXEC);
1279 break_ptr = new_node(OC_EXEC);
1280 chain_group();
1281 n2 = chain_node(OC_EXEC | Vx);
1282 n2->l.n = nn;
1283 n2->a.n = n;
1284 continue_ptr->a.n = n2;
1285 break_ptr->a.n = n->r.n = seq->last;
1286
1287 continue_ptr = save_cont;
1288 break_ptr = save_brk;
1289
1290 return n;
1291}
1292
1293/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001294static void chain_group(void)
1295{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001296 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001297 node *n, *n2, *n3;
1298
1299 do {
1300 c = next_token(TC_GRPSEQ);
1301 } while (c & TC_NEWLINE);
1302
1303 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001304 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001305 if (t_tclass & TC_NEWLINE) continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001306 rollback_token();
1307 chain_group();
1308 }
1309 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1310 rollback_token();
1311 chain_expr(OC_EXEC | Vx);
1312 } else { /* TC_STATEMNT */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001313 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001314 case ST_IF:
1315 n = chain_node(OC_BR | Vx);
1316 n->l.n = condition();
1317 chain_group();
1318 n2 = chain_node(OC_EXEC);
1319 n->r.n = seq->last;
1320 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001321 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001322 n2->a.n = seq->last;
1323 } else {
1324 rollback_token();
1325 }
1326 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001327
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001328 case ST_WHILE:
1329 n2 = condition();
1330 n = chain_loop(NULL);
1331 n->l.n = n2;
1332 break;
1333
1334 case ST_DO:
1335 n2 = chain_node(OC_EXEC);
1336 n = chain_loop(NULL);
1337 n2->a.n = n->a.n;
1338 next_token(TC_WHILE);
1339 n->l.n = condition();
1340 break;
1341
1342 case ST_FOR:
1343 next_token(TC_SEQSTART);
1344 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001345 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001346 if ((n2->info & OPCLSMASK) != OC_IN)
1347 syntax_error(EMSG_UNEXP_TOKEN);
1348 n = chain_node(OC_WALKINIT | VV);
1349 n->l.n = n2->l.n;
1350 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001351 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001352 n->info = OC_WALKNEXT | Vx;
1353 n->l.n = n2->l.n;
1354 } else { /* for (;;) */
1355 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001356 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001357 n2 = parse_expr(TC_SEMICOL);
1358 n3 = parse_expr(TC_SEQTERM);
1359 n = chain_loop(n3);
1360 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001361 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001362 n->info = OC_EXEC;
1363 }
1364 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001365
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001366 case OC_PRINT:
1367 case OC_PRINTF:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001368 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001369 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001370 if (t_tclass & TC_OUTRDR) {
1371 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001372 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1373 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001374 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001375 rollback_token();
1376 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001377
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001378 case OC_BREAK:
1379 n = chain_node(OC_EXEC);
1380 n->a.n = break_ptr;
1381 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001382
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001383 case OC_CONTINUE:
1384 n = chain_node(OC_EXEC);
1385 n->a.n = continue_ptr;
1386 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001387
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001388 /* delete, next, nextfile, return, exit */
1389 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001390 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001391 }
1392 }
1393}
1394
Mike Frysinger10a11e22005-09-27 02:23:02 +00001395static void parse_program(char *p)
1396{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001397 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001398 node *cn;
1399 func *f;
1400 var *v;
1401
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001402 g_pos = p;
1403 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001404 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001405 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001406
1407 if (tclass & TC_OPTERM)
1408 continue;
1409
1410 seq = &mainseq;
1411 if (tclass & TC_BEGIN) {
1412 seq = &beginseq;
1413 chain_group();
1414
1415 } else if (tclass & TC_END) {
1416 seq = &endseq;
1417 chain_group();
1418
1419 } else if (tclass & TC_FUNCDECL) {
1420 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001421 g_pos++;
1422 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001423 f->body.first = NULL;
1424 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001425 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001426 v = findvar(ahash, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001427 v->x.aidx = (f->nargs)++;
1428
1429 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1430 break;
1431 }
1432 seq = &(f->body);
1433 chain_group();
1434 clear_array(ahash);
1435
1436 } else if (tclass & TC_OPSEQ) {
1437 rollback_token();
1438 cn = chain_node(OC_TEST);
1439 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001440 if (t_tclass & TC_GRPSTART) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001441 rollback_token();
1442 chain_group();
1443 } else {
1444 chain_node(OC_PRINT);
1445 }
1446 cn->r.n = mainseq.last;
1447
1448 } else /* if (tclass & TC_GRPSTART) */ {
1449 rollback_token();
1450 chain_group();
1451 }
1452 }
1453}
1454
1455
1456/* -------- program execution part -------- */
1457
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001458static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001459{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001460 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001461 node *n;
1462
1463 re = &spl->re[0];
1464 ire = &spl->re[1];
1465 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001466 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001467 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001468 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001469 }
Rob Landleya3896512006-05-07 20:20:34 +00001470 if (strlen(s) > 1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001471 mk_re_node(s, n, re);
1472 } else {
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001473 n->info = (uint32_t) *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001474 }
1475
1476 return n;
1477}
1478
1479/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001480 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001481 * be later regfree'd manually
1482 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001483static regex_t *as_regex(node *op, regex_t *preg)
1484{
Denis Vlasenko7a676642009-03-15 22:20:31 +00001485 int cflags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001486 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001487 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001488
1489 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1490 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001491 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001492 v = nvalloc(1);
1493 s = getvar_s(evaluate(op, v));
Denis Vlasenko7a676642009-03-15 22:20:31 +00001494
1495 cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED;
1496 /* Testcase where REG_EXTENDED fails (unpaired '{'):
1497 * echo Hi | awk 'gsub("@(samp|code|file)\{","");'
1498 * gawk 3.1.5 eats this. We revert to ~REG_EXTENDED
1499 * (maybe gsub is not supposed to use REG_EXTENDED?).
1500 */
1501 if (regcomp(preg, s, cflags)) {
1502 cflags &= ~REG_EXTENDED;
1503 xregcomp(preg, s, cflags);
1504 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001505 nvfree(v);
1506 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001507}
1508
1509/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001510static void qrealloc(char **b, int n, int *size)
1511{
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001512 if (!*b || n >= *size) {
1513 *size = n + (n>>1) + 80;
1514 *b = xrealloc(*b, *size);
1515 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001516}
1517
1518/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001519static void fsrealloc(int size)
1520{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001521 int i;
1522
1523 if (size >= maxfields) {
1524 i = maxfields;
1525 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001526 Fields = xrealloc(Fields, maxfields * sizeof(var));
1527 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001528 Fields[i].type = VF_SPECIAL;
1529 Fields[i].string = NULL;
1530 }
1531 }
1532
1533 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001534 for (i = size; i < nfields; i++) {
1535 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001536 }
1537 }
1538 nfields = size;
1539}
1540
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001541static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001542{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001543 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001544 char c[4];
1545 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001546 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001547
1548 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001549 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1550 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001551
1552 c[0] = c[1] = (char)spl->info;
1553 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001554 if (*getvar_s(intvar[RS]) == '\0')
1555 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001556
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001557 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1558 if (!*s)
1559 return n; /* "": zero fields */
1560 n++; /* at least one field will be there */
1561 do {
1562 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001563 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1564 && pmatch[0].rm_so <= l
1565 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001566 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001567 if (pmatch[0].rm_eo == 0) {
1568 l++;
1569 pmatch[0].rm_eo++;
1570 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001571 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001572 } else {
1573 pmatch[0].rm_eo = l;
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001574 if (s[l])
1575 pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001576 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001577 memcpy(s1, s, l);
Denis Vlasenko67b5eeb2009-04-12 13:54:13 +00001578 /* make sure we remove *all* of the separator chars */
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001579 do {
1580 s1[l] = '\0';
1581 } while (++l < pmatch[0].rm_eo);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001582 nextword(&s1);
1583 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001584 } while (*s);
1585 return n;
1586 }
1587 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001588 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001589 *s1++ = *s++;
1590 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001591 n++;
1592 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001593 return n;
1594 }
1595 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001596 if (icase) {
1597 c[0] = toupper(c[0]);
1598 c[1] = tolower(c[1]);
1599 }
1600 if (*s1) n++;
1601 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001602 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001603 n++;
1604 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001605 return n;
1606 }
1607 /* space split */
1608 while (*s) {
1609 s = skip_whitespace(s);
1610 if (!*s) break;
1611 n++;
1612 while (*s && !isspace(*s))
1613 *s1++ = *s++;
1614 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001615 }
1616 return n;
1617}
1618
Mike Frysinger10a11e22005-09-27 02:23:02 +00001619static void split_f0(void)
1620{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001621/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001622#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001623
Glenn L McGrath545106f2002-11-11 06:21:00 +00001624 int i, n;
1625 char *s;
1626
1627 if (is_f0_split)
1628 return;
1629
1630 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001631 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001632 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001633 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001634 fsrealloc(n);
1635 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001636 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001637 Fields[i].string = nextword(&s);
1638 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1639 }
1640
1641 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001642 clrvar(intvar[NF]);
1643 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1644 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001645#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001646}
1647
1648/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001649static void handle_special(var *v)
1650{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001651 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001652 char *b;
1653 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001654 int sl, l, len, i, bsize;
1655
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001656 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001657 return;
1658
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001659 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001660 n = (int)getvar_i(v);
1661 fsrealloc(n);
1662
1663 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001664 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001665 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001666 b = NULL;
1667 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001668 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001669 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001670 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001671 if (b) {
1672 memcpy(b+len, sep, sl);
1673 len += sl;
1674 }
1675 qrealloc(&b, len+l+sl, &bsize);
1676 memcpy(b+len, s, l);
1677 len += l;
1678 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001679 if (b)
1680 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001681 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001682 is_f0_split = TRUE;
1683
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001684 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001685 is_f0_split = FALSE;
1686
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001687 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001688 mk_splitter(getvar_s(v), &fsplitter);
1689
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001690 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001691 mk_splitter(getvar_s(v), &rsplitter);
1692
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001693 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001694 icase = istrue(v);
1695
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001696 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001697 n = getvar_i(intvar[NF]);
1698 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001699 /* right here v is invalid. Just to note... */
1700 }
1701}
1702
1703/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001704static node *nextarg(node **pn)
1705{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001706 node *n;
1707
1708 n = *pn;
1709 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1710 *pn = n->r.n;
1711 n = n->l.n;
1712 } else {
1713 *pn = NULL;
1714 }
1715 return n;
1716}
1717
Mike Frysinger10a11e22005-09-27 02:23:02 +00001718static void hashwalk_init(var *v, xhash *array)
1719{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001720 char **w;
1721 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001722 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001723
1724 if (v->type & VF_WALK)
1725 free(v->x.walker);
1726
1727 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001728 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001729 w[0] = w[1] = (char *)(w + 2);
1730 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001731 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001732 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001733 strcpy(*w, hi->name);
1734 nextword(w);
1735 hi = hi->next;
1736 }
1737 }
1738}
1739
Mike Frysinger10a11e22005-09-27 02:23:02 +00001740static int hashwalk_next(var *v)
1741{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001742 char **w;
1743
1744 w = v->x.walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001745 if (w[1] == w[0])
Glenn L McGrath545106f2002-11-11 06:21:00 +00001746 return FALSE;
1747
1748 setvar_s(v, nextword(w+1));
1749 return TRUE;
1750}
1751
1752/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001753static int ptest(node *pattern)
1754{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001755 /* ptest__v is "static": to save stack space? */
1756 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001757}
1758
1759/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001760static int awk_getline(rstream *rsm, var *v)
1761{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001762 char *b;
1763 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001764 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001765 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001766 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001767
1768 /* we're using our own buffer since we need access to accumulating
1769 * characters
1770 */
1771 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001772 m = rsm->buffer;
1773 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001774 p = rsm->pos;
1775 size = rsm->size;
1776 c = (char) rsplitter.n.info;
1777 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001778
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001779 if (!m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001780 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001781 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001782 so = eo = p;
1783 r = 1;
1784 if (p > 0) {
1785 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1786 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001787 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001788 so = pmatch[0].rm_so;
1789 eo = pmatch[0].rm_eo;
1790 if (b[eo] != '\0')
1791 break;
1792 }
1793 } else if (c != '\0') {
1794 s = strchr(b+pp, c);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001795 if (!s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001796 if (s) {
1797 so = eo = s-b;
1798 eo++;
1799 break;
1800 }
1801 } else {
1802 while (b[rp] == '\n')
1803 rp++;
1804 s = strstr(b+rp, "\n\n");
1805 if (s) {
1806 so = eo = s-b;
1807 while (b[eo] == '\n') eo++;
1808 if (b[eo] != '\0')
1809 break;
1810 }
1811 }
1812 }
1813
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001814 if (a > 0) {
1815 memmove(m, (const void *)(m+a), p+1);
1816 b = m;
1817 a = 0;
1818 }
1819
1820 qrealloc(&m, a+p+128, &size);
1821 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001822 pp = p;
1823 p += safe_read(fd, b+p, size-p-1);
1824 if (p < pp) {
1825 p = 0;
1826 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001827 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001828 }
1829 b[p] = '\0';
1830
1831 } while (p > pp);
1832
1833 if (p == 0) {
1834 r--;
1835 } else {
1836 c = b[so]; b[so] = '\0';
1837 setvar_s(v, b+rp);
1838 v->type |= VF_USER;
1839 b[so] = c;
1840 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001841 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001842 b[eo] = c;
1843 }
1844
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001845 rsm->buffer = m;
1846 rsm->adv = a + eo;
1847 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001848 rsm->size = size;
1849
1850 return r;
1851}
1852
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001853static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001854{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001855 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001856 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001857 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001858
1859 if (int_as_int && n == (int)n) {
1860 r = snprintf(b, size, "%d", (int)n);
1861 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001862 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001863 if (strchr("diouxX", c)) {
1864 r = snprintf(b, size, format, (int)n);
1865 } else if (strchr("eEfgG", c)) {
1866 r = snprintf(b, size, format, n);
1867 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001868 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001869 }
1870 }
1871 return r;
1872}
1873
Glenn L McGrath545106f2002-11-11 06:21:00 +00001874/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001875static char *awk_printf(node *n)
1876{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001877 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001878 char *fmt, *s, *f;
1879 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001880 int i, j, incr, bsize;
1881 char c, c1;
1882 var *v, *arg;
1883
1884 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001885 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001886
1887 i = 0;
1888 while (*f) {
1889 s = f;
1890 while (*f && (*f != '%' || *(++f) == '%'))
1891 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001892 while (*f && !isalpha(*f)) {
1893 if (*f == '*')
1894 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001895 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001896 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001897
1898 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001899 qrealloc(&b, incr + i, &bsize);
1900 c = *f;
1901 if (c != '\0') f++;
1902 c1 = *f;
1903 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001904 arg = evaluate(nextarg(&n), v);
1905
1906 j = i;
1907 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001908 i += sprintf(b+i, s, is_numeric(arg) ?
1909 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001910 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001911 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001912 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001913 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001914 } else {
1915 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1916 }
1917 *f = c1;
1918
1919 /* if there was an error while sprintf, return value is negative */
1920 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001921 }
1922
Denis Vlasenkof782f522007-01-01 23:51:30 +00001923 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001924 free(fmt);
1925 nvfree(v);
1926 b[i] = '\0';
1927 return b;
1928}
1929
1930/* common substitution routine
1931 * replace (nm) substring of (src) that match (n) with (repl), store
1932 * result into (dest), return number of substitutions. If nm=0, replace
1933 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1934 * subexpression matching (\1-\9)
1935 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001936static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001937{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001938 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001939 const char *s;
1940 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001941 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1942 regmatch_t pmatch[10];
1943 regex_t sreg, *re;
1944
1945 re = as_regex(rn, &sreg);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001946 if (!src) src = intvar[F0];
1947 if (!dest) dest = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001948
1949 i = di = 0;
1950 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001951 rl = strlen(repl);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001952 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001953 so = pmatch[0].rm_so;
1954 eo = pmatch[0].rm_eo;
1955
1956 qrealloc(&ds, di + eo + rl, &dssize);
1957 memcpy(ds + di, sp, eo);
1958 di += eo;
1959 if (++i >= nm) {
1960 /* replace */
1961 di -= (eo - so);
1962 nbs = 0;
1963 for (s = repl; *s; s++) {
1964 ds[di++] = c = *s;
1965 if (c == '\\') {
1966 nbs++;
1967 continue;
1968 }
1969 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1970 di -= ((nbs + 3) >> 1);
1971 j = 0;
1972 if (c != '&') {
1973 j = c - '0';
1974 nbs++;
1975 }
1976 if (nbs % 2) {
1977 ds[di++] = c;
1978 } else {
1979 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1980 qrealloc(&ds, di + rl + n, &dssize);
1981 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1982 di += n;
1983 }
1984 }
1985 nbs = 0;
1986 }
1987 }
1988
1989 sp += eo;
1990 if (i == nm) break;
1991 if (eo == so) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001992 ds[di] = *sp++;
1993 if (!ds[di++]) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001994 }
1995 }
1996
1997 qrealloc(&ds, di + strlen(sp), &dssize);
1998 strcpy(ds + di, sp);
1999 setvar_p(dest, ds);
2000 if (re == &sreg) regfree(re);
2001 return i;
2002}
2003
Mike Frysinger10a11e22005-09-27 02:23:02 +00002004static var *exec_builtin(node *op, var *res)
2005{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002006#define tspl (G.exec_builtin__tspl)
2007
Glenn L McGrath545106f2002-11-11 06:21:00 +00002008 int (*to_xxx)(int);
2009 var *tv;
2010 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002011 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002012 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002013 regmatch_t pmatch[2];
2014 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002015 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002016 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002017 int nargs;
2018 time_t tt;
2019 char *s, *s1;
2020 int i, l, ll, n;
2021
2022 tv = nvalloc(4);
2023 isr = info = op->info;
2024 op = op->l.n;
2025
2026 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002027 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002028 an[i] = nextarg(&op);
2029 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
2030 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
2031 isr >>= 1;
2032 }
2033
2034 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002035 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002036 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002037
2038 switch (info & OPNMASK) {
2039
Denis Vlasenkof782f522007-01-01 23:51:30 +00002040 case B_a2:
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002041#if ENABLE_FEATURE_AWK_LIBM
Denis Vlasenko37890e22008-10-21 12:59:34 +00002042 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002043#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002044 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002045#endif
2046 break;
2047
Denis Vlasenkof782f522007-01-01 23:51:30 +00002048 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002049 if (nargs > 2) {
2050 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2051 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2052 } else {
2053 spl = &fsplitter.n;
2054 }
2055
2056 n = awk_split(as[0], spl, &s);
2057 s1 = s;
2058 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002059 for (i = 1; i <= n; i++)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002060 setari_u(av[1], i, nextword(&s1));
2061 free(s);
2062 setvar_i(res, n);
2063 break;
2064
Denis Vlasenkof782f522007-01-01 23:51:30 +00002065 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00002066 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002067 i = getvar_i(av[1]) - 1;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002068 if (i > l) i = l;
2069 if (i < 0) i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002070 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002071 if (n < 0) n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002072 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002073 setvar_p(res, s);
2074 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002075
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002076 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2077 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002078 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002079 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002080 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002081
Denis Vlasenkof782f522007-01-01 23:51:30 +00002082 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002083 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002084 break;
2085
Denis Vlasenkof782f522007-01-01 23:51:30 +00002086 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002087 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002088 break;
2089
Denis Vlasenkof782f522007-01-01 23:51:30 +00002090 case B_or:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002091 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002092 break;
2093
Denis Vlasenkof782f522007-01-01 23:51:30 +00002094 case B_rs:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002095 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002096 break;
2097
Denis Vlasenkof782f522007-01-01 23:51:30 +00002098 case B_xo:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002099 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002100 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002101
Denis Vlasenkof782f522007-01-01 23:51:30 +00002102 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002103 to_xxx = tolower;
2104 goto lo_cont;
2105
Denis Vlasenkof782f522007-01-01 23:51:30 +00002106 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002107 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002108 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00002109 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002110 while (*s1) {
2111 *s1 = (*to_xxx)(*s1);
2112 s1++;
2113 }
2114 setvar_p(res, s);
2115 break;
2116
Denis Vlasenkof782f522007-01-01 23:51:30 +00002117 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002118 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002119 ll = strlen(as[1]);
2120 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002121 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002122 if (!icase) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002123 s = strstr(as[0], as[1]);
2124 if (s) n = (s - as[0]) + 1;
2125 } else {
2126 /* this piece of code is terribly slow and
2127 * really should be rewritten
2128 */
2129 for (i=0; i<=l; i++) {
2130 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2131 n = i+1;
2132 break;
2133 }
2134 }
2135 }
2136 }
2137 setvar_i(res, n);
2138 break;
2139
Denis Vlasenkof782f522007-01-01 23:51:30 +00002140 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002141 if (nargs > 1)
2142 tt = getvar_i(av[1]);
2143 else
2144 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002145 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002146 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002147 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2148 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002149 g_buf[i] = '\0';
2150 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002151 break;
2152
Denis Vlasenkof782f522007-01-01 23:51:30 +00002153 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002154 re = as_regex(an[1], &sreg);
2155 n = regexec(re, as[0], 1, pmatch, 0);
2156 if (n == 0) {
2157 pmatch[0].rm_so++;
2158 pmatch[0].rm_eo++;
2159 } else {
2160 pmatch[0].rm_so = 0;
2161 pmatch[0].rm_eo = -1;
2162 }
2163 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2164 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2165 setvar_i(res, pmatch[0].rm_so);
2166 if (re == &sreg) regfree(re);
2167 break;
2168
Denis Vlasenkof782f522007-01-01 23:51:30 +00002169 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002170 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2171 break;
2172
Denis Vlasenkof782f522007-01-01 23:51:30 +00002173 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002174 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2175 break;
2176
Denis Vlasenkof782f522007-01-01 23:51:30 +00002177 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002178 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2179 break;
2180 }
2181
2182 nvfree(tv);
2183 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002184#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002185}
2186
2187/*
2188 * Evaluate node - the heart of the program. Supplied with subtree
2189 * and place where to store result. returns ptr to result.
2190 */
2191#define XC(n) ((n) >> 8)
2192
Mike Frysinger10a11e22005-09-27 02:23:02 +00002193static var *evaluate(node *op, var *res)
2194{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002195/* This procedure is recursive so we should count every byte */
2196#define fnargs (G.evaluate__fnargs)
2197/* seed is initialized to 1 */
2198#define seed (G.evaluate__seed)
2199#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002200
Glenn L McGrath545106f2002-11-11 06:21:00 +00002201 node *op1;
2202 var *v1;
2203 union {
2204 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002205 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002206 double d;
2207 int i;
2208 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002209 uint32_t opinfo;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002210 int opn;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002211 union {
2212 char *s;
2213 rstream *rsm;
2214 FILE *F;
2215 var *v;
2216 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002217 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002218 } X;
2219
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002220 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002221 return setvar_s(res, NULL);
2222
2223 v1 = nvalloc(2);
2224
2225 while (op) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002226 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002227 opn = (opinfo & OPNMASK);
2228 g_lineno = op->lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002229
Mike Frysingerde2b9382005-09-27 03:18:00 +00002230 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002231 op1 = op->l.n;
2232 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2233 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2234 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2235 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2236 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2237
2238 switch (XC(opinfo & OPCLSMASK)) {
2239
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002240 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002241
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002242 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002243 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002244 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2245 /* it's range pattern */
2246 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2247 op->info |= OF_CHECKED;
2248 if (ptest(op1->r.n))
2249 op->info &= ~OF_CHECKED;
2250
2251 op = op->a.n;
2252 } else {
2253 op = op->r.n;
2254 }
2255 } else {
2256 op = (ptest(op1)) ? op->a.n : op->r.n;
2257 }
2258 break;
2259
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002260 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002261 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002262 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002263
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002264 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002265 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002266 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002267 break;
2268
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002269 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002270 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002271 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002272 break;
2273
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002274 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002275 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002276 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2277 break;
2278
Denis Vlasenkof782f522007-01-01 23:51:30 +00002279 case XC( OC_PRINT ):
2280 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002281 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002282 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002283 X.rsm = newfile(R.s);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002284 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002285 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002286 X.rsm->F = popen(R.s, "w");
2287 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002288 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002289 X.rsm->is_pipe = 1;
2290 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002291 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002292 }
2293 }
2294 X.F = X.rsm->F;
2295 }
2296
2297 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002298 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002299 fputs(getvar_s(intvar[F0]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002300 } else {
2301 while (op1) {
2302 L.v = evaluate(nextarg(&op1), v1);
2303 if (L.v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002304 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002305 getvar_i(L.v), TRUE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002306 fputs(g_buf, X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002307 } else {
2308 fputs(getvar_s(L.v), X.F);
2309 }
2310
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002311 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002312 }
2313 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002314 fputs(getvar_s(intvar[ORS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002315
2316 } else { /* OC_PRINTF */
2317 L.s = awk_printf(op1);
2318 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002319 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002320 }
2321 fflush(X.F);
2322 break;
2323
Denis Vlasenkof782f522007-01-01 23:51:30 +00002324 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002325 X.info = op1->info & OPCLSMASK;
2326 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002327 R.v = op1->l.v;
2328 } else if (X.info == OC_FNARG) {
2329 R.v = &fnargs[op1->l.i];
2330 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002331 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002332 }
2333
Mike Frysingerde2b9382005-09-27 03:18:00 +00002334 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002335 clrvar(L.v);
2336 L.s = getvar_s(evaluate(op1->r.n, v1));
2337 hash_remove(iamarray(R.v), L.s);
2338 } else {
2339 clear_array(iamarray(R.v));
2340 }
2341 break;
2342
Denis Vlasenkof782f522007-01-01 23:51:30 +00002343 case XC( OC_NEWSOURCE ):
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002344 g_progname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002345 break;
2346
Denis Vlasenkof782f522007-01-01 23:51:30 +00002347 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002348 copyvar(res, L.v);
2349 break;
2350
Denis Vlasenkof782f522007-01-01 23:51:30 +00002351 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002352 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002353 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002354 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002355 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002356 clrvar(res);
2357 break;
2358
Denis Vlasenkof782f522007-01-01 23:51:30 +00002359 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002360 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002361
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002362 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002363
Denis Vlasenkof782f522007-01-01 23:51:30 +00002364 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002365 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002366 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002367 split_f0();
2368 goto v_cont;
2369
Denis Vlasenkof782f522007-01-01 23:51:30 +00002370 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002371 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002372 v_cont:
2373 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002374 break;
2375
Denis Vlasenkof782f522007-01-01 23:51:30 +00002376 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002377 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2378 break;
2379
Denis Vlasenkof782f522007-01-01 23:51:30 +00002380 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002381 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002382 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002383 goto re_cont;
2384
Denis Vlasenkof782f522007-01-01 23:51:30 +00002385 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002386 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002387 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002388 X.re = as_regex(op1, &sreg);
2389 R.i = regexec(X.re, L.s, 0, NULL, 0);
2390 if (X.re == &sreg) regfree(X.re);
2391 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2392 break;
2393
Denis Vlasenkof782f522007-01-01 23:51:30 +00002394 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002395 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002396 if (R.v == v1+1 && R.v->string) {
2397 res = setvar_p(L.v, R.v->string);
2398 R.v->string = NULL;
2399 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002400 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002401 }
2402 break;
2403
Denis Vlasenkof782f522007-01-01 23:51:30 +00002404 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002405 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002406 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002407 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2408 break;
2409
Denis Vlasenkof782f522007-01-01 23:51:30 +00002410 case XC( OC_FUNC ):
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002411 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002412 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002413
2414 X.v = R.v = nvalloc(op->r.f->nargs+1);
2415 while (op1) {
2416 L.v = evaluate(nextarg(&op1), v1);
2417 copyvar(R.v, L.v);
2418 R.v->type |= VF_CHILD;
2419 R.v->x.parent = L.v;
2420 if (++R.v - X.v >= op->r.f->nargs)
2421 break;
2422 }
2423
2424 R.v = fnargs;
2425 fnargs = X.v;
2426
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002427 L.s = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002428 res = evaluate(op->r.f->body.first, res);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002429 g_progname = L.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002430
2431 nvfree(fnargs);
2432 fnargs = R.v;
2433 break;
2434
Denis Vlasenkof782f522007-01-01 23:51:30 +00002435 case XC( OC_GETLINE ):
2436 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002437 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002438 X.rsm = newfile(L.s);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002439 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002440 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2441 X.rsm->F = popen(L.s, "r");
2442 X.rsm->is_pipe = TRUE;
2443 } else {
Denis Vlasenko5415c852008-07-21 23:05:26 +00002444 X.rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002445 }
2446 }
2447 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002448 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002449 X.rsm = iF;
2450 }
2451
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002452 if (!X.rsm->F) {
2453 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002454 setvar_i(res, -1);
2455 break;
2456 }
2457
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002458 if (!op->r.n)
2459 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002460
2461 L.i = awk_getline(X.rsm, R.v);
2462 if (L.i > 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002463 if (!op1) {
2464 incvar(intvar[FNR]);
2465 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002466 }
2467 }
2468 setvar_i(res, L.i);
2469 break;
2470
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002471 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002472 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002473 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002474
Denis Vlasenkof782f522007-01-01 23:51:30 +00002475 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002476 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002477 break;
2478
Denis Vlasenkof782f522007-01-01 23:51:30 +00002479 case F_rn:
2480 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002481 break;
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002482#if ENABLE_FEATURE_AWK_LIBM
Denis Vlasenkof782f522007-01-01 23:51:30 +00002483 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002484 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002485 break;
2486
Denis Vlasenkof782f522007-01-01 23:51:30 +00002487 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002488 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002489 break;
2490
Denis Vlasenkof782f522007-01-01 23:51:30 +00002491 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002492 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002493 break;
2494
Denis Vlasenkof782f522007-01-01 23:51:30 +00002495 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002496 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002497 break;
2498
Denis Vlasenkof782f522007-01-01 23:51:30 +00002499 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002500 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002501 break;
2502#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002503 case F_co:
2504 case F_ex:
2505 case F_lg:
2506 case F_si:
2507 case F_sq:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002508 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002509 break;
2510#endif
Denis Vlasenkof782f522007-01-01 23:51:30 +00002511 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002512 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002513 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002514 srand(seed);
2515 break;
2516
Denis Vlasenkof782f522007-01-01 23:51:30 +00002517 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002518 R.d = time(NULL);
2519 break;
2520
Denis Vlasenkof782f522007-01-01 23:51:30 +00002521 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002522 if (!op1)
2523 L.s = getvar_s(intvar[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002524 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002525 break;
2526
Denis Vlasenkof782f522007-01-01 23:51:30 +00002527 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002528 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002529 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2530 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002531 break;
2532
Denis Vlasenkof782f522007-01-01 23:51:30 +00002533 case F_ff:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002534 if (!op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002535 fflush(stdout);
2536 else {
2537 if (L.s && *L.s) {
2538 X.rsm = newfile(L.s);
2539 fflush(X.rsm->F);
2540 } else {
2541 fflush(NULL);
2542 }
2543 }
2544 break;
2545
Denis Vlasenkof782f522007-01-01 23:51:30 +00002546 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002547 X.rsm = (rstream *)hash_search(fdhash, L.s);
2548 if (X.rsm) {
2549 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002550 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002551 hash_remove(fdhash, L.s);
2552 }
2553 if (R.i != 0)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002554 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002555 R.d = (double)R.i;
2556 break;
2557 }
2558 setvar_i(res, R.d);
2559 break;
2560
Denis Vlasenkof782f522007-01-01 23:51:30 +00002561 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002562 res = exec_builtin(op, res);
2563 break;
2564
Denis Vlasenkof782f522007-01-01 23:51:30 +00002565 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002566 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002567 break;
2568
Denis Vlasenkof782f522007-01-01 23:51:30 +00002569 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002570 X.v = R.v;
2571 L.d = R.d = getvar_i(R.v);
2572 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002573 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002574 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002575 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002576 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002577 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002578 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002579 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002580 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002581 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002582 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002583 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002584 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002585 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002586 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002587 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002588 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002589 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002590 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002591 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002592 setvar_i(X.v, R.d);
2593 }
2594 setvar_i(res, L.d);
2595 break;
2596
Denis Vlasenkof782f522007-01-01 23:51:30 +00002597 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002598 R.i = (int)getvar_i(R.v);
2599 if (R.i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002600 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002601 } else {
2602 split_f0();
2603 if (R.i > nfields)
2604 fsrealloc(R.i);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002605 res = &Fields[R.i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002606 }
2607 break;
2608
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002609 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002610 case XC( OC_CONCAT ):
2611 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002612 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002613 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002614 strcpy(X.s, L.s);
2615 if ((opinfo & OPCLSMASK) == OC_COMMA) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002616 L.s = getvar_s(intvar[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002617 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002618 strcat(X.s, L.s);
2619 }
2620 strcat(X.s, R.s);
2621 setvar_p(res, X.s);
2622 break;
2623
Denis Vlasenkof782f522007-01-01 23:51:30 +00002624 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002625 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2626 break;
2627
Denis Vlasenkof782f522007-01-01 23:51:30 +00002628 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002629 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2630 break;
2631
Denis Vlasenkof782f522007-01-01 23:51:30 +00002632 case XC( OC_BINARY ):
2633 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002634 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002635 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002636 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002637 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002638 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002639 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002640 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002641 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002642 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002643 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002644 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002645 case '/':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002646 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002647 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002648 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002649 case '&':
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002650#if ENABLE_FEATURE_AWK_LIBM
Mike Frysingerde2b9382005-09-27 03:18:00 +00002651 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002652#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002653 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002654#endif
2655 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002656 case '%':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002657 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002658 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002659 break;
2660 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002661 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002662 break;
2663
Denis Vlasenkof782f522007-01-01 23:51:30 +00002664 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002665 if (is_numeric(L.v) && is_numeric(R.v)) {
2666 L.d = getvar_i(L.v) - getvar_i(R.v);
2667 } else {
2668 L.s = getvar_s(L.v);
2669 R.s = getvar_s(R.v);
2670 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2671 }
2672 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002673 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002674 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002675 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002676 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002677 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002678 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002679 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002680 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002681 break;
2682 }
2683 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2684 break;
2685
Denis Vlasenkof782f522007-01-01 23:51:30 +00002686 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002687 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002688 }
2689 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2690 op = op->a.n;
2691 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2692 break;
2693 if (nextrec)
2694 break;
2695 }
2696 nvfree(v1);
2697 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002698#undef fnargs
2699#undef seed
2700#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002701}
2702
2703
2704/* -------- main & co. -------- */
2705
Mike Frysinger10a11e22005-09-27 02:23:02 +00002706static int awk_exit(int r)
2707{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002708 var tv;
2709 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002710 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002711
Denis Vlasenkof782f522007-01-01 23:51:30 +00002712 zero_out_var(&tv);
2713
2714 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002715 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002716 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002717 evaluate(endseq.first, &tv);
2718 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002719
2720 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002721 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002722 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002723 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002724 if (hi->data.rs.F && hi->data.rs.is_pipe)
2725 pclose(hi->data.rs.F);
2726 hi = hi->next;
2727 }
2728 }
2729
2730 exit(r);
2731}
2732
2733/* if expr looks like "var=value", perform assignment and return 1,
2734 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002735static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002736{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002737 char *exprc, *s, *s0, *s1;
2738
Rob Landleyd921b2e2006-08-03 15:41:12 +00002739 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002740 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2741 free(exprc);
2742 return FALSE;
2743 }
2744
2745 *(s++) = '\0';
2746 s0 = s1 = s;
2747 while (*s)
2748 *(s1++) = nextchar(&s);
2749
2750 *s1 = '\0';
2751 setvar_u(newvar(exprc), s0);
2752 free(exprc);
2753 return TRUE;
2754}
2755
2756/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002757static rstream *next_input_file(void)
2758{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002759#define rsm (G.next_input_file__rsm)
2760#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002761
Glenn L McGrath545106f2002-11-11 06:21:00 +00002762 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002763 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002764
2765 if (rsm.F) fclose(rsm.F);
2766 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002767 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002768
2769 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002770 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002771 if (files_happen)
2772 return NULL;
2773 fname = "-";
2774 F = stdin;
2775 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002776 ind = getvar_s(incvar(intvar[ARGIND]));
2777 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002778 if (fname && *fname && !is_assignment(fname))
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002779 F = xfopen_stdin(fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002780 }
2781 } while (!F);
2782
2783 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002784 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002785 rsm.F = F;
2786 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002787#undef rsm
2788#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002789}
2790
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002791int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00002792int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002793{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002794 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002795 char *opt_F, *opt_W;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002796 llist_t *list_v = NULL;
2797 llist_t *list_f = NULL;
2798 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002799 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002800 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002801 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002802 char *vnames = (char *)vNames; /* cheat */
2803 char *vvalues = (char *)vValues;
2804
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002805 INIT_G();
2806
Denis Vlasenko150f4022007-01-13 21:06:21 +00002807 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002808 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2809 if (ENABLE_LOCALE_SUPPORT)
2810 setlocale(LC_NUMERIC, "C");
2811
Denis Vlasenkof782f522007-01-01 23:51:30 +00002812 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002813
2814 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002815 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002816
2817 vhash = hash_init();
2818 ahash = hash_init();
2819 fdhash = hash_init();
2820 fnhash = hash_init();
2821
2822 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002823 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002824 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00002825 if (*vvalues != '\377')
2826 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002827 else
2828 setvar_i(v, 0);
2829
Denis Vlasenkof782f522007-01-01 23:51:30 +00002830 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002831 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002832 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002833 }
2834 }
2835
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002836 handle_special(intvar[FS]);
2837 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002838
Denis Vlasenkof782f522007-01-01 23:51:30 +00002839 newfile("/dev/stdin")->F = stdin;
2840 newfile("/dev/stdout")->F = stdout;
2841 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002842
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002843 /* Huh, people report that sometimes environ is NULL. Oh well. */
2844 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002845 /* environ is writable, thus we don't strdup it needlessly */
2846 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002847 char *s1 = strchr(s, '=');
2848 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002849 *s1 = '\0';
2850 /* Both findvar and setvar_u take const char*
2851 * as 2nd arg -> environment is not trashed */
2852 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
2853 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00002854 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002855 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002856 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
2857 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002858 argv += optind;
2859 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002860 if (opt & 0x1)
2861 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002862 while (list_v) { /* -v */
2863 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002864 bb_show_usage();
2865 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002866 if (list_f) { /* -f */
2867 do {
2868 char *s = NULL;
2869 FILE *from_file;
2870
2871 g_progname = llist_pop(&list_f);
2872 from_file = xfopen_stdin(g_progname);
2873 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002874 for (i = j = 1; j > 0; i += j) {
2875 s = xrealloc(s, i + 4096);
2876 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002877 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002878 s[i] = '\0';
2879 fclose(from_file);
2880 parse_program(s + 1);
2881 free(s);
2882 } while (list_f);
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00002883 argc++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002884 } else { // no -f: take program from 1st parameter
2885 if (!argc)
2886 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002887 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00002888 parse_program(*argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002889 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002890 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002891 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002892
Glenn L McGrath545106f2002-11-11 06:21:00 +00002893 /* fill in ARGV array */
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00002894 setvar_i(intvar[ARGC], argc);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002895 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002896 i = 0;
2897 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002898 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002899
2900 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002901 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002902 awk_exit(EXIT_SUCCESS);
2903
2904 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002905 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002906
2907 /* passing through input files */
2908 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002909 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002910 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002911
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002912 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002913 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002914 incvar(intvar[NR]);
2915 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002916 evaluate(mainseq.first, &tv);
2917
2918 if (nextfile)
2919 break;
2920 }
2921
Denis Vlasenkof782f522007-01-01 23:51:30 +00002922 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002923 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002924
2925 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002926 }
2927
Glenn L McGrath545106f2002-11-11 06:21:00 +00002928 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002929 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002930}