blob: 3f8368c8f75f59d9461a8209d18a3f337e36f4f4 [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 Vlasenkoa60f84e2008-07-05 09:18:54 +0000524static void syntax_error(const char *const message) NORETURN;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000525static void syntax_error(const char *const 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;
Rob Landley9ffd4232006-05-21 18:30:35 +0000607 hi = xzalloc(sizeof(hash_item) + l);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000608 memcpy(hi->name, name, l);
609
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{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001485 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001486 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001487
1488 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1489 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001490 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001491 v = nvalloc(1);
1492 s = getvar_s(evaluate(op, v));
1493 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
1494 nvfree(v);
1495 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001496}
1497
1498/* gradually increasing buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001499static void qrealloc(char **b, int n, int *size)
1500{
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001501 if (!*b || n >= *size) {
1502 *size = n + (n>>1) + 80;
1503 *b = xrealloc(*b, *size);
1504 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001505}
1506
1507/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001508static void fsrealloc(int size)
1509{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001510 int i;
1511
1512 if (size >= maxfields) {
1513 i = maxfields;
1514 maxfields = size + 16;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001515 Fields = xrealloc(Fields, maxfields * sizeof(var));
1516 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001517 Fields[i].type = VF_SPECIAL;
1518 Fields[i].string = NULL;
1519 }
1520 }
1521
1522 if (size < nfields) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001523 for (i = size; i < nfields; i++) {
1524 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001525 }
1526 }
1527 nfields = size;
1528}
1529
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001530static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001531{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001532 int l, n = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001533 char c[4];
1534 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001535 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001536
1537 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001538 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1539 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001540
1541 c[0] = c[1] = (char)spl->info;
1542 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001543 if (*getvar_s(intvar[RS]) == '\0')
1544 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001545
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001546 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1547 if (!*s)
1548 return n; /* "": zero fields */
1549 n++; /* at least one field will be there */
1550 do {
1551 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001552 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1553 && pmatch[0].rm_so <= l
1554 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001555 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001556 if (pmatch[0].rm_eo == 0) {
1557 l++;
1558 pmatch[0].rm_eo++;
1559 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001560 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001561 } else {
1562 pmatch[0].rm_eo = l;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001563 if (s[l]) pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001564 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001565 memcpy(s1, s, l);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001566 s1[l] = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001567 nextword(&s1);
1568 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001569 } while (*s);
1570 return n;
1571 }
1572 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001573 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001574 *s1++ = *s++;
1575 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001576 n++;
1577 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001578 return n;
1579 }
1580 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001581 if (icase) {
1582 c[0] = toupper(c[0]);
1583 c[1] = tolower(c[1]);
1584 }
1585 if (*s1) n++;
1586 while ((s1 = strpbrk(s1, c))) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001587 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001588 n++;
1589 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001590 return n;
1591 }
1592 /* space split */
1593 while (*s) {
1594 s = skip_whitespace(s);
1595 if (!*s) break;
1596 n++;
1597 while (*s && !isspace(*s))
1598 *s1++ = *s++;
1599 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001600 }
1601 return n;
1602}
1603
Mike Frysinger10a11e22005-09-27 02:23:02 +00001604static void split_f0(void)
1605{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001606/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001607#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001608
Glenn L McGrath545106f2002-11-11 06:21:00 +00001609 int i, n;
1610 char *s;
1611
1612 if (is_f0_split)
1613 return;
1614
1615 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001616 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001617 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001618 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001619 fsrealloc(n);
1620 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001621 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001622 Fields[i].string = nextword(&s);
1623 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1624 }
1625
1626 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001627 clrvar(intvar[NF]);
1628 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1629 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001630#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001631}
1632
1633/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001634static void handle_special(var *v)
1635{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001636 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001637 char *b;
1638 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001639 int sl, l, len, i, bsize;
1640
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001641 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001642 return;
1643
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001644 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001645 n = (int)getvar_i(v);
1646 fsrealloc(n);
1647
1648 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001649 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001650 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001651 b = NULL;
1652 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001653 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001654 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001655 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001656 if (b) {
1657 memcpy(b+len, sep, sl);
1658 len += sl;
1659 }
1660 qrealloc(&b, len+l+sl, &bsize);
1661 memcpy(b+len, s, l);
1662 len += l;
1663 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001664 if (b)
1665 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001666 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001667 is_f0_split = TRUE;
1668
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001669 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001670 is_f0_split = FALSE;
1671
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001672 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001673 mk_splitter(getvar_s(v), &fsplitter);
1674
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001675 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001676 mk_splitter(getvar_s(v), &rsplitter);
1677
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001678 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001679 icase = istrue(v);
1680
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001681 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001682 n = getvar_i(intvar[NF]);
1683 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001684 /* right here v is invalid. Just to note... */
1685 }
1686}
1687
1688/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001689static node *nextarg(node **pn)
1690{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001691 node *n;
1692
1693 n = *pn;
1694 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1695 *pn = n->r.n;
1696 n = n->l.n;
1697 } else {
1698 *pn = NULL;
1699 }
1700 return n;
1701}
1702
Mike Frysinger10a11e22005-09-27 02:23:02 +00001703static void hashwalk_init(var *v, xhash *array)
1704{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001705 char **w;
1706 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001707 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001708
1709 if (v->type & VF_WALK)
1710 free(v->x.walker);
1711
1712 v->type |= VF_WALK;
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001713 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001714 w[0] = w[1] = (char *)(w + 2);
1715 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001716 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001717 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001718 strcpy(*w, hi->name);
1719 nextword(w);
1720 hi = hi->next;
1721 }
1722 }
1723}
1724
Mike Frysinger10a11e22005-09-27 02:23:02 +00001725static int hashwalk_next(var *v)
1726{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001727 char **w;
1728
1729 w = v->x.walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001730 if (w[1] == w[0])
Glenn L McGrath545106f2002-11-11 06:21:00 +00001731 return FALSE;
1732
1733 setvar_s(v, nextword(w+1));
1734 return TRUE;
1735}
1736
1737/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001738static int ptest(node *pattern)
1739{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001740 /* ptest__v is "static": to save stack space? */
1741 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001742}
1743
1744/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001745static int awk_getline(rstream *rsm, var *v)
1746{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001747 char *b;
1748 regmatch_t pmatch[2];
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001749 int a, p, pp=0, size;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001750 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001751 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001752
1753 /* we're using our own buffer since we need access to accumulating
1754 * characters
1755 */
1756 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001757 m = rsm->buffer;
1758 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001759 p = rsm->pos;
1760 size = rsm->size;
1761 c = (char) rsplitter.n.info;
1762 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001763
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001764 if (!m) qrealloc(&m, 256, &size);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001765 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001766 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001767 so = eo = p;
1768 r = 1;
1769 if (p > 0) {
1770 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1771 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001772 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001773 so = pmatch[0].rm_so;
1774 eo = pmatch[0].rm_eo;
1775 if (b[eo] != '\0')
1776 break;
1777 }
1778 } else if (c != '\0') {
1779 s = strchr(b+pp, c);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001780 if (!s) s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001781 if (s) {
1782 so = eo = s-b;
1783 eo++;
1784 break;
1785 }
1786 } else {
1787 while (b[rp] == '\n')
1788 rp++;
1789 s = strstr(b+rp, "\n\n");
1790 if (s) {
1791 so = eo = s-b;
1792 while (b[eo] == '\n') eo++;
1793 if (b[eo] != '\0')
1794 break;
1795 }
1796 }
1797 }
1798
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001799 if (a > 0) {
1800 memmove(m, (const void *)(m+a), p+1);
1801 b = m;
1802 a = 0;
1803 }
1804
1805 qrealloc(&m, a+p+128, &size);
1806 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001807 pp = p;
1808 p += safe_read(fd, b+p, size-p-1);
1809 if (p < pp) {
1810 p = 0;
1811 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001812 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001813 }
1814 b[p] = '\0';
1815
1816 } while (p > pp);
1817
1818 if (p == 0) {
1819 r--;
1820 } else {
1821 c = b[so]; b[so] = '\0';
1822 setvar_s(v, b+rp);
1823 v->type |= VF_USER;
1824 b[so] = c;
1825 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001826 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001827 b[eo] = c;
1828 }
1829
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001830 rsm->buffer = m;
1831 rsm->adv = a + eo;
1832 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001833 rsm->size = size;
1834
1835 return r;
1836}
1837
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001838static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001839{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001840 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001841 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001842 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001843
1844 if (int_as_int && n == (int)n) {
1845 r = snprintf(b, size, "%d", (int)n);
1846 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001847 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001848 if (strchr("diouxX", c)) {
1849 r = snprintf(b, size, format, (int)n);
1850 } else if (strchr("eEfgG", c)) {
1851 r = snprintf(b, size, format, n);
1852 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001853 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001854 }
1855 }
1856 return r;
1857}
1858
Glenn L McGrath545106f2002-11-11 06:21:00 +00001859/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001860static char *awk_printf(node *n)
1861{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001862 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001863 char *fmt, *s, *f;
1864 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001865 int i, j, incr, bsize;
1866 char c, c1;
1867 var *v, *arg;
1868
1869 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001870 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001871
1872 i = 0;
1873 while (*f) {
1874 s = f;
1875 while (*f && (*f != '%' || *(++f) == '%'))
1876 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001877 while (*f && !isalpha(*f)) {
1878 if (*f == '*')
1879 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001880 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001881 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001882
1883 incr = (f - s) + MAXVARFMT;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001884 qrealloc(&b, incr + i, &bsize);
1885 c = *f;
1886 if (c != '\0') f++;
1887 c1 = *f;
1888 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001889 arg = evaluate(nextarg(&n), v);
1890
1891 j = i;
1892 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001893 i += sprintf(b+i, s, is_numeric(arg) ?
1894 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001895 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001896 s1 = getvar_s(arg);
Rob Landleya3896512006-05-07 20:20:34 +00001897 qrealloc(&b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001898 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001899 } else {
1900 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1901 }
1902 *f = c1;
1903
1904 /* if there was an error while sprintf, return value is negative */
1905 if (i < j) i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001906 }
1907
Denis Vlasenkof782f522007-01-01 23:51:30 +00001908 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001909 free(fmt);
1910 nvfree(v);
1911 b[i] = '\0';
1912 return b;
1913}
1914
1915/* common substitution routine
1916 * replace (nm) substring of (src) that match (n) with (repl), store
1917 * result into (dest), return number of substitutions. If nm=0, replace
1918 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
1919 * subexpression matching (\1-\9)
1920 */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001921static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001922{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001923 char *ds = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001924 const char *s;
1925 const char *sp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001926 int c, i, j, di, rl, so, eo, nbs, n, dssize;
1927 regmatch_t pmatch[10];
1928 regex_t sreg, *re;
1929
1930 re = as_regex(rn, &sreg);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001931 if (!src) src = intvar[F0];
1932 if (!dest) dest = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001933
1934 i = di = 0;
1935 sp = getvar_s(src);
Rob Landleya3896512006-05-07 20:20:34 +00001936 rl = strlen(repl);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001937 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001938 so = pmatch[0].rm_so;
1939 eo = pmatch[0].rm_eo;
1940
1941 qrealloc(&ds, di + eo + rl, &dssize);
1942 memcpy(ds + di, sp, eo);
1943 di += eo;
1944 if (++i >= nm) {
1945 /* replace */
1946 di -= (eo - so);
1947 nbs = 0;
1948 for (s = repl; *s; s++) {
1949 ds[di++] = c = *s;
1950 if (c == '\\') {
1951 nbs++;
1952 continue;
1953 }
1954 if (c == '&' || (ex && c >= '0' && c <= '9')) {
1955 di -= ((nbs + 3) >> 1);
1956 j = 0;
1957 if (c != '&') {
1958 j = c - '0';
1959 nbs++;
1960 }
1961 if (nbs % 2) {
1962 ds[di++] = c;
1963 } else {
1964 n = pmatch[j].rm_eo - pmatch[j].rm_so;
1965 qrealloc(&ds, di + rl + n, &dssize);
1966 memcpy(ds + di, sp + pmatch[j].rm_so, n);
1967 di += n;
1968 }
1969 }
1970 nbs = 0;
1971 }
1972 }
1973
1974 sp += eo;
1975 if (i == nm) break;
1976 if (eo == so) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001977 ds[di] = *sp++;
1978 if (!ds[di++]) break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001979 }
1980 }
1981
1982 qrealloc(&ds, di + strlen(sp), &dssize);
1983 strcpy(ds + di, sp);
1984 setvar_p(dest, ds);
1985 if (re == &sreg) regfree(re);
1986 return i;
1987}
1988
Mike Frysinger10a11e22005-09-27 02:23:02 +00001989static var *exec_builtin(node *op, var *res)
1990{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001991#define tspl (G.exec_builtin__tspl)
1992
Glenn L McGrath545106f2002-11-11 06:21:00 +00001993 int (*to_xxx)(int);
1994 var *tv;
1995 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001996 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001997 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001998 regmatch_t pmatch[2];
1999 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002000 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002001 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002002 int nargs;
2003 time_t tt;
2004 char *s, *s1;
2005 int i, l, ll, n;
2006
2007 tv = nvalloc(4);
2008 isr = info = op->info;
2009 op = op->l.n;
2010
2011 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002012 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002013 an[i] = nextarg(&op);
2014 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
2015 if (isr & 0x08000000) as[i] = getvar_s(av[i]);
2016 isr >>= 1;
2017 }
2018
2019 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002020 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002021 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002022
2023 switch (info & OPNMASK) {
2024
Denis Vlasenkof782f522007-01-01 23:51:30 +00002025 case B_a2:
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002026#if ENABLE_FEATURE_AWK_LIBM
Denis Vlasenko37890e22008-10-21 12:59:34 +00002027 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002028#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002029 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002030#endif
2031 break;
2032
Denis Vlasenkof782f522007-01-01 23:51:30 +00002033 case B_sp:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002034 if (nargs > 2) {
2035 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2036 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2037 } else {
2038 spl = &fsplitter.n;
2039 }
2040
2041 n = awk_split(as[0], spl, &s);
2042 s1 = s;
2043 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002044 for (i = 1; i <= n; i++)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002045 setari_u(av[1], i, nextword(&s1));
2046 free(s);
2047 setvar_i(res, n);
2048 break;
2049
Denis Vlasenkof782f522007-01-01 23:51:30 +00002050 case B_ss:
Rob Landleya3896512006-05-07 20:20:34 +00002051 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002052 i = getvar_i(av[1]) - 1;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002053 if (i > l) i = l;
2054 if (i < 0) i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002055 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002056 if (n < 0) n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002057 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002058 setvar_p(res, s);
2059 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002060
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002061 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2062 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002063 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002064 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002065 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002066
Denis Vlasenkof782f522007-01-01 23:51:30 +00002067 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002068 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002069 break;
2070
Denis Vlasenkof782f522007-01-01 23:51:30 +00002071 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002072 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002073 break;
2074
Denis Vlasenkof782f522007-01-01 23:51:30 +00002075 case B_or:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002076 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002077 break;
2078
Denis Vlasenkof782f522007-01-01 23:51:30 +00002079 case B_rs:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002080 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002081 break;
2082
Denis Vlasenkof782f522007-01-01 23:51:30 +00002083 case B_xo:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002084 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002085 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002086
Denis Vlasenkof782f522007-01-01 23:51:30 +00002087 case B_lo:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002088 to_xxx = tolower;
2089 goto lo_cont;
2090
Denis Vlasenkof782f522007-01-01 23:51:30 +00002091 case B_up:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002092 to_xxx = toupper;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002093 lo_cont:
Rob Landleyd921b2e2006-08-03 15:41:12 +00002094 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002095 while (*s1) {
2096 *s1 = (*to_xxx)(*s1);
2097 s1++;
2098 }
2099 setvar_p(res, s);
2100 break;
2101
Denis Vlasenkof782f522007-01-01 23:51:30 +00002102 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002103 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002104 ll = strlen(as[1]);
2105 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002106 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002107 if (!icase) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002108 s = strstr(as[0], as[1]);
2109 if (s) n = (s - as[0]) + 1;
2110 } else {
2111 /* this piece of code is terribly slow and
2112 * really should be rewritten
2113 */
2114 for (i=0; i<=l; i++) {
2115 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2116 n = i+1;
2117 break;
2118 }
2119 }
2120 }
2121 }
2122 setvar_i(res, n);
2123 break;
2124
Denis Vlasenkof782f522007-01-01 23:51:30 +00002125 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002126 if (nargs > 1)
2127 tt = getvar_i(av[1]);
2128 else
2129 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002130 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002131 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002132 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2133 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002134 g_buf[i] = '\0';
2135 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002136 break;
2137
Denis Vlasenkof782f522007-01-01 23:51:30 +00002138 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002139 re = as_regex(an[1], &sreg);
2140 n = regexec(re, as[0], 1, pmatch, 0);
2141 if (n == 0) {
2142 pmatch[0].rm_so++;
2143 pmatch[0].rm_eo++;
2144 } else {
2145 pmatch[0].rm_so = 0;
2146 pmatch[0].rm_eo = -1;
2147 }
2148 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2149 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2150 setvar_i(res, pmatch[0].rm_so);
2151 if (re == &sreg) regfree(re);
2152 break;
2153
Denis Vlasenkof782f522007-01-01 23:51:30 +00002154 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002155 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2156 break;
2157
Denis Vlasenkof782f522007-01-01 23:51:30 +00002158 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002159 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2160 break;
2161
Denis Vlasenkof782f522007-01-01 23:51:30 +00002162 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002163 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2164 break;
2165 }
2166
2167 nvfree(tv);
2168 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002169#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002170}
2171
2172/*
2173 * Evaluate node - the heart of the program. Supplied with subtree
2174 * and place where to store result. returns ptr to result.
2175 */
2176#define XC(n) ((n) >> 8)
2177
Mike Frysinger10a11e22005-09-27 02:23:02 +00002178static var *evaluate(node *op, var *res)
2179{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002180/* This procedure is recursive so we should count every byte */
2181#define fnargs (G.evaluate__fnargs)
2182/* seed is initialized to 1 */
2183#define seed (G.evaluate__seed)
2184#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002185
Glenn L McGrath545106f2002-11-11 06:21:00 +00002186 node *op1;
2187 var *v1;
2188 union {
2189 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002190 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002191 double d;
2192 int i;
2193 } L, R;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002194 uint32_t opinfo;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002195 int opn;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002196 union {
2197 char *s;
2198 rstream *rsm;
2199 FILE *F;
2200 var *v;
2201 regex_t *re;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002202 uint32_t info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002203 } X;
2204
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002205 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002206 return setvar_s(res, NULL);
2207
2208 v1 = nvalloc(2);
2209
2210 while (op) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002211 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002212 opn = (opinfo & OPNMASK);
2213 g_lineno = op->lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002214
Mike Frysingerde2b9382005-09-27 03:18:00 +00002215 /* execute inevitable things */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002216 op1 = op->l.n;
2217 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
2218 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
2219 if (opinfo & OF_STR1) L.s = getvar_s(L.v);
2220 if (opinfo & OF_STR2) R.s = getvar_s(R.v);
2221 if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
2222
2223 switch (XC(opinfo & OPCLSMASK)) {
2224
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002225 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002226
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002227 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002228 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002229 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2230 /* it's range pattern */
2231 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2232 op->info |= OF_CHECKED;
2233 if (ptest(op1->r.n))
2234 op->info &= ~OF_CHECKED;
2235
2236 op = op->a.n;
2237 } else {
2238 op = op->r.n;
2239 }
2240 } else {
2241 op = (ptest(op1)) ? op->a.n : op->r.n;
2242 }
2243 break;
2244
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002245 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002246 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002247 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002248
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002249 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002250 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002251 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002252 break;
2253
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002254 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002255 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002256 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002257 break;
2258
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002259 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002260 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002261 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2262 break;
2263
Denis Vlasenkof782f522007-01-01 23:51:30 +00002264 case XC( OC_PRINT ):
2265 case XC( OC_PRINTF ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002266 X.F = stdout;
Mike Frysingerde2b9382005-09-27 03:18:00 +00002267 if (op->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002268 X.rsm = newfile(R.s);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002269 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002270 if (opn == '|') {
Denis Vlasenko51742f42007-04-12 00:32:05 +00002271 X.rsm->F = popen(R.s, "w");
2272 if (X.rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002273 bb_perror_msg_and_die("popen");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002274 X.rsm->is_pipe = 1;
2275 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00002276 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002277 }
2278 }
2279 X.F = X.rsm->F;
2280 }
2281
2282 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002283 if (!op1) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002284 fputs(getvar_s(intvar[F0]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002285 } else {
2286 while (op1) {
2287 L.v = evaluate(nextarg(&op1), v1);
2288 if (L.v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002289 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denis Vlasenkob54b2082006-10-27 09:05:40 +00002290 getvar_i(L.v), TRUE);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002291 fputs(g_buf, X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002292 } else {
2293 fputs(getvar_s(L.v), X.F);
2294 }
2295
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002296 if (op1) fputs(getvar_s(intvar[OFS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002297 }
2298 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002299 fputs(getvar_s(intvar[ORS]), X.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002300
2301 } else { /* OC_PRINTF */
2302 L.s = awk_printf(op1);
2303 fputs(L.s, X.F);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002304 free((char*)L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002305 }
2306 fflush(X.F);
2307 break;
2308
Denis Vlasenkof782f522007-01-01 23:51:30 +00002309 case XC( OC_DELETE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002310 X.info = op1->info & OPCLSMASK;
2311 if (X.info == OC_VAR) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002312 R.v = op1->l.v;
2313 } else if (X.info == OC_FNARG) {
2314 R.v = &fnargs[op1->l.i];
2315 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002316 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002317 }
2318
Mike Frysingerde2b9382005-09-27 03:18:00 +00002319 if (op1->r.n) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002320 clrvar(L.v);
2321 L.s = getvar_s(evaluate(op1->r.n, v1));
2322 hash_remove(iamarray(R.v), L.s);
2323 } else {
2324 clear_array(iamarray(R.v));
2325 }
2326 break;
2327
Denis Vlasenkof782f522007-01-01 23:51:30 +00002328 case XC( OC_NEWSOURCE ):
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002329 g_progname = op->l.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002330 break;
2331
Denis Vlasenkof782f522007-01-01 23:51:30 +00002332 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002333 copyvar(res, L.v);
2334 break;
2335
Denis Vlasenkof782f522007-01-01 23:51:30 +00002336 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002337 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002338 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002339 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002340 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002341 clrvar(res);
2342 break;
2343
Denis Vlasenkof782f522007-01-01 23:51:30 +00002344 case XC( OC_EXIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002345 awk_exit(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002346
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002347 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002348
Denis Vlasenkof782f522007-01-01 23:51:30 +00002349 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002350 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002351 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002352 split_f0();
2353 goto v_cont;
2354
Denis Vlasenkof782f522007-01-01 23:51:30 +00002355 case XC( OC_FNARG ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002356 L.v = &fnargs[op->l.i];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002357 v_cont:
2358 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002359 break;
2360
Denis Vlasenkof782f522007-01-01 23:51:30 +00002361 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002362 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2363 break;
2364
Denis Vlasenkof782f522007-01-01 23:51:30 +00002365 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002366 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002367 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002368 goto re_cont;
2369
Denis Vlasenkof782f522007-01-01 23:51:30 +00002370 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002371 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002372 re_cont:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002373 X.re = as_regex(op1, &sreg);
2374 R.i = regexec(X.re, L.s, 0, NULL, 0);
2375 if (X.re == &sreg) regfree(X.re);
2376 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
2377 break;
2378
Denis Vlasenkof782f522007-01-01 23:51:30 +00002379 case XC( OC_MOVE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002380 /* if source is a temporary string, jusk relink it to dest */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002381 if (R.v == v1+1 && R.v->string) {
2382 res = setvar_p(L.v, R.v->string);
2383 R.v->string = NULL;
2384 } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002385 res = copyvar(L.v, R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002386 }
2387 break;
2388
Denis Vlasenkof782f522007-01-01 23:51:30 +00002389 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002390 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002391 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002392 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2393 break;
2394
Denis Vlasenkof782f522007-01-01 23:51:30 +00002395 case XC( OC_FUNC ):
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002396 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002397 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002398
2399 X.v = R.v = nvalloc(op->r.f->nargs+1);
2400 while (op1) {
2401 L.v = evaluate(nextarg(&op1), v1);
2402 copyvar(R.v, L.v);
2403 R.v->type |= VF_CHILD;
2404 R.v->x.parent = L.v;
2405 if (++R.v - X.v >= op->r.f->nargs)
2406 break;
2407 }
2408
2409 R.v = fnargs;
2410 fnargs = X.v;
2411
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002412 L.s = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002413 res = evaluate(op->r.f->body.first, res);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002414 g_progname = L.s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002415
2416 nvfree(fnargs);
2417 fnargs = R.v;
2418 break;
2419
Denis Vlasenkof782f522007-01-01 23:51:30 +00002420 case XC( OC_GETLINE ):
2421 case XC( OC_PGETLINE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002422 if (op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002423 X.rsm = newfile(L.s);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002424 if (!X.rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002425 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
2426 X.rsm->F = popen(L.s, "r");
2427 X.rsm->is_pipe = TRUE;
2428 } else {
Denis Vlasenko5415c852008-07-21 23:05:26 +00002429 X.rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002430 }
2431 }
2432 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002433 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002434 X.rsm = iF;
2435 }
2436
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002437 if (!X.rsm->F) {
2438 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002439 setvar_i(res, -1);
2440 break;
2441 }
2442
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002443 if (!op->r.n)
2444 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002445
2446 L.i = awk_getline(X.rsm, R.v);
2447 if (L.i > 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002448 if (!op1) {
2449 incvar(intvar[FNR]);
2450 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002451 }
2452 }
2453 setvar_i(res, L.i);
2454 break;
2455
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002456 /* simple builtins */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002457 case XC( OC_FBLTIN ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002458 switch (opn) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002459
Denis Vlasenkof782f522007-01-01 23:51:30 +00002460 case F_in:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002461 R.d = (int)L.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002462 break;
2463
Denis Vlasenkof782f522007-01-01 23:51:30 +00002464 case F_rn:
2465 R.d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002466 break;
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002467#if ENABLE_FEATURE_AWK_LIBM
Denis Vlasenkof782f522007-01-01 23:51:30 +00002468 case F_co:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002469 R.d = cos(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002470 break;
2471
Denis Vlasenkof782f522007-01-01 23:51:30 +00002472 case F_ex:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002473 R.d = exp(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002474 break;
2475
Denis Vlasenkof782f522007-01-01 23:51:30 +00002476 case F_lg:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002477 R.d = log(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002478 break;
2479
Denis Vlasenkof782f522007-01-01 23:51:30 +00002480 case F_si:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002481 R.d = sin(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002482 break;
2483
Denis Vlasenkof782f522007-01-01 23:51:30 +00002484 case F_sq:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002485 R.d = sqrt(L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002486 break;
2487#else
Denis Vlasenkof782f522007-01-01 23:51:30 +00002488 case F_co:
2489 case F_ex:
2490 case F_lg:
2491 case F_si:
2492 case F_sq:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002493 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002494 break;
2495#endif
Denis Vlasenkof782f522007-01-01 23:51:30 +00002496 case F_sr:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002497 R.d = (double)seed;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002498 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002499 srand(seed);
2500 break;
2501
Denis Vlasenkof782f522007-01-01 23:51:30 +00002502 case F_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002503 R.d = time(NULL);
2504 break;
2505
Denis Vlasenkof782f522007-01-01 23:51:30 +00002506 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002507 if (!op1)
2508 L.s = getvar_s(intvar[F0]);
Rob Landleya3896512006-05-07 20:20:34 +00002509 R.d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002510 break;
2511
Denis Vlasenkof782f522007-01-01 23:51:30 +00002512 case F_sy:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002513 fflush(NULL);
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002514 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
2515 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002516 break;
2517
Denis Vlasenkof782f522007-01-01 23:51:30 +00002518 case F_ff:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002519 if (!op1)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002520 fflush(stdout);
2521 else {
2522 if (L.s && *L.s) {
2523 X.rsm = newfile(L.s);
2524 fflush(X.rsm->F);
2525 } else {
2526 fflush(NULL);
2527 }
2528 }
2529 break;
2530
Denis Vlasenkof782f522007-01-01 23:51:30 +00002531 case F_cl:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002532 X.rsm = (rstream *)hash_search(fdhash, L.s);
2533 if (X.rsm) {
2534 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00002535 free(X.rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002536 hash_remove(fdhash, L.s);
2537 }
2538 if (R.i != 0)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002539 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002540 R.d = (double)R.i;
2541 break;
2542 }
2543 setvar_i(res, R.d);
2544 break;
2545
Denis Vlasenkof782f522007-01-01 23:51:30 +00002546 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002547 res = exec_builtin(op, res);
2548 break;
2549
Denis Vlasenkof782f522007-01-01 23:51:30 +00002550 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002551 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002552 break;
2553
Denis Vlasenkof782f522007-01-01 23:51:30 +00002554 case XC( OC_UNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002555 X.v = R.v;
2556 L.d = R.d = getvar_i(R.v);
2557 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002558 case 'P':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002559 L.d = ++R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002560 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002561 case 'p':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002562 R.d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002563 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002564 case 'M':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002565 L.d = --R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002566 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002567 case 'm':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002568 R.d--;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002569 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002570 case '!':
Denis Vlasenko92758142006-10-03 19:56:34 +00002571 L.d = istrue(X.v) ? 0 : 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002572 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002573 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002574 L.d = -R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002575 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002576 r_op_change:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002577 setvar_i(X.v, R.d);
2578 }
2579 setvar_i(res, L.d);
2580 break;
2581
Denis Vlasenkof782f522007-01-01 23:51:30 +00002582 case XC( OC_FIELD ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002583 R.i = (int)getvar_i(R.v);
2584 if (R.i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002585 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002586 } else {
2587 split_f0();
2588 if (R.i > nfields)
2589 fsrealloc(R.i);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002590 res = &Fields[R.i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002591 }
2592 break;
2593
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002594 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002595 case XC( OC_CONCAT ):
2596 case XC( OC_COMMA ):
Rob Landleya3896512006-05-07 20:20:34 +00002597 opn = strlen(L.s) + strlen(R.s) + 2;
Denis Vlasenkob95636c2006-12-19 23:36:04 +00002598 X.s = xmalloc(opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002599 strcpy(X.s, L.s);
2600 if ((opinfo & OPCLSMASK) == OC_COMMA) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002601 L.s = getvar_s(intvar[SUBSEP]);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002602 X.s = xrealloc(X.s, opn + strlen(L.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002603 strcat(X.s, L.s);
2604 }
2605 strcat(X.s, R.s);
2606 setvar_p(res, X.s);
2607 break;
2608
Denis Vlasenkof782f522007-01-01 23:51:30 +00002609 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002610 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2611 break;
2612
Denis Vlasenkof782f522007-01-01 23:51:30 +00002613 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002614 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2615 break;
2616
Denis Vlasenkof782f522007-01-01 23:51:30 +00002617 case XC( OC_BINARY ):
2618 case XC( OC_REPLACE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002619 R.d = getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002620 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002621 case '+':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002622 L.d += R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002623 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002624 case '-':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002625 L.d -= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002626 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002627 case '*':
Mike Frysingerde2b9382005-09-27 03:18:00 +00002628 L.d *= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002629 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002630 case '/':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002631 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002632 L.d /= R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002633 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002634 case '&':
Denis Vlasenko2d5bd802008-10-24 10:49:49 +00002635#if ENABLE_FEATURE_AWK_LIBM
Mike Frysingerde2b9382005-09-27 03:18:00 +00002636 L.d = pow(L.d, R.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002637#else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002638 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002639#endif
2640 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002641 case '%':
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002642 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002643 L.d -= (int)(L.d / R.d) * R.d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002644 break;
2645 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002646 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002647 break;
2648
Denis Vlasenkof782f522007-01-01 23:51:30 +00002649 case XC( OC_COMPARE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002650 if (is_numeric(L.v) && is_numeric(R.v)) {
2651 L.d = getvar_i(L.v) - getvar_i(R.v);
2652 } else {
2653 L.s = getvar_s(L.v);
2654 R.s = getvar_s(R.v);
2655 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
2656 }
2657 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002658 case 0:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002659 R.i = (L.d > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002660 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002661 case 2:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002662 R.i = (L.d >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002663 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002664 case 4:
Mike Frysingerde2b9382005-09-27 03:18:00 +00002665 R.i = (L.d == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002666 break;
2667 }
2668 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
2669 break;
2670
Denis Vlasenkof782f522007-01-01 23:51:30 +00002671 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002672 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002673 }
2674 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2675 op = op->a.n;
2676 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2677 break;
2678 if (nextrec)
2679 break;
2680 }
2681 nvfree(v1);
2682 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002683#undef fnargs
2684#undef seed
2685#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002686}
2687
2688
2689/* -------- main & co. -------- */
2690
Mike Frysinger10a11e22005-09-27 02:23:02 +00002691static int awk_exit(int r)
2692{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002693 var tv;
2694 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002695 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002696
Denis Vlasenkof782f522007-01-01 23:51:30 +00002697 zero_out_var(&tv);
2698
2699 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002700 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002701 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002702 evaluate(endseq.first, &tv);
2703 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002704
2705 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002706 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002707 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002708 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002709 if (hi->data.rs.F && hi->data.rs.is_pipe)
2710 pclose(hi->data.rs.F);
2711 hi = hi->next;
2712 }
2713 }
2714
2715 exit(r);
2716}
2717
2718/* if expr looks like "var=value", perform assignment and return 1,
2719 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002720static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002721{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002722 char *exprc, *s, *s0, *s1;
2723
Rob Landleyd921b2e2006-08-03 15:41:12 +00002724 exprc = xstrdup(expr);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002725 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2726 free(exprc);
2727 return FALSE;
2728 }
2729
2730 *(s++) = '\0';
2731 s0 = s1 = s;
2732 while (*s)
2733 *(s1++) = nextchar(&s);
2734
2735 *s1 = '\0';
2736 setvar_u(newvar(exprc), s0);
2737 free(exprc);
2738 return TRUE;
2739}
2740
2741/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002742static rstream *next_input_file(void)
2743{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002744#define rsm (G.next_input_file__rsm)
2745#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002746
Glenn L McGrath545106f2002-11-11 06:21:00 +00002747 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002748 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002749
2750 if (rsm.F) fclose(rsm.F);
2751 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002752 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002753
2754 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002755 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002756 if (files_happen)
2757 return NULL;
2758 fname = "-";
2759 F = stdin;
2760 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002761 ind = getvar_s(incvar(intvar[ARGIND]));
2762 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002763 if (fname && *fname && !is_assignment(fname))
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002764 F = xfopen_stdin(fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002765 }
2766 } while (!F);
2767
2768 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002769 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002770 rsm.F = F;
2771 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002772#undef rsm
2773#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002774}
2775
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002776int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00002777int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002778{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002779 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002780 char *opt_F, *opt_W;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002781 llist_t *list_v = NULL;
2782 llist_t *list_f = NULL;
2783 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002784 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002785 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002786 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002787 char *vnames = (char *)vNames; /* cheat */
2788 char *vvalues = (char *)vValues;
2789
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002790 INIT_G();
2791
Denis Vlasenko150f4022007-01-13 21:06:21 +00002792 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00002793 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
2794 if (ENABLE_LOCALE_SUPPORT)
2795 setlocale(LC_NUMERIC, "C");
2796
Denis Vlasenkof782f522007-01-01 23:51:30 +00002797 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002798
2799 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002800 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002801
2802 vhash = hash_init();
2803 ahash = hash_init();
2804 fdhash = hash_init();
2805 fnhash = hash_init();
2806
2807 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002808 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002809 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00002810 if (*vvalues != '\377')
2811 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002812 else
2813 setvar_i(v, 0);
2814
Denis Vlasenkof782f522007-01-01 23:51:30 +00002815 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002816 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002817 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002818 }
2819 }
2820
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002821 handle_special(intvar[FS]);
2822 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002823
Denis Vlasenkof782f522007-01-01 23:51:30 +00002824 newfile("/dev/stdin")->F = stdin;
2825 newfile("/dev/stdout")->F = stdout;
2826 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002827
Denis Vlasenkof71d9162007-05-03 22:57:56 +00002828 /* Huh, people report that sometimes environ is NULL. Oh well. */
2829 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002830 /* environ is writable, thus we don't strdup it needlessly */
2831 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002832 char *s1 = strchr(s, '=');
2833 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00002834 *s1 = '\0';
2835 /* Both findvar and setvar_u take const char*
2836 * as 2nd arg -> environment is not trashed */
2837 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
2838 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00002839 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002840 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002841 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
2842 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002843 argv += optind;
2844 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002845 if (opt & 0x1)
2846 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002847 while (list_v) { /* -v */
2848 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002849 bb_show_usage();
2850 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002851 if (list_f) { /* -f */
2852 do {
2853 char *s = NULL;
2854 FILE *from_file;
2855
2856 g_progname = llist_pop(&list_f);
2857 from_file = xfopen_stdin(g_progname);
2858 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002859 for (i = j = 1; j > 0; i += j) {
2860 s = xrealloc(s, i + 4096);
2861 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002862 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002863 s[i] = '\0';
2864 fclose(from_file);
2865 parse_program(s + 1);
2866 free(s);
2867 } while (list_f);
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00002868 argc++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002869 } else { // no -f: take program from 1st parameter
2870 if (!argc)
2871 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002872 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00002873 parse_program(*argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002874 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00002875 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00002876 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002877
Glenn L McGrath545106f2002-11-11 06:21:00 +00002878 /* fill in ARGV array */
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00002879 setvar_i(intvar[ARGC], argc);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002880 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00002881 i = 0;
2882 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002883 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002884
2885 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002886 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002887 awk_exit(EXIT_SUCCESS);
2888
2889 /* input file could already be opened in BEGIN block */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002890 if (!iF) iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002891
2892 /* passing through input files */
2893 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002894 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002895 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002896
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002897 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002898 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002899 incvar(intvar[NR]);
2900 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002901 evaluate(mainseq.first, &tv);
2902
2903 if (nextfile)
2904 break;
2905 }
2906
Denis Vlasenkof782f522007-01-01 23:51:30 +00002907 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002908 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002909
2910 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002911 }
2912
Glenn L McGrath545106f2002-11-11 06:21:00 +00002913 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002914 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00002915}