blob: 924cfcfabd17ee5072a20197f3034360075291e5 [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;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001574 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001575 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001576 memcpy(s1, s, l);
Denis Vlasenko67b5eeb2009-04-12 13:54:13 +00001577 /* make sure we remove *all* of the separator chars */
1578 while (l < pmatch[0].rm_eo) {
1579 s1[l++] = '\0';
1580 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001581 nextword(&s1);
1582 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001583 } while (*s);
1584 return n;
1585 }
1586 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001587 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001588 *s1++ = *s++;
1589 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001590 n++;
1591 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001592 return n;
1593 }
1594 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001595 if (icase) {
1596 c[0] = toupper(c[0]);
1597 c[1] = tolower(c[1]);
1598 }
1599 if (*s1) n++;
1600 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001601 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001602 n++;
1603 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001604 return n;
1605 }
1606 /* space split */
1607 while (*s) {
1608 s = skip_whitespace(s);
1609 if (!*s) break;
1610 n++;
1611 while (*s && !isspace(*s))
1612 *s1++ = *s++;
1613 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001614 }
1615 return n;
1616}
1617
Mike Frysinger10a11e22005-09-27 02:23:02 +00001618static void split_f0(void)
1619{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001620/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001621#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001622
Glenn L McGrath545106f2002-11-11 06:21:00 +00001623 int i, n;
1624 char *s;
1625
1626 if (is_f0_split)
1627 return;
1628
1629 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001630 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001631 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001632 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001633 fsrealloc(n);
1634 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001635 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001636 Fields[i].string = nextword(&s);
1637 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1638 }
1639
1640 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001641 clrvar(intvar[NF]);
1642 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1643 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001644#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001645}
1646
1647/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001648static void handle_special(var *v)
1649{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001650 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001651 char *b;
1652 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001653 int sl, l, len, i, bsize;
1654
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001655 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001656 return;
1657
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001658 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001659 n = (int)getvar_i(v);
1660 fsrealloc(n);
1661
1662 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001663 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001664 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001665 b = NULL;
1666 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001667 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001668 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001669 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001670 if (b) {
1671 memcpy(b+len, sep, sl);
1672 len += sl;
1673 }
1674 qrealloc(&b, len+l+sl, &bsize);
1675 memcpy(b+len, s, l);
1676 len += l;
1677 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001678 if (b)
1679 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001680 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001681 is_f0_split = TRUE;
1682
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001683 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001684 is_f0_split = FALSE;
1685
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001686 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001687 mk_splitter(getvar_s(v), &fsplitter);
1688
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001689 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001690 mk_splitter(getvar_s(v), &rsplitter);
1691
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001692 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001693 icase = istrue(v);
1694
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001695 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001696 n = getvar_i(intvar[NF]);
1697 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001698 /* right here v is invalid. Just to note... */
1699 }
1700}
1701
1702/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001703static node *nextarg(node **pn)
1704{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001705 node *n;
1706
1707 n = *pn;
1708 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1709 *pn = n->r.n;
1710 n = n->l.n;
1711 } else {
1712 *pn = NULL;
1713 }
1714 return n;
1715}
1716
Mike Frysinger10a11e22005-09-27 02:23:02 +00001717static void hashwalk_init(var *v, xhash *array)
1718{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001719 char **w;
1720 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001721 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001722
1723 if (v->type & VF_WALK)
1724 free(v->x.walker);
1725
1726 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001727 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001728 w[0] = w[1] = (char *)(w + 2);
1729 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001730 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001731 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001732 strcpy(*w, hi->name);
1733 nextword(w);
1734 hi = hi->next;
1735 }
1736 }
1737}
1738
Mike Frysinger10a11e22005-09-27 02:23:02 +00001739static int hashwalk_next(var *v)
1740{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001741 char **w;
1742
1743 w = v->x.walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001744 if (w[1] == w[0])
Glenn L McGrath545106f2002-11-11 06:21:00 +00001745 return FALSE;
1746
1747 setvar_s(v, nextword(w+1));
1748 return TRUE;
1749}
1750
1751/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001752static int ptest(node *pattern)
1753{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001754 /* ptest__v is "static": to save stack space? */
1755 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001756}
1757
1758/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001759static int awk_getline(rstream *rsm, var *v)
1760{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001761 char *b;
1762 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001763 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001764 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001765 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001766
1767 /* we're using our own buffer since we need access to accumulating
1768 * characters
1769 */
1770 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001771 m = rsm->buffer;
1772 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001773 p = rsm->pos;
1774 size = rsm->size;
1775 c = (char) rsplitter.n.info;
1776 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001777
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001778 if (!m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001779 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001780 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001781 so = eo = p;
1782 r = 1;
1783 if (p > 0) {
1784 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1785 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001786 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001787 so = pmatch[0].rm_so;
1788 eo = pmatch[0].rm_eo;
1789 if (b[eo] != '\0')
1790 break;
1791 }
1792 } else if (c != '\0') {
1793 s = strchr(b+pp, c);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001794 if (!s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001795 if (s) {
1796 so = eo = s-b;
1797 eo++;
1798 break;
1799 }
1800 } else {
1801 while (b[rp] == '\n')
1802 rp++;
1803 s = strstr(b+rp, "\n\n");
1804 if (s) {
1805 so = eo = s-b;
1806 while (b[eo] == '\n') eo++;
1807 if (b[eo] != '\0')
1808 break;
1809 }
1810 }
1811 }
1812
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001813 if (a > 0) {
1814 memmove(m, (const void *)(m+a), p+1);
1815 b = m;
1816 a = 0;
1817 }
1818
1819 qrealloc(&m, a+p+128, &size);
1820 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001821 pp = p;
1822 p += safe_read(fd, b+p, size-p-1);
1823 if (p < pp) {
1824 p = 0;
1825 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001826 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001827 }
1828 b[p] = '\0';
1829
1830 } while (p > pp);
1831
1832 if (p == 0) {
1833 r--;
1834 } else {
1835 c = b[so]; b[so] = '\0';
1836 setvar_s(v, b+rp);
1837 v->type |= VF_USER;
1838 b[so] = c;
1839 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001840 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001841 b[eo] = c;
1842 }
1843
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001844 rsm->buffer = m;
1845 rsm->adv = a + eo;
1846 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001847 rsm->size = size;
1848
1849 return r;
1850}
1851
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001852static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001853{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001854 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001855 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001856 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001857
1858 if (int_as_int && n == (int)n) {
1859 r = snprintf(b, size, "%d", (int)n);
1860 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001861 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001862 if (strchr("diouxX", c)) {
1863 r = snprintf(b, size, format, (int)n);
1864 } else if (strchr("eEfgG", c)) {
1865 r = snprintf(b, size, format, n);
1866 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001867 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001868 }
1869 }
1870 return r;
1871}
1872
Glenn L McGrath545106f2002-11-11 06:21:00 +00001873/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001874static char *awk_printf(node *n)
1875{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001876 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001877 char *fmt, *s, *f;
1878 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001879 int i, j, incr, bsize;
1880 char c, c1;
1881 var *v, *arg;
1882
1883 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001884 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001885
1886 i = 0;
1887 while (*f) {
1888 s = f;
1889 while (*f && (*f != '%' || *(++f) == '%'))
1890 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001891 while (*f && !isalpha(*f)) {
1892 if (*f == '*')
1893 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001894 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001895 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001896
1897 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001898 qrealloc(&b, incr + i, &bsize);
1899 c = *f;
1900 if (c != '\0') f++;
1901 c1 = *f;
1902 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001903 arg = evaluate(nextarg(&n), v);
1904
1905 j = i;
1906 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001907 i += sprintf(b+i, s, is_numeric(arg) ?
1908 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001909 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001910 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001911 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001912 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001913 } else {
1914 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1915 }
1916 *f = c1;
1917
1918 /* if there was an error while sprintf, return value is negative */
1919 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001920 }
1921
Denis Vlasenkof782f522007-01-01 23:51:30 +00001922 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001923 free(fmt);
1924 nvfree(v);
1925 b[i] = '\0';
1926 return b;
1927}
1928
1929/* common substitution routine
1930 * replace (nm) substring of (src) that match (n) with (repl), store
1931 * result into (dest), return number of substitutions. If nm=0, replace
1932 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1933 * subexpression matching (\1-\9)
1934 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001935static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001936{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001937 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001938 const char *s;
1939 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001940 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1941 regmatch_t pmatch[10];
1942 regex_t sreg, *re;
1943
1944 re = as_regex(rn, &sreg);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001945 if (!src) src = intvar[F0];
1946 if (!dest) dest = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001947
1948 i = di = 0;
1949 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001950 rl = strlen(repl);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001951 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001952 so = pmatch[0].rm_so;
1953 eo = pmatch[0].rm_eo;
1954
1955 qrealloc(&ds, di + eo + rl, &dssize);
1956 memcpy(ds + di, sp, eo);
1957 di += eo;
1958 if (++i >= nm) {
1959 /* replace */
1960 di -= (eo - so);
1961 nbs = 0;
1962 for (s = repl; *s; s++) {
1963 ds[di++] = c = *s;
1964 if (c == '\\') {
1965 nbs++;
1966 continue;
1967 }
1968 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1969 di -= ((nbs + 3) >> 1);
1970 j = 0;
1971 if (c != '&') {
1972 j = c - '0';
1973 nbs++;
1974 }
1975 if (nbs % 2) {
1976 ds[di++] = c;
1977 } else {
1978 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1979 qrealloc(&ds, di + rl + n, &dssize);
1980 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1981 di += n;
1982 }
1983 }
1984 nbs = 0;
1985 }
1986 }
1987
1988 sp += eo;
1989 if (i == nm) break;
1990 if (eo == so) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001991 ds[di] = *sp++;
1992 if (!ds[di++]) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001993 }
1994 }
1995
1996 qrealloc(&ds, di + strlen(sp), &dssize);
1997 strcpy(ds + di, sp);
1998 setvar_p(dest, ds);
1999 if (re == &sreg) regfree(re);
2000 return i;
2001}
2002
Mike Frysinger10a11e22005-09-27 02:23:02 +00002003static var *exec_builtin(node *op, var *res)
2004{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002005#define tspl (G.exec_builtin__tspl)
2006
Glenn L McGrath545106f2002-11-11 06:21:00 +00002007 int (*to_xxx)(int);
2008 var *tv;
2009 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002010 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002011 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002012 regmatch_t pmatch[2];
2013 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002014 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002015 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002016 int nargs;
2017 time_t tt;
2018 char *s, *s1;
2019 int i, l, ll, n;
2020
2021 tv = nvalloc(4);
2022 isr = info = op->info;
2023 op = op->l.n;
2024
2025 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002026 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002027 an[i] = nextarg(&op);
2028 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
2029 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
2030 isr >>= 1;
2031 }
2032
2033 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002034 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002035 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002036
2037 switch (info & OPNMASK) {
2038
Denis Vlasenkof782f522007-01-01 23:51:30 +00002039 case B_a2:
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002040#if ENABLE_FEATURE_AWK_LIBM
Denis Vlasenko37890e22008-10-21 12:59:34 +00002041 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002042#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002043 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002044#endif
2045 break;
2046
Denis Vlasenkof782f522007-01-01 23:51:30 +00002047 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002048 if (nargs > 2) {
2049 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2050 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2051 } else {
2052 spl = &fsplitter.n;
2053 }
2054
2055 n = awk_split(as[0], spl, &s);
2056 s1 = s;
2057 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002058 for (i = 1; i <= n; i++)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002059 setari_u(av[1], i, nextword(&s1));
2060 free(s);
2061 setvar_i(res, n);
2062 break;
2063
Denis Vlasenkof782f522007-01-01 23:51:30 +00002064 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00002065 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002066 i = getvar_i(av[1]) - 1;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002067 if (i > l) i = l;
2068 if (i < 0) i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002069 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002070 if (n < 0) n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002071 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002072 setvar_p(res, s);
2073 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002074
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002075 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2076 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002077 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002078 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002079 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002080
Denis Vlasenkof782f522007-01-01 23:51:30 +00002081 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002082 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002083 break;
2084
Denis Vlasenkof782f522007-01-01 23:51:30 +00002085 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002086 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002087 break;
2088
Denis Vlasenkof782f522007-01-01 23:51:30 +00002089 case B_or:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002090 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002091 break;
2092
Denis Vlasenkof782f522007-01-01 23:51:30 +00002093 case B_rs:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002094 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002095 break;
2096
Denis Vlasenkof782f522007-01-01 23:51:30 +00002097 case B_xo:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002098 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002099 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002100
Denis Vlasenkof782f522007-01-01 23:51:30 +00002101 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002102 to_xxx = tolower;
2103 goto lo_cont;
2104
Denis Vlasenkof782f522007-01-01 23:51:30 +00002105 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002106 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002107 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00002108 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002109 while (*s1) {
2110 *s1 = (*to_xxx)(*s1);
2111 s1++;
2112 }
2113 setvar_p(res, s);
2114 break;
2115
Denis Vlasenkof782f522007-01-01 23:51:30 +00002116 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002117 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002118 ll = strlen(as[1]);
2119 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002120 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002121 if (!icase) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002122 s = strstr(as[0], as[1]);
2123 if (s) n = (s - as[0]) + 1;
2124 } else {
2125 /* this piece of code is terribly slow and
2126 * really should be rewritten
2127 */
2128 for (i=0; i<=l; i++) {
2129 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2130 n = i+1;
2131 break;
2132 }
2133 }
2134 }
2135 }
2136 setvar_i(res, n);
2137 break;
2138
Denis Vlasenkof782f522007-01-01 23:51:30 +00002139 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002140 if (nargs > 1)
2141 tt = getvar_i(av[1]);
2142 else
2143 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002144 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002145 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002146 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2147 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002148 g_buf[i] = '\0';
2149 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002150 break;
2151
Denis Vlasenkof782f522007-01-01 23:51:30 +00002152 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002153 re = as_regex(an[1], &sreg);
2154 n = regexec(re, as[0], 1, pmatch, 0);
2155 if (n == 0) {
2156 pmatch[0].rm_so++;
2157 pmatch[0].rm_eo++;
2158 } else {
2159 pmatch[0].rm_so = 0;
2160 pmatch[0].rm_eo = -1;
2161 }
2162 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2163 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2164 setvar_i(res, pmatch[0].rm_so);
2165 if (re == &sreg) regfree(re);
2166 break;
2167
Denis Vlasenkof782f522007-01-01 23:51:30 +00002168 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002169 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2170 break;
2171
Denis Vlasenkof782f522007-01-01 23:51:30 +00002172 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002173 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2174 break;
2175
Denis Vlasenkof782f522007-01-01 23:51:30 +00002176 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002177 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2178 break;
2179 }
2180
2181 nvfree(tv);
2182 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002183#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002184}
2185
2186/*
2187 * Evaluate node - the heart of the program. Supplied with subtree
2188 * and place where to store result. returns ptr to result.
2189 */
2190#define XC(n) ((n) >> 8)
2191
Mike Frysinger10a11e22005-09-27 02:23:02 +00002192static var *evaluate(node *op, var *res)
2193{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002194/* This procedure is recursive so we should count every byte */
2195#define fnargs (G.evaluate__fnargs)
2196/* seed is initialized to 1 */
2197#define seed (G.evaluate__seed)
2198#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002199
Glenn L McGrath545106f2002-11-11 06:21:00 +00002200 node *op1;
2201 var *v1;
2202 union {
2203 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002204 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002205 double d;
2206 int i;
2207 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002208 uint32_t opinfo;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002209 int opn;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002210 union {
2211 char *s;
2212 rstream *rsm;
2213 FILE *F;
2214 var *v;
2215 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002216 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002217 } X;
2218
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002219 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002220 return setvar_s(res, NULL);
2221
2222 v1 = nvalloc(2);
2223
2224 while (op) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002225 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002226 opn = (opinfo & OPNMASK);
2227 g_lineno = op->lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002228
Mike Frysingerde2b9382005-09-27 03:18:00 +00002229 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002230 op1 = op->l.n;
2231 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2232 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2233 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2234 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2235 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2236
2237 switch (XC(opinfo & OPCLSMASK)) {
2238
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002239 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002240
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002241 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002242 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002243 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2244 /* it's range pattern */
2245 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2246 op->info |= OF_CHECKED;
2247 if (ptest(op1->r.n))
2248 op->info &= ~OF_CHECKED;
2249
2250 op = op->a.n;
2251 } else {
2252 op = op->r.n;
2253 }
2254 } else {
2255 op = (ptest(op1)) ? op->a.n : op->r.n;
2256 }
2257 break;
2258
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002259 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002260 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002261 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002262
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002263 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002264 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002265 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002266 break;
2267
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002268 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002269 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002270 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002271 break;
2272
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002273 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002274 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002275 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2276 break;
2277
Denis Vlasenkof782f522007-01-01 23:51:30 +00002278 case XC( OC_PRINT ):
2279 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002280 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002281 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002282 X.rsm = newfile(R.s);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002283 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002284 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002285 X.rsm->F = popen(R.s, "w");
2286 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002287 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002288 X.rsm->is_pipe = 1;
2289 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002290 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002291 }
2292 }
2293 X.F = X.rsm->F;
2294 }
2295
2296 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002297 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002298 fputs(getvar_s(intvar[F0]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002299 } else {
2300 while (op1) {
2301 L.v = evaluate(nextarg(&op1), v1);
2302 if (L.v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002303 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002304 getvar_i(L.v), TRUE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002305 fputs(g_buf, X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002306 } else {
2307 fputs(getvar_s(L.v), X.F);
2308 }
2309
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002310 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002311 }
2312 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002313 fputs(getvar_s(intvar[ORS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002314
2315 } else { /* OC_PRINTF */
2316 L.s = awk_printf(op1);
2317 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002318 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002319 }
2320 fflush(X.F);
2321 break;
2322
Denis Vlasenkof782f522007-01-01 23:51:30 +00002323 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002324 X.info = op1->info & OPCLSMASK;
2325 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002326 R.v = op1->l.v;
2327 } else if (X.info == OC_FNARG) {
2328 R.v = &fnargs[op1->l.i];
2329 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002330 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002331 }
2332
Mike Frysingerde2b9382005-09-27 03:18:00 +00002333 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002334 clrvar(L.v);
2335 L.s = getvar_s(evaluate(op1->r.n, v1));
2336 hash_remove(iamarray(R.v), L.s);
2337 } else {
2338 clear_array(iamarray(R.v));
2339 }
2340 break;
2341
Denis Vlasenkof782f522007-01-01 23:51:30 +00002342 case XC( OC_NEWSOURCE ):
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002343 g_progname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002344 break;
2345
Denis Vlasenkof782f522007-01-01 23:51:30 +00002346 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002347 copyvar(res, L.v);
2348 break;
2349
Denis Vlasenkof782f522007-01-01 23:51:30 +00002350 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002351 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002352 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002353 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002354 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002355 clrvar(res);
2356 break;
2357
Denis Vlasenkof782f522007-01-01 23:51:30 +00002358 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002359 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002360
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002361 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002362
Denis Vlasenkof782f522007-01-01 23:51:30 +00002363 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002364 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002365 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002366 split_f0();
2367 goto v_cont;
2368
Denis Vlasenkof782f522007-01-01 23:51:30 +00002369 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002370 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002371 v_cont:
2372 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002373 break;
2374
Denis Vlasenkof782f522007-01-01 23:51:30 +00002375 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002376 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2377 break;
2378
Denis Vlasenkof782f522007-01-01 23:51:30 +00002379 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002380 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002381 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002382 goto re_cont;
2383
Denis Vlasenkof782f522007-01-01 23:51:30 +00002384 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002385 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002386 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002387 X.re = as_regex(op1, &sreg);
2388 R.i = regexec(X.re, L.s, 0, NULL, 0);
2389 if (X.re == &sreg) regfree(X.re);
2390 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2391 break;
2392
Denis Vlasenkof782f522007-01-01 23:51:30 +00002393 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002394 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002395 if (R.v == v1+1 && R.v->string) {
2396 res = setvar_p(L.v, R.v->string);
2397 R.v->string = NULL;
2398 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002399 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002400 }
2401 break;
2402
Denis Vlasenkof782f522007-01-01 23:51:30 +00002403 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002404 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002405 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002406 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2407 break;
2408
Denis Vlasenkof782f522007-01-01 23:51:30 +00002409 case XC( OC_FUNC ):
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002410 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002411 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002412
2413 X.v = R.v = nvalloc(op->r.f->nargs+1);
2414 while (op1) {
2415 L.v = evaluate(nextarg(&op1), v1);
2416 copyvar(R.v, L.v);
2417 R.v->type |= VF_CHILD;
2418 R.v->x.parent = L.v;
2419 if (++R.v - X.v >= op->r.f->nargs)
2420 break;
2421 }
2422
2423 R.v = fnargs;
2424 fnargs = X.v;
2425
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002426 L.s = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002427 res = evaluate(op->r.f->body.first, res);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002428 g_progname = L.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002429
2430 nvfree(fnargs);
2431 fnargs = R.v;
2432 break;
2433
Denis Vlasenkof782f522007-01-01 23:51:30 +00002434 case XC( OC_GETLINE ):
2435 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002436 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002437 X.rsm = newfile(L.s);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002438 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002439 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2440 X.rsm->F = popen(L.s, "r");
2441 X.rsm->is_pipe = TRUE;
2442 } else {
Denis Vlasenko5415c852008-07-21 23:05:26 +00002443 X.rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002444 }
2445 }
2446 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002447 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002448 X.rsm = iF;
2449 }
2450
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002451 if (!X.rsm->F) {
2452 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002453 setvar_i(res, -1);
2454 break;
2455 }
2456
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002457 if (!op->r.n)
2458 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002459
2460 L.i = awk_getline(X.rsm, R.v);
2461 if (L.i > 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002462 if (!op1) {
2463 incvar(intvar[FNR]);
2464 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002465 }
2466 }
2467 setvar_i(res, L.i);
2468 break;
2469
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002470 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002471 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002472 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002473
Denis Vlasenkof782f522007-01-01 23:51:30 +00002474 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002475 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002476 break;
2477
Denis Vlasenkof782f522007-01-01 23:51:30 +00002478 case F_rn:
2479 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002480 break;
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002481#if ENABLE_FEATURE_AWK_LIBM
Denis Vlasenkof782f522007-01-01 23:51:30 +00002482 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002483 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002484 break;
2485
Denis Vlasenkof782f522007-01-01 23:51:30 +00002486 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002487 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002488 break;
2489
Denis Vlasenkof782f522007-01-01 23:51:30 +00002490 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002491 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002492 break;
2493
Denis Vlasenkof782f522007-01-01 23:51:30 +00002494 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002495 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002496 break;
2497
Denis Vlasenkof782f522007-01-01 23:51:30 +00002498 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002499 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002500 break;
2501#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002502 case F_co:
2503 case F_ex:
2504 case F_lg:
2505 case F_si:
2506 case F_sq:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002507 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002508 break;
2509#endif
Denis Vlasenkof782f522007-01-01 23:51:30 +00002510 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002511 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002512 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002513 srand(seed);
2514 break;
2515
Denis Vlasenkof782f522007-01-01 23:51:30 +00002516 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002517 R.d = time(NULL);
2518 break;
2519
Denis Vlasenkof782f522007-01-01 23:51:30 +00002520 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002521 if (!op1)
2522 L.s = getvar_s(intvar[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002523 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002524 break;
2525
Denis Vlasenkof782f522007-01-01 23:51:30 +00002526 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002527 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002528 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2529 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002530 break;
2531
Denis Vlasenkof782f522007-01-01 23:51:30 +00002532 case F_ff:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002533 if (!op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002534 fflush(stdout);
2535 else {
2536 if (L.s && *L.s) {
2537 X.rsm = newfile(L.s);
2538 fflush(X.rsm->F);
2539 } else {
2540 fflush(NULL);
2541 }
2542 }
2543 break;
2544
Denis Vlasenkof782f522007-01-01 23:51:30 +00002545 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002546 X.rsm = (rstream *)hash_search(fdhash, L.s);
2547 if (X.rsm) {
2548 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002549 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002550 hash_remove(fdhash, L.s);
2551 }
2552 if (R.i != 0)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002553 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002554 R.d = (double)R.i;
2555 break;
2556 }
2557 setvar_i(res, R.d);
2558 break;
2559
Denis Vlasenkof782f522007-01-01 23:51:30 +00002560 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002561 res = exec_builtin(op, res);
2562 break;
2563
Denis Vlasenkof782f522007-01-01 23:51:30 +00002564 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002565 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002566 break;
2567
Denis Vlasenkof782f522007-01-01 23:51:30 +00002568 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002569 X.v = R.v;
2570 L.d = R.d = getvar_i(R.v);
2571 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002572 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002573 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002574 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002575 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002576 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002577 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002578 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002579 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002580 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002581 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002582 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002583 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002584 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002585 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002586 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002587 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002588 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002589 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002590 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002591 setvar_i(X.v, R.d);
2592 }
2593 setvar_i(res, L.d);
2594 break;
2595
Denis Vlasenkof782f522007-01-01 23:51:30 +00002596 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002597 R.i = (int)getvar_i(R.v);
2598 if (R.i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002599 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002600 } else {
2601 split_f0();
2602 if (R.i > nfields)
2603 fsrealloc(R.i);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002604 res = &Fields[R.i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002605 }
2606 break;
2607
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002608 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002609 case XC( OC_CONCAT ):
2610 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002611 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002612 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002613 strcpy(X.s, L.s);
2614 if ((opinfo & OPCLSMASK) == OC_COMMA) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002615 L.s = getvar_s(intvar[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002616 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002617 strcat(X.s, L.s);
2618 }
2619 strcat(X.s, R.s);
2620 setvar_p(res, X.s);
2621 break;
2622
Denis Vlasenkof782f522007-01-01 23:51:30 +00002623 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002624 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2625 break;
2626
Denis Vlasenkof782f522007-01-01 23:51:30 +00002627 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002628 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2629 break;
2630
Denis Vlasenkof782f522007-01-01 23:51:30 +00002631 case XC( OC_BINARY ):
2632 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002633 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002634 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002635 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002636 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002637 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002638 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002639 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002640 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002641 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002642 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002643 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002644 case '/':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002645 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002646 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002647 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002648 case '&':
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002649#if ENABLE_FEATURE_AWK_LIBM
Mike Frysingerde2b9382005-09-27 03:18:00 +00002650 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002651#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002652 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002653#endif
2654 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002655 case '%':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002656 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002657 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002658 break;
2659 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002660 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002661 break;
2662
Denis Vlasenkof782f522007-01-01 23:51:30 +00002663 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002664 if (is_numeric(L.v) && is_numeric(R.v)) {
2665 L.d = getvar_i(L.v) - getvar_i(R.v);
2666 } else {
2667 L.s = getvar_s(L.v);
2668 R.s = getvar_s(R.v);
2669 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2670 }
2671 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002672 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002673 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002674 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002675 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002676 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002677 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002678 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002679 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002680 break;
2681 }
2682 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2683 break;
2684
Denis Vlasenkof782f522007-01-01 23:51:30 +00002685 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002686 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002687 }
2688 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2689 op = op->a.n;
2690 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2691 break;
2692 if (nextrec)
2693 break;
2694 }
2695 nvfree(v1);
2696 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002697#undef fnargs
2698#undef seed
2699#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002700}
2701
2702
2703/* -------- main & co. -------- */
2704
Mike Frysinger10a11e22005-09-27 02:23:02 +00002705static int awk_exit(int r)
2706{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002707 var tv;
2708 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002709 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002710
Denis Vlasenkof782f522007-01-01 23:51:30 +00002711 zero_out_var(&tv);
2712
2713 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002714 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002715 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002716 evaluate(endseq.first, &tv);
2717 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002718
2719 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002720 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002721 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002722 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002723 if (hi->data.rs.F && hi->data.rs.is_pipe)
2724 pclose(hi->data.rs.F);
2725 hi = hi->next;
2726 }
2727 }
2728
2729 exit(r);
2730}
2731
2732/* if expr looks like "var=value", perform assignment and return 1,
2733 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002734static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002735{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002736 char *exprc, *s, *s0, *s1;
2737
Rob Landleyd921b2e2006-08-03 15:41:12 +00002738 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002739 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2740 free(exprc);
2741 return FALSE;
2742 }
2743
2744 *(s++) = '\0';
2745 s0 = s1 = s;
2746 while (*s)
2747 *(s1++) = nextchar(&s);
2748
2749 *s1 = '\0';
2750 setvar_u(newvar(exprc), s0);
2751 free(exprc);
2752 return TRUE;
2753}
2754
2755/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002756static rstream *next_input_file(void)
2757{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002758#define rsm (G.next_input_file__rsm)
2759#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002760
Glenn L McGrath545106f2002-11-11 06:21:00 +00002761 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002762 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002763
2764 if (rsm.F) fclose(rsm.F);
2765 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002766 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002767
2768 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002769 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002770 if (files_happen)
2771 return NULL;
2772 fname = "-";
2773 F = stdin;
2774 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002775 ind = getvar_s(incvar(intvar[ARGIND]));
2776 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002777 if (fname && *fname && !is_assignment(fname))
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002778 F = xfopen_stdin(fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002779 }
2780 } while (!F);
2781
2782 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002783 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002784 rsm.F = F;
2785 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002786#undef rsm
2787#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002788}
2789
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002790int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00002791int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002792{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002793 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002794 char *opt_F, *opt_W;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002795 llist_t *list_v = NULL;
2796 llist_t *list_f = NULL;
2797 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002798 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002799 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002800 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002801 char *vnames = (char *)vNames; /* cheat */
2802 char *vvalues = (char *)vValues;
2803
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002804 INIT_G();
2805
Denis Vlasenko150f4022007-01-13 21:06:21 +00002806 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002807 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2808 if (ENABLE_LOCALE_SUPPORT)
2809 setlocale(LC_NUMERIC, "C");
2810
Denis Vlasenkof782f522007-01-01 23:51:30 +00002811 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002812
2813 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002814 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002815
2816 vhash = hash_init();
2817 ahash = hash_init();
2818 fdhash = hash_init();
2819 fnhash = hash_init();
2820
2821 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002822 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002823 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00002824 if (*vvalues != '\377')
2825 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002826 else
2827 setvar_i(v, 0);
2828
Denis Vlasenkof782f522007-01-01 23:51:30 +00002829 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002830 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002831 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002832 }
2833 }
2834
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002835 handle_special(intvar[FS]);
2836 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002837
Denis Vlasenkof782f522007-01-01 23:51:30 +00002838 newfile("/dev/stdin")->F = stdin;
2839 newfile("/dev/stdout")->F = stdout;
2840 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002841
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002842 /* Huh, people report that sometimes environ is NULL. Oh well. */
2843 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002844 /* environ is writable, thus we don't strdup it needlessly */
2845 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002846 char *s1 = strchr(s, '=');
2847 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002848 *s1 = '\0';
2849 /* Both findvar and setvar_u take const char*
2850 * as 2nd arg -> environment is not trashed */
2851 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
2852 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00002853 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002854 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002855 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
2856 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002857 argv += optind;
2858 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002859 if (opt & 0x1)
2860 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002861 while (list_v) { /* -v */
2862 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002863 bb_show_usage();
2864 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002865 if (list_f) { /* -f */
2866 do {
2867 char *s = NULL;
2868 FILE *from_file;
2869
2870 g_progname = llist_pop(&list_f);
2871 from_file = xfopen_stdin(g_progname);
2872 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002873 for (i = j = 1; j > 0; i += j) {
2874 s = xrealloc(s, i + 4096);
2875 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002876 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002877 s[i] = '\0';
2878 fclose(from_file);
2879 parse_program(s + 1);
2880 free(s);
2881 } while (list_f);
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00002882 argc++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002883 } else { // no -f: take program from 1st parameter
2884 if (!argc)
2885 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002886 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00002887 parse_program(*argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002888 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002889 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002890 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002891
Glenn L McGrath545106f2002-11-11 06:21:00 +00002892 /* fill in ARGV array */
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00002893 setvar_i(intvar[ARGC], argc);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002894 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002895 i = 0;
2896 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002897 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002898
2899 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002900 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002901 awk_exit(EXIT_SUCCESS);
2902
2903 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002904 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002905
2906 /* passing through input files */
2907 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002908 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002909 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002910
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002911 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002912 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002913 incvar(intvar[NR]);
2914 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002915 evaluate(mainseq.first, &tv);
2916
2917 if (nextfile)
2918 break;
2919 }
2920
Denis Vlasenkof782f522007-01-01 23:51:30 +00002921 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002922 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002923
2924 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002925 }
2926
Glenn L McGrath545106f2002-11-11 06:21:00 +00002927 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002928 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002929}