blob: 0918026d7339add22c6c192a818e1a4322bc9421 [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 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Glenn L McGrath545106f2002-11-11 06:21:00 +00008 */
9
Pere Orga6a3e01d2011-04-01 22:56:30 +020010//usage:#define awk_trivial_usage
11//usage: "[OPTIONS] [AWK_PROGRAM] [FILE]..."
12//usage:#define awk_full_usage "\n\n"
Denys Vlasenko66426762011-06-05 03:58:28 +020013//usage: " -v VAR=VAL Set variable"
Pere Orga6a3e01d2011-04-01 22:56:30 +020014//usage: "\n -F SEP Use SEP as field separator"
15//usage: "\n -f FILE Read program from FILE"
16
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000017#include "libbb.h"
Rob Landleyd921b2e2006-08-03 15:41:12 +000018#include "xregex.h"
19#include <math.h>
Glenn L McGrath545106f2002-11-11 06:21:00 +000020
Denis Vlasenko99912ca2007-04-10 15:43:37 +000021/* This is a NOEXEC applet. Be very careful! */
22
Glenn L McGrath545106f2002-11-11 06:21:00 +000023
Denys Vlasenkoda62b092010-03-11 12:13:18 +010024/* If you comment out one of these below, it will be #defined later
25 * to perform debug printfs to stderr: */
26#define debug_printf_walker(...) do {} while (0)
Denys Vlasenkod527e0c2010-10-05 13:22:11 +020027#define debug_printf_eval(...) do {} while (0)
Denys Vlasenkoda62b092010-03-11 12:13:18 +010028
29#ifndef debug_printf_walker
30# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__))
31#endif
Denys Vlasenkod527e0c2010-10-05 13:22:11 +020032#ifndef debug_printf_eval
33# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__))
34#endif
Denys Vlasenkoda62b092010-03-11 12:13:18 +010035
36
37
Denis Vlasenko629563b2007-02-24 17:05:52 +000038#define MAXVARFMT 240
39#define MINNVBLOCK 64
Glenn L McGrath545106f2002-11-11 06:21:00 +000040
41/* variable flags */
Denis Vlasenko629563b2007-02-24 17:05:52 +000042#define VF_NUMBER 0x0001 /* 1 = primary type is number */
43#define VF_ARRAY 0x0002 /* 1 = it's an array */
Glenn L McGrath545106f2002-11-11 06:21:00 +000044
Denis Vlasenko629563b2007-02-24 17:05:52 +000045#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
46#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
47#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
48#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
49#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
50#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
51#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
Glenn L McGrath545106f2002-11-11 06:21:00 +000052
53/* these flags are static, don't change them when value is changed */
Denis Vlasenko629563b2007-02-24 17:05:52 +000054#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
Glenn L McGrath545106f2002-11-11 06:21:00 +000055
Denys Vlasenkoda62b092010-03-11 12:13:18 +010056typedef struct walker_list {
57 char *end;
58 char *cur;
59 struct walker_list *prev;
60 char wbuf[1];
61} walker_list;
62
Glenn L McGrath545106f2002-11-11 06:21:00 +000063/* Variable */
64typedef struct var_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000065 unsigned type; /* flags */
Glenn L McGrath545106f2002-11-11 06:21:00 +000066 double number;
67 char *string;
68 union {
Denis Vlasenko629563b2007-02-24 17:05:52 +000069 int aidx; /* func arg idx (for compilation stage) */
70 struct xhash_s *array; /* array ptr */
71 struct var_s *parent; /* for func args, ptr to actual parameter */
Denys Vlasenkoda62b092010-03-11 12:13:18 +010072 walker_list *walker; /* list of array elements (for..in) */
Glenn L McGrath545106f2002-11-11 06:21:00 +000073 } x;
74} var;
75
76/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
77typedef struct chain_s {
78 struct node_s *first;
79 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +000080 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +000081} chain;
82
83/* Function */
84typedef struct func_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000085 unsigned nargs;
Glenn L McGrath545106f2002-11-11 06:21:00 +000086 struct chain_s body;
87} func;
88
89/* I/O stream */
90typedef struct rstream_s {
91 FILE *F;
92 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +000093 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +000094 int size;
95 int pos;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000096 smallint is_pipe;
Glenn L McGrath545106f2002-11-11 06:21:00 +000097} rstream;
98
99typedef struct hash_item_s {
100 union {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000101 struct var_s v; /* variable/array hash */
102 struct rstream_s rs; /* redirect streams hash */
103 struct func_s f; /* functions hash */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000104 } data;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000105 struct hash_item_s *next; /* next in chain */
106 char name[1]; /* really it's longer */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000107} hash_item;
108
109typedef struct xhash_s {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000110 unsigned nel; /* num of elements */
111 unsigned csize; /* current hash size */
112 unsigned nprime; /* next hash size in PRIMES[] */
113 unsigned glen; /* summary length of item names */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000114 struct hash_item_s **items;
115} xhash;
116
117/* Tree node */
118typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000119 uint32_t info;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000120 unsigned lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000121 union {
122 struct node_s *n;
123 var *v;
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100124 int aidx;
125 char *new_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000126 regex_t *re;
127 } l;
128 union {
129 struct node_s *n;
130 regex_t *ire;
131 func *f;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000132 } r;
133 union {
134 struct node_s *n;
135 } a;
136} node;
137
138/* Block of temporary variables */
139typedef struct nvblock_s {
140 int size;
141 var *pos;
142 struct nvblock_s *prev;
143 struct nvblock_s *next;
Denys Vlasenkod069e532009-09-09 23:12:10 +0200144 var nv[];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000145} nvblock;
146
147typedef struct tsplitter_s {
148 node n;
149 regex_t re[2];
150} tsplitter;
151
152/* simple token classes */
153/* Order and hex values are very important!!! See next_token() */
154#define TC_SEQSTART 1 /* ( */
155#define TC_SEQTERM (1 << 1) /* ) */
156#define TC_REGEXP (1 << 2) /* /.../ */
157#define TC_OUTRDR (1 << 3) /* | > >> */
158#define TC_UOPPOST (1 << 4) /* unary postfix operator */
159#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
160#define TC_BINOPX (1 << 6) /* two-opnd operator */
161#define TC_IN (1 << 7)
162#define TC_COMMA (1 << 8)
163#define TC_PIPE (1 << 9) /* input redirection pipe */
164#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
165#define TC_ARRTERM (1 << 11) /* ] */
166#define TC_GRPSTART (1 << 12) /* { */
167#define TC_GRPTERM (1 << 13) /* } */
168#define TC_SEMICOL (1 << 14)
169#define TC_NEWLINE (1 << 15)
170#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
171#define TC_WHILE (1 << 17)
172#define TC_ELSE (1 << 18)
173#define TC_BUILTIN (1 << 19)
174#define TC_GETLINE (1 << 20)
175#define TC_FUNCDECL (1 << 21) /* `function' `func' */
176#define TC_BEGIN (1 << 22)
177#define TC_END (1 << 23)
178#define TC_EOF (1 << 24)
179#define TC_VARIABLE (1 << 25)
180#define TC_ARRAY (1 << 26)
181#define TC_FUNCTION (1 << 27)
182#define TC_STRING (1 << 28)
183#define TC_NUMBER (1 << 29)
184
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000185#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000186
187/* combined token classes */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000188#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
189#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
190#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
191 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000192
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000193#define TC_STATEMNT (TC_STATX | TC_WHILE)
194#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000195
196/* word tokens, cannot mean something else if not expected */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000197#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
198 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000199
200/* discard newlines after these */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000201#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
202 | TC_BINOP | TC_OPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000203
204/* what can expression begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000205#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000206/* what can group begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000207#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000208
209/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
210/* operator is inserted between them */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000211#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
212 | TC_STRING | TC_NUMBER | TC_UOPPOST)
213#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000214
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000215#define OF_RES1 0x010000
216#define OF_RES2 0x020000
217#define OF_STR1 0x040000
218#define OF_STR2 0x080000
219#define OF_NUM1 0x100000
220#define OF_CHECKED 0x200000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000221
222/* combined operator flags */
223#define xx 0
224#define xV OF_RES2
225#define xS (OF_RES2 | OF_STR2)
226#define Vx OF_RES1
227#define VV (OF_RES1 | OF_RES2)
228#define Nx (OF_RES1 | OF_NUM1)
229#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
230#define Sx (OF_RES1 | OF_STR1)
231#define SV (OF_RES1 | OF_STR1 | OF_RES2)
232#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
233
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000234#define OPCLSMASK 0xFF00
235#define OPNMASK 0x007F
Glenn L McGrath545106f2002-11-11 06:21:00 +0000236
237/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
238 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
239 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
240 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000241#define P(x) (x << 24)
242#define PRIMASK 0x7F000000
243#define PRIMASK2 0x7E000000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000244
245/* Operation classes */
246
247#define SHIFT_TIL_THIS 0x0600
248#define RECUR_FROM_THIS 0x1000
249
250enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000251 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
252 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000253
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000254 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
255 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
256 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000257
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000258 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
259 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
260 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
261 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
262 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
263 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
264 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
265 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
266 OC_DONE = 0x2800,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000267
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000268 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
269 ST_WHILE = 0x3300
Glenn L McGrath545106f2002-11-11 06:21:00 +0000270};
271
272/* simple builtins */
273enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000274 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000275 F_ti, F_le, F_sy, F_ff, F_cl
276};
277
278/* builtins */
279enum {
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +0200280 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_mt, B_lo, B_up,
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000281 B_ge, B_gs, B_su,
282 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000283};
284
285/* tokens and their corresponding info values */
286
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200287#define NTC "\377" /* switch to next token class (tc<<1) */
288#define NTCC '\377'
Glenn L McGrath545106f2002-11-11 06:21:00 +0000289
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200290#define OC_B OC_BUILTIN
Glenn L McGrath545106f2002-11-11 06:21:00 +0000291
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000292static const char tokenlist[] ALIGN1 =
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200293 "\1(" NTC
294 "\1)" NTC
295 "\1/" NTC /* REGEXP */
296 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
297 "\2++" "\2--" NTC /* UOPPOST */
298 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
299 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
300 "\2*=" "\2/=" "\2%=" "\2^="
301 "\1+" "\1-" "\3**=" "\2**"
302 "\1/" "\1%" "\1^" "\1*"
303 "\2!=" "\2>=" "\2<=" "\1>"
304 "\1<" "\2!~" "\1~" "\2&&"
305 "\2||" "\1?" "\1:" NTC
306 "\2in" NTC
307 "\1," NTC
308 "\1|" NTC
309 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
310 "\1]" NTC
311 "\1{" NTC
312 "\1}" NTC
313 "\1;" NTC
314 "\1\n" NTC
315 "\2if" "\2do" "\3for" "\5break" /* STATX */
316 "\10continue" "\6delete" "\5print"
317 "\6printf" "\4next" "\10nextfile"
318 "\6return" "\4exit" NTC
319 "\5while" NTC
320 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000321
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200322 "\3and" "\5compl" "\6lshift" "\2or"
323 "\6rshift" "\3xor"
324 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
325 "\3cos" "\3exp" "\3int" "\3log"
326 "\4rand" "\3sin" "\4sqrt" "\5srand"
327 "\6gensub" "\4gsub" "\5index" "\6length"
328 "\5match" "\5split" "\7sprintf" "\3sub"
329 "\6substr" "\7systime" "\10strftime" "\6mktime"
330 "\7tolower" "\7toupper" NTC
331 "\7getline" NTC
332 "\4func" "\10function" NTC
333 "\5BEGIN" NTC
334 "\3END"
335 /* compiler adds trailing "\0" */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000336 ;
337
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000338static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000339 0,
340 0,
341 OC_REGEXP,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200342 xS|'a', xS|'w', xS|'|',
343 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
344 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5),
345 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
346 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
347 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
348 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
349 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
350 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
351 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':',
352 OC_IN|SV|P(49), /* in */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000353 OC_COMMA|SS|P(80),
354 OC_PGETLINE|SV|P(37),
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200355 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!',
356 0, /* ] */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000357 0,
358 0,
359 0,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200360 0, /* \n */
361 ST_IF, ST_DO, ST_FOR, OC_BREAK,
362 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
363 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
364 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000365 ST_WHILE,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200366 0, /* else */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000367
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000368 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
369 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000370 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
371 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
372 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
373 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
374 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +0200375 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000376 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
377 OC_GETLINE|SV|P(0),
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200378 0, 0,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000379 0,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200380 0 /* END */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000381};
382
383/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000384/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000385enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000386 CONVFMT, OFMT, FS, OFS,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000387 ORS, RS, RT, FILENAME,
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000388 SUBSEP, F0, ARGIND, ARGC,
389 ARGV, ERRNO, FNR, NR,
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200390 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS
Glenn L McGrath545106f2002-11-11 06:21:00 +0000391};
392
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000393static const char vNames[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000394 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
395 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000396 "SUBSEP\0" "$\0*" "ARGIND\0" "ARGC\0"
397 "ARGV\0" "ERRNO\0" "FNR\0" "NR\0"
398 "NF\0*" "IGNORECASE\0*" "ENVIRON\0" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000399
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000400static const char vValues[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000401 "%.6g\0" "%.6g\0" " \0" " \0"
402 "\n\0" "\n\0" "\0" "\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000403 "\034\0" "\0" "\377";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000404
405/* hash size may grow to these values */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000406#define FIRST_PRIME 61
407static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000408
Glenn L McGrath545106f2002-11-11 06:21:00 +0000409
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000410/* Globals. Split in two parts so that first one is addressed
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000411 * with (mostly short) negative offsets.
412 * NB: it's unsafe to put members of type "double"
413 * into globals2 (gcc may fail to align them).
414 */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000415struct globals {
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000416 double t_double;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000417 chain beginseq, mainseq, endseq;
418 chain *seq;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000419 node *break_ptr, *continue_ptr;
420 rstream *iF;
421 xhash *vhash, *ahash, *fdhash, *fnhash;
422 const char *g_progname;
423 int g_lineno;
424 int nfields;
425 int maxfields; /* used in fsrealloc() only */
426 var *Fields;
427 nvblock *g_cb;
428 char *g_pos;
429 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000430 smallint icase;
431 smallint exiting;
432 smallint nextrec;
433 smallint nextfile;
434 smallint is_f0_split;
435};
436struct globals2 {
437 uint32_t t_info; /* often used */
438 uint32_t t_tclass;
439 char *t_string;
440 int t_lineno;
441 int t_rollback;
442
443 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000444
445 /* former statics from various functions */
446 char *split_f0__fstrings;
447
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000448 uint32_t next_token__save_tclass;
449 uint32_t next_token__save_info;
450 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000451 smallint next_token__concat_inserted;
452
453 smallint next_input_file__files_happen;
454 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000455
456 var *evaluate__fnargs;
457 unsigned evaluate__seed;
458 regex_t evaluate__sreg;
459
460 var ptest__v;
461
462 tsplitter exec_builtin__tspl;
463
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000464 /* biggest and least used members go last */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000465 tsplitter fsplitter, rsplitter;
Denys Vlasenko3dbc5a92010-02-05 14:54:22 +0100466};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000467#define G1 (ptr_to_globals[-1])
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000468#define G (*(struct globals2 *)ptr_to_globals)
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000469/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000470/*char G1size[sizeof(G1)]; - 0x74 */
471/*char Gsize[sizeof(G)]; - 0x1c4 */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000472/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000473/*char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
474#define t_double (G1.t_double )
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000475#define beginseq (G1.beginseq )
476#define mainseq (G1.mainseq )
477#define endseq (G1.endseq )
478#define seq (G1.seq )
479#define break_ptr (G1.break_ptr )
480#define continue_ptr (G1.continue_ptr)
481#define iF (G1.iF )
482#define vhash (G1.vhash )
483#define ahash (G1.ahash )
484#define fdhash (G1.fdhash )
485#define fnhash (G1.fnhash )
486#define g_progname (G1.g_progname )
487#define g_lineno (G1.g_lineno )
488#define nfields (G1.nfields )
489#define maxfields (G1.maxfields )
490#define Fields (G1.Fields )
491#define g_cb (G1.g_cb )
492#define g_pos (G1.g_pos )
493#define g_buf (G1.g_buf )
494#define icase (G1.icase )
495#define exiting (G1.exiting )
496#define nextrec (G1.nextrec )
497#define nextfile (G1.nextfile )
498#define is_f0_split (G1.is_f0_split )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000499#define t_info (G.t_info )
500#define t_tclass (G.t_tclass )
501#define t_string (G.t_string )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000502#define t_lineno (G.t_lineno )
503#define t_rollback (G.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000504#define intvar (G.intvar )
505#define fsplitter (G.fsplitter )
506#define rsplitter (G.rsplitter )
507#define INIT_G() do { \
Denys Vlasenko90a99042009-09-06 02:36:23 +0200508 SET_PTR_TO_GLOBALS((char*)xzalloc(sizeof(G1)+sizeof(G)) + sizeof(G1)); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000509 G.next_token__ltclass = TC_OPTERM; \
510 G.evaluate__seed = 1; \
511} while (0)
512
Glenn L McGrath545106f2002-11-11 06:21:00 +0000513
514/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000515static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000516static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000517static void chain_group(void);
518static var *evaluate(node *, var *);
519static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000520static int fmt_num(char *, int, const char *, double, int);
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000521static int awk_exit(int) NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000522
523/* ---- error handling ---- */
524
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000525static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
526static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
527static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
528static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
529static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
530static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
531static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
532static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
533static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000534static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000535
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100536static void zero_out_var(var *vp)
Denis Vlasenkof782f522007-01-01 23:51:30 +0000537{
538 memset(vp, 0, sizeof(*vp));
539}
540
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000541static void syntax_error(const char *message) NORETURN;
542static void syntax_error(const char *message)
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000543{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000544 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000545}
546
Glenn L McGrath545106f2002-11-11 06:21:00 +0000547/* ---- hash stuff ---- */
548
Denis Vlasenkof782f522007-01-01 23:51:30 +0000549static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000550{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000551 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000552
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100553 while (*name)
554 idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000555 return idx;
556}
557
558/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000559static xhash *hash_init(void)
560{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000561 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000562
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100563 newhash = xzalloc(sizeof(*newhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000564 newhash->csize = FIRST_PRIME;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100565 newhash->items = xzalloc(FIRST_PRIME * sizeof(newhash->items[0]));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000566
567 return newhash;
568}
569
570/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000571static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000572{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000573 hash_item *hi;
574
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100575 hi = hash->items[hashidx(name) % hash->csize];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000576 while (hi) {
577 if (strcmp(hi->name, name) == 0)
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100578 return &hi->data;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000579 hi = hi->next;
580 }
581 return NULL;
582}
583
584/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000585static void hash_rebuild(xhash *hash)
586{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000587 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000588 hash_item **newitems, *hi, *thi;
589
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000590 if (hash->nprime == ARRAY_SIZE(PRIMES))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000591 return;
592
593 newsize = PRIMES[hash->nprime++];
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100594 newitems = xzalloc(newsize * sizeof(newitems[0]));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000595
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000596 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000597 hi = hash->items[i];
598 while (hi) {
599 thi = hi;
600 hi = thi->next;
601 idx = hashidx(thi->name) % newsize;
602 thi->next = newitems[idx];
603 newitems[idx] = thi;
604 }
605 }
606
607 free(hash->items);
608 hash->csize = newsize;
609 hash->items = newitems;
610}
611
612/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000613static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000614{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000615 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000616 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000617 int l;
618
619 hi = hash_search(hash, name);
Denis Vlasenkob78c7822007-07-18 18:31:11 +0000620 if (!hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000621 if (++hash->nel / hash->csize > 10)
622 hash_rebuild(hash);
623
Rob Landleya3896512006-05-07 20:20:34 +0000624 l = strlen(name) + 1;
Denis Vlasenko7a676642009-03-15 22:20:31 +0000625 hi = xzalloc(sizeof(*hi) + l);
626 strcpy(hi->name, name);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000627
628 idx = hashidx(name) % hash->csize;
629 hi->next = hash->items[idx];
630 hash->items[idx] = hi;
631 hash->glen += l;
632 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100633 return &hi->data;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000634}
635
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000636#define findvar(hash, name) ((var*) hash_find((hash), (name)))
637#define newvar(name) ((var*) hash_find(vhash, (name)))
638#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
639#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000640
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000641static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000642{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000643 hash_item *hi, **phi;
644
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100645 phi = &hash->items[hashidx(name) % hash->csize];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000646 while (*phi) {
647 hi = *phi;
648 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000649 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000650 hash->nel--;
651 *phi = hi->next;
652 free(hi);
653 break;
654 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100655 phi = &hi->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000656 }
657}
658
659/* ------ some useful functions ------ */
660
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100661static char *skip_spaces(char *p)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000662{
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000663 while (1) {
664 if (*p == '\\' && p[1] == '\n') {
665 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000666 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000667 } else if (*p != ' ' && *p != '\t') {
668 break;
669 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000670 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000671 }
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100672 return p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000673}
674
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100675/* returns old *s, advances *s past word and terminating NUL */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000676static char *nextword(char **s)
677{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000678 char *p = *s;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100679 while (*(*s)++ != '\0')
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100680 continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000681 return p;
682}
683
Mike Frysinger10a11e22005-09-27 02:23:02 +0000684static char nextchar(char **s)
685{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000686 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000687
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100688 c = *(*s)++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000689 pps = *s;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100690 if (c == '\\')
691 c = bb_process_escape_sequence((const char**)s);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +0200692 if (c == '\\' && *s == pps) { /* unrecognized \z? */
693 c = *(*s); /* yes, fetch z */
694 if (c)
695 (*s)++; /* advance unless z = NUL */
696 }
Glenn L McGrath545106f2002-11-11 06:21:00 +0000697 return c;
698}
699
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000700static ALWAYS_INLINE int isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000701{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000702 return (isalnum(c) || c == '_');
703}
704
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000705static double my_strtod(char **pp)
706{
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200707 char *cp = *pp;
Rob Landleyd8205b32010-10-24 03:27:22 +0200708 if (ENABLE_DESKTOP && cp[0] == '0') {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200709 /* Might be hex or octal integer: 0x123abc or 07777 */
710 char c = (cp[1] | 0x20);
711 if (c == 'x' || isdigit(cp[1])) {
712 unsigned long long ull = strtoull(cp, pp, 0);
713 if (c == 'x')
714 return ull;
715 c = **pp;
716 if (!isdigit(c) && c != '.')
717 return ull;
718 /* else: it may be a floating number. Examples:
719 * 009.123 (*pp points to '9')
720 * 000.123 (*pp points to '.')
721 * fall through to strtod.
722 */
723 }
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000724 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200725 return strtod(cp, pp);
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000726}
727
Glenn L McGrath545106f2002-11-11 06:21:00 +0000728/* -------- working with variables (set/get/copy/etc) -------- */
729
Mike Frysinger10a11e22005-09-27 02:23:02 +0000730static xhash *iamarray(var *v)
731{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000732 var *a = v;
733
734 while (a->type & VF_CHILD)
735 a = a->x.parent;
736
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000737 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000738 a->type |= VF_ARRAY;
739 a->x.array = hash_init();
740 }
741 return a->x.array;
742}
743
Mike Frysinger10a11e22005-09-27 02:23:02 +0000744static void clear_array(xhash *array)
745{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000746 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000747 hash_item *hi, *thi;
748
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000749 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000750 hi = array->items[i];
751 while (hi) {
752 thi = hi;
753 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000754 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000755 free(thi);
756 }
757 array->items[i] = NULL;
758 }
759 array->glen = array->nel = 0;
760}
761
762/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000763static var *clrvar(var *v)
764{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000765 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000766 free(v->string);
767
768 v->type &= VF_DONTTOUCH;
769 v->type |= VF_DIRTY;
770 v->string = NULL;
771 return v;
772}
773
774/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000775static var *setvar_p(var *v, char *value)
776{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000777 clrvar(v);
778 v->string = value;
779 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000780 return v;
781}
782
783/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000784static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000785{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000786 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000787}
788
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100789/* same as setvar_s but sets USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000790static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000791{
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100792 v = setvar_s(v, value);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000793 v->type |= VF_USER;
794 return v;
795}
796
797/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000798static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000799{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000800 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000801
Denys Vlasenko7bb346f2009-10-06 22:09:50 +0200802 v = findvar(iamarray(a), itoa(idx));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000803 setvar_u(v, s);
804}
805
806/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000807static var *setvar_i(var *v, double value)
808{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000809 clrvar(v);
810 v->type |= VF_NUMBER;
811 v->number = value;
812 handle_special(v);
813 return v;
814}
815
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000816static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000817{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000818 /* if v is numeric and has no cached string, convert it to string */
819 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000820 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
821 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000822 v->type |= VF_CACHED;
823 }
824 return (v->string == NULL) ? "" : v->string;
825}
826
Mike Frysinger10a11e22005-09-27 02:23:02 +0000827static double getvar_i(var *v)
828{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000829 char *s;
830
831 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
832 v->number = 0;
833 s = v->string;
834 if (s && *s) {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200835 debug_printf_eval("getvar_i: '%s'->", s);
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000836 v->number = my_strtod(&s);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200837 debug_printf_eval("%f (s:'%s')\n", v->number, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000838 if (v->type & VF_USER) {
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100839 s = skip_spaces(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000840 if (*s != '\0')
841 v->type &= ~VF_USER;
842 }
843 } else {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200844 debug_printf_eval("getvar_i: '%s'->zero\n", s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000845 v->type &= ~VF_USER;
846 }
847 v->type |= VF_CACHED;
848 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200849 debug_printf_eval("getvar_i: %f\n", v->number);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000850 return v->number;
851}
852
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000853/* Used for operands of bitwise ops */
854static unsigned long getvar_i_int(var *v)
855{
856 double d = getvar_i(v);
857
858 /* Casting doubles to longs is undefined for values outside
859 * of target type range. Try to widen it as much as possible */
860 if (d >= 0)
861 return (unsigned long)d;
Denis Vlasenko665eaff2008-09-05 04:59:02 +0000862 /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000863 return - (long) (unsigned long) (-d);
864}
865
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000866static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000867{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000868 if (dest != src) {
869 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000870 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200871 debug_printf_eval("copyvar: number:%f string:'%s'\n", src->number, src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000872 dest->number = src->number;
873 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000874 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000875 }
876 handle_special(dest);
877 return dest;
878}
879
Mike Frysinger10a11e22005-09-27 02:23:02 +0000880static var *incvar(var *v)
881{
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100882 return setvar_i(v, getvar_i(v) + 1.0);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000883}
884
885/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000886static int is_numeric(var *v)
887{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000888 getvar_i(v);
889 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
890}
891
892/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000893static int istrue(var *v)
894{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000895 if (is_numeric(v))
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100896 return (v->number != 0);
897 return (v->string && v->string[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000898}
899
Eric Andersenaff114c2004-04-14 17:51:38 +0000900/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000901static var *nvalloc(int n)
902{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000903 nvblock *pb = NULL;
904 var *v, *r;
905 int size;
906
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000907 while (g_cb) {
908 pb = g_cb;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100909 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size)
910 break;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000911 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000912 }
913
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000914 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000915 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000916 g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000917 g_cb->size = size;
918 g_cb->pos = g_cb->nv;
919 g_cb->prev = pb;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000920 /*g_cb->next = NULL; - xzalloc did it */
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100921 if (pb)
922 pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000923 }
924
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000925 v = r = g_cb->pos;
926 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000927
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000928 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000929 v->type = 0;
930 v->string = NULL;
931 v++;
932 }
933
934 return r;
935}
936
Mike Frysinger10a11e22005-09-27 02:23:02 +0000937static void nvfree(var *v)
938{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000939 var *p;
940
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000941 if (v < g_cb->nv || v >= g_cb->pos)
942 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000943
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000944 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000945 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000946 clear_array(iamarray(p));
947 free(p->x.array->items);
948 free(p->x.array);
949 }
Denys Vlasenko3cb60c32010-03-10 19:20:32 +0100950 if (p->type & VF_WALK) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +0100951 walker_list *n;
952 walker_list *w = p->x.walker;
953 debug_printf_walker("nvfree: freeing walker @%p\n", &p->x.walker);
954 p->x.walker = NULL;
955 while (w) {
956 n = w->prev;
957 debug_printf_walker(" free(%p)\n", w);
958 free(w);
959 w = n;
960 }
Denys Vlasenko3cb60c32010-03-10 19:20:32 +0100961 }
Glenn L McGrath545106f2002-11-11 06:21:00 +0000962 clrvar(p);
963 }
964
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000965 g_cb->pos = v;
966 while (g_cb->prev && g_cb->pos == g_cb->nv) {
967 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000968 }
969}
970
971/* ------- awk program text parsing ------- */
972
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000973/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000974 * If token isn't expected, give away. Return token class
975 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000976static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000977{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000978#define concat_inserted (G.next_token__concat_inserted)
979#define save_tclass (G.next_token__save_tclass)
980#define save_info (G.next_token__save_info)
981/* Initialized to TC_OPTERM: */
982#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000983
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100984 char *p, *s;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000985 const char *tl;
986 uint32_t tc;
987 const uint32_t *ti;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000988
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000989 if (t_rollback) {
990 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000991
992 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000993 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000994 t_tclass = save_tclass;
995 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000996
997 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000998 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000999 readnext:
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +01001000 p = skip_spaces(p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001001 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001002 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001003 while (*p != '\n' && *p != '\0')
1004 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001005
1006 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001007 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001008
1009 if (*p == '\0') {
1010 tc = TC_EOF;
1011
1012 } else if (*p == '\"') {
1013 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001014 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001015 while (*p != '\"') {
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02001016 char *pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001017 if (*p == '\0' || *p == '\n')
1018 syntax_error(EMSG_UNEXP_EOS);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02001019 pp = p;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001020 *s++ = nextchar(&pp);
1021 p = pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001022 }
1023 p++;
1024 *s = '\0';
1025 tc = TC_STRING;
1026
1027 } else if ((expected & TC_REGEXP) && *p == '/') {
1028 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001029 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001030 while (*p != '/') {
1031 if (*p == '\0' || *p == '\n')
1032 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +00001033 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001034 if (*s++ == '\\') {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001035 char *pp = p;
1036 s[-1] = bb_process_escape_sequence((const char **)&pp);
1037 if (*p == '\\')
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001038 *s++ = '\\';
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001039 if (pp == p)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001040 *s++ = *p++;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001041 else
1042 p = pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001043 }
1044 }
1045 p++;
1046 *s = '\0';
1047 tc = TC_REGEXP;
1048
1049 } else if (*p == '.' || isdigit(*p)) {
1050 /* it's a number */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001051 char *pp = p;
1052 t_double = my_strtod(&pp);
1053 p = pp;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001054 if (*p == '.')
Glenn L McGrath545106f2002-11-11 06:21:00 +00001055 syntax_error(EMSG_UNEXP_TOKEN);
1056 tc = TC_NUMBER;
1057
1058 } else {
1059 /* search for something known */
1060 tl = tokenlist;
1061 tc = 0x00000001;
1062 ti = tokeninfo;
1063 while (*tl) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001064 int l = (unsigned char) *tl++;
1065 if (l == (unsigned char) NTCC) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001066 tc <<= 1;
1067 continue;
1068 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001069 /* if token class is expected,
1070 * token matches,
1071 * and it's not a longer word,
Glenn L McGrath545106f2002-11-11 06:21:00 +00001072 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001073 if ((tc & (expected | TC_WORD | TC_NEWLINE))
Denys Vlasenko28458c62010-10-05 16:49:03 +02001074 && strncmp(p, tl, l) == 0
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001075 && !((tc & TC_WORD) && isalnum_(p[l]))
1076 ) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001077 /* then this is what we are looking for */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001078 t_info = *ti;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001079 p += l;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001080 goto token_found;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001081 }
1082 ti++;
1083 tl += l;
1084 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001085 /* not a known token */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001086
Denys Vlasenko28458c62010-10-05 16:49:03 +02001087 /* is it a name? (var/array/function) */
1088 if (!isalnum_(*p))
1089 syntax_error(EMSG_UNEXP_TOKEN); /* no */
1090 /* yes */
1091 t_string = --p;
1092 while (isalnum_(*++p)) {
1093 p[-1] = *p;
1094 }
1095 p[-1] = '\0';
1096 tc = TC_VARIABLE;
1097 /* also consume whitespace between functionname and bracket */
1098 if (!(expected & TC_VARIABLE) || (expected & TC_ARRAY))
1099 p = skip_spaces(p);
1100 if (*p == '(') {
1101 tc = TC_FUNCTION;
1102 } else {
1103 if (*p == '[') {
1104 p++;
1105 tc = TC_ARRAY;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001106 }
1107 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001108 token_found: ;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001109 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001110 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001111
1112 /* skipping newlines in some cases */
1113 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1114 goto readnext;
1115
1116 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001117 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001118 concat_inserted = TRUE;
1119 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001120 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001121 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001122 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001123 }
1124
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001125 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001126 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001127 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001128
1129 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001130 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001131 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001132 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001133
1134 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001135#undef concat_inserted
1136#undef save_tclass
1137#undef save_info
1138#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001139}
1140
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001141static void rollback_token(void)
1142{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001143 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001144}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001145
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001146static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001147{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001148 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001149
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001150 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001151 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001152 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001153 return n;
1154}
1155
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001156static void mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001157{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001158 n->info = OC_REGEXP;
1159 n->l.re = re;
1160 n->r.ire = re + 1;
1161 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001162 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001163}
1164
Mike Frysinger10a11e22005-09-27 02:23:02 +00001165static node *condition(void)
1166{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001167 next_token(TC_SEQSTART);
1168 return parse_expr(TC_SEQTERM);
1169}
1170
1171/* parse expression terminated by given argument, return ptr
1172 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001173static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001174{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001175 node sn;
1176 node *cn = &sn;
1177 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001178 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001179 var *v;
1180
1181 sn.info = PRIMASK;
1182 sn.r.n = glptr = NULL;
1183 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1184
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001185 while (!((tc = next_token(xtc)) & iexp)) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001186
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001187 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001188 /* input redirection (<) attached to glptr node */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001189 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001190 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001191 xtc = TC_OPERAND | TC_UOPPRE;
1192 glptr = NULL;
1193
1194 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1195 /* for binary and postfix-unary operators, jump back over
1196 * previous operators with higher priority */
1197 vn = cn;
Denys Vlasenkocdeda162009-11-30 01:14:16 +01001198 while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1199 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON))
1200 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001201 vn = vn->a.n;
Denys Vlasenkocdeda162009-11-30 01:14:16 +01001202 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001203 if ((t_info & OPCLSMASK) == OC_TERNARY)
1204 t_info += P(6);
1205 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001206 cn->a.n = vn->a.n;
1207 if (tc & TC_BINOP) {
1208 cn->l.n = vn;
1209 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001210 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001211 /* it's a pipe */
1212 next_token(TC_GETLINE);
1213 /* give maximum priority to this pipe */
1214 cn->info &= ~PRIMASK;
1215 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1216 }
1217 } else {
1218 cn->r.n = vn;
1219 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1220 }
1221 vn->a.n = cn;
1222
1223 } else {
1224 /* for operands and prefix-unary operators, attach them
1225 * to last node */
1226 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001227 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001228 cn->a.n = vn;
1229 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1230 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001231 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001232 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001233 * only simple tclasses should be used! */
1234 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001235 case TC_VARIABLE:
1236 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001237 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001238 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001239 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001240 cn->info = OC_FNARG;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001241 cn->l.aidx = v->x.aidx;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001242 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001243 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001244 }
1245 if (tc & TC_ARRAY) {
1246 cn->info |= xS;
1247 cn->r.n = parse_expr(TC_ARRTERM);
1248 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001249 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001250
Denis Vlasenkof782f522007-01-01 23:51:30 +00001251 case TC_NUMBER:
1252 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001253 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001254 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001255 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001256 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001257 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001258 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001259 break;
1260
Denis Vlasenkof782f522007-01-01 23:51:30 +00001261 case TC_REGEXP:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001262 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001263 break;
1264
Denis Vlasenkof782f522007-01-01 23:51:30 +00001265 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001266 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001267 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001268 cn->l.n = condition();
1269 break;
1270
Denis Vlasenkof782f522007-01-01 23:51:30 +00001271 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001272 cn = vn->r.n = parse_expr(TC_SEQTERM);
1273 cn->a.n = vn;
1274 break;
1275
Denis Vlasenkof782f522007-01-01 23:51:30 +00001276 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001277 glptr = cn;
1278 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1279 break;
1280
Denis Vlasenkof782f522007-01-01 23:51:30 +00001281 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001282 cn->l.n = condition();
1283 break;
1284 }
1285 }
1286 }
1287 }
1288 return sn.r.n;
1289}
1290
1291/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001292static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001293{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001294 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001295
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001296 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001297 seq->first = seq->last = new_node(0);
1298
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001299 if (seq->programname != g_progname) {
1300 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001301 n = chain_node(OC_NEWSOURCE);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001302 n->l.new_progname = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001303 }
1304
1305 n = seq->last;
1306 n->info = info;
1307 seq->last = n->a.n = new_node(OC_DONE);
1308
1309 return n;
1310}
1311
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001312static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001313{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001314 node *n;
1315
1316 n = chain_node(info);
1317 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001318 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001319 rollback_token();
1320}
1321
Mike Frysinger10a11e22005-09-27 02:23:02 +00001322static node *chain_loop(node *nn)
1323{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001324 node *n, *n2, *save_brk, *save_cont;
1325
1326 save_brk = break_ptr;
1327 save_cont = continue_ptr;
1328
1329 n = chain_node(OC_BR | Vx);
1330 continue_ptr = new_node(OC_EXEC);
1331 break_ptr = new_node(OC_EXEC);
1332 chain_group();
1333 n2 = chain_node(OC_EXEC | Vx);
1334 n2->l.n = nn;
1335 n2->a.n = n;
1336 continue_ptr->a.n = n2;
1337 break_ptr->a.n = n->r.n = seq->last;
1338
1339 continue_ptr = save_cont;
1340 break_ptr = save_brk;
1341
1342 return n;
1343}
1344
1345/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001346static void chain_group(void)
1347{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001348 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001349 node *n, *n2, *n3;
1350
1351 do {
1352 c = next_token(TC_GRPSEQ);
1353 } while (c & TC_NEWLINE);
1354
1355 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001356 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001357 if (t_tclass & TC_NEWLINE)
1358 continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001359 rollback_token();
1360 chain_group();
1361 }
1362 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1363 rollback_token();
1364 chain_expr(OC_EXEC | Vx);
1365 } else { /* TC_STATEMNT */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001366 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001367 case ST_IF:
1368 n = chain_node(OC_BR | Vx);
1369 n->l.n = condition();
1370 chain_group();
1371 n2 = chain_node(OC_EXEC);
1372 n->r.n = seq->last;
1373 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001374 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001375 n2->a.n = seq->last;
1376 } else {
1377 rollback_token();
1378 }
1379 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001380
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001381 case ST_WHILE:
1382 n2 = condition();
1383 n = chain_loop(NULL);
1384 n->l.n = n2;
1385 break;
1386
1387 case ST_DO:
1388 n2 = chain_node(OC_EXEC);
1389 n = chain_loop(NULL);
1390 n2->a.n = n->a.n;
1391 next_token(TC_WHILE);
1392 n->l.n = condition();
1393 break;
1394
1395 case ST_FOR:
1396 next_token(TC_SEQSTART);
1397 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001398 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001399 if ((n2->info & OPCLSMASK) != OC_IN)
1400 syntax_error(EMSG_UNEXP_TOKEN);
1401 n = chain_node(OC_WALKINIT | VV);
1402 n->l.n = n2->l.n;
1403 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001404 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001405 n->info = OC_WALKNEXT | Vx;
1406 n->l.n = n2->l.n;
1407 } else { /* for (;;) */
1408 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001409 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001410 n2 = parse_expr(TC_SEMICOL);
1411 n3 = parse_expr(TC_SEQTERM);
1412 n = chain_loop(n3);
1413 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001414 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001415 n->info = OC_EXEC;
1416 }
1417 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001418
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001419 case OC_PRINT:
1420 case OC_PRINTF:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001421 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001422 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001423 if (t_tclass & TC_OUTRDR) {
1424 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001425 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1426 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001427 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001428 rollback_token();
1429 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001430
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001431 case OC_BREAK:
1432 n = chain_node(OC_EXEC);
1433 n->a.n = break_ptr;
1434 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001435
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001436 case OC_CONTINUE:
1437 n = chain_node(OC_EXEC);
1438 n->a.n = continue_ptr;
1439 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001440
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001441 /* delete, next, nextfile, return, exit */
1442 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001443 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001444 }
1445 }
1446}
1447
Mike Frysinger10a11e22005-09-27 02:23:02 +00001448static void parse_program(char *p)
1449{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001450 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001451 node *cn;
1452 func *f;
1453 var *v;
1454
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001455 g_pos = p;
1456 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001457 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001458 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001459
1460 if (tclass & TC_OPTERM)
1461 continue;
1462
1463 seq = &mainseq;
1464 if (tclass & TC_BEGIN) {
1465 seq = &beginseq;
1466 chain_group();
1467
1468 } else if (tclass & TC_END) {
1469 seq = &endseq;
1470 chain_group();
1471
1472 } else if (tclass & TC_FUNCDECL) {
1473 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001474 g_pos++;
1475 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001476 f->body.first = NULL;
1477 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001478 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001479 v = findvar(ahash, t_string);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001480 v->x.aidx = f->nargs++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001481
1482 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1483 break;
1484 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001485 seq = &f->body;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001486 chain_group();
1487 clear_array(ahash);
1488
1489 } else if (tclass & TC_OPSEQ) {
1490 rollback_token();
1491 cn = chain_node(OC_TEST);
1492 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001493 if (t_tclass & TC_GRPSTART) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001494 rollback_token();
1495 chain_group();
1496 } else {
1497 chain_node(OC_PRINT);
1498 }
1499 cn->r.n = mainseq.last;
1500
1501 } else /* if (tclass & TC_GRPSTART) */ {
1502 rollback_token();
1503 chain_group();
1504 }
1505 }
1506}
1507
1508
1509/* -------- program execution part -------- */
1510
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001511static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001512{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001513 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001514 node *n;
1515
1516 re = &spl->re[0];
1517 ire = &spl->re[1];
1518 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001519 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001520 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001521 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001522 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001523 if (s[0] && s[1]) { /* strlen(s) > 1 */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001524 mk_re_node(s, n, re);
1525 } else {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001526 n->info = (uint32_t) s[0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001527 }
1528
1529 return n;
1530}
1531
1532/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001533 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001534 * be later regfree'd manually
1535 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001536static regex_t *as_regex(node *op, regex_t *preg)
1537{
Denis Vlasenko7a676642009-03-15 22:20:31 +00001538 int cflags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001539 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001540 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001541
1542 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1543 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001544 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001545 v = nvalloc(1);
1546 s = getvar_s(evaluate(op, v));
Denis Vlasenko7a676642009-03-15 22:20:31 +00001547
1548 cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED;
1549 /* Testcase where REG_EXTENDED fails (unpaired '{'):
1550 * echo Hi | awk 'gsub("@(samp|code|file)\{","");'
1551 * gawk 3.1.5 eats this. We revert to ~REG_EXTENDED
1552 * (maybe gsub is not supposed to use REG_EXTENDED?).
1553 */
1554 if (regcomp(preg, s, cflags)) {
1555 cflags &= ~REG_EXTENDED;
1556 xregcomp(preg, s, cflags);
1557 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001558 nvfree(v);
1559 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001560}
1561
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001562/* gradually increasing buffer.
1563 * note that we reallocate even if n == old_size,
1564 * and thus there is at least one extra allocated byte.
1565 */
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001566static char* qrealloc(char *b, int n, int *size)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001567{
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001568 if (!b || n >= *size) {
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001569 *size = n + (n>>1) + 80;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001570 b = xrealloc(b, *size);
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001571 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001572 return b;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001573}
1574
1575/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001576static void fsrealloc(int size)
1577{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001578 int i;
1579
1580 if (size >= maxfields) {
1581 i = maxfields;
1582 maxfields = size + 16;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001583 Fields = xrealloc(Fields, maxfields * sizeof(Fields[0]));
Denis Vlasenkof782f522007-01-01 23:51:30 +00001584 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001585 Fields[i].type = VF_SPECIAL;
1586 Fields[i].string = NULL;
1587 }
1588 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001589 /* if size < nfields, clear extra field variables */
1590 for (i = size; i < nfields; i++) {
1591 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001592 }
1593 nfields = size;
1594}
1595
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001596static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001597{
Denys Vlasenko28458c62010-10-05 16:49:03 +02001598 int l, n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001599 char c[4];
1600 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001601 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001602
1603 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001604 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1605 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001606
1607 c[0] = c[1] = (char)spl->info;
1608 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001609 if (*getvar_s(intvar[RS]) == '\0')
1610 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001611
Denys Vlasenko28458c62010-10-05 16:49:03 +02001612 n = 0;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001613 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1614 if (!*s)
1615 return n; /* "": zero fields */
1616 n++; /* at least one field will be there */
1617 do {
1618 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001619 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1620 && pmatch[0].rm_so <= l
1621 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001622 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001623 if (pmatch[0].rm_eo == 0) {
1624 l++;
1625 pmatch[0].rm_eo++;
1626 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001627 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001628 } else {
1629 pmatch[0].rm_eo = l;
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001630 if (s[l])
1631 pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001632 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001633 memcpy(s1, s, l);
Denis Vlasenko67b5eeb2009-04-12 13:54:13 +00001634 /* make sure we remove *all* of the separator chars */
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001635 do {
1636 s1[l] = '\0';
1637 } while (++l < pmatch[0].rm_eo);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001638 nextword(&s1);
1639 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001640 } while (*s);
1641 return n;
1642 }
1643 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001644 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001645 *s1++ = *s++;
1646 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001647 n++;
1648 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001649 return n;
1650 }
1651 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001652 if (icase) {
1653 c[0] = toupper(c[0]);
1654 c[1] = tolower(c[1]);
1655 }
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001656 if (*s1)
1657 n++;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001658 while ((s1 = strpbrk(s1, c)) != NULL) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001659 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001660 n++;
1661 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001662 return n;
1663 }
1664 /* space split */
1665 while (*s) {
1666 s = skip_whitespace(s);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001667 if (!*s)
1668 break;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001669 n++;
1670 while (*s && !isspace(*s))
1671 *s1++ = *s++;
1672 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001673 }
1674 return n;
1675}
1676
Mike Frysinger10a11e22005-09-27 02:23:02 +00001677static void split_f0(void)
1678{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001679/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001680#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001681
Glenn L McGrath545106f2002-11-11 06:21:00 +00001682 int i, n;
1683 char *s;
1684
1685 if (is_f0_split)
1686 return;
1687
1688 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001689 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001690 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001691 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001692 fsrealloc(n);
1693 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001694 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001695 Fields[i].string = nextword(&s);
1696 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1697 }
1698
1699 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001700 clrvar(intvar[NF]);
1701 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1702 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001703#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001704}
1705
1706/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001707static void handle_special(var *v)
1708{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001709 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001710 char *b;
1711 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001712 int sl, l, len, i, bsize;
1713
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001714 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001715 return;
1716
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001717 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001718 n = (int)getvar_i(v);
1719 fsrealloc(n);
1720
1721 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001722 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001723 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001724 b = NULL;
1725 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001726 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001727 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001728 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001729 if (b) {
1730 memcpy(b+len, sep, sl);
1731 len += sl;
1732 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001733 b = qrealloc(b, len+l+sl, &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001734 memcpy(b+len, s, l);
1735 len += l;
1736 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001737 if (b)
1738 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001739 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001740 is_f0_split = TRUE;
1741
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001742 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001743 is_f0_split = FALSE;
1744
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001745 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001746 mk_splitter(getvar_s(v), &fsplitter);
1747
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001748 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001749 mk_splitter(getvar_s(v), &rsplitter);
1750
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001751 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001752 icase = istrue(v);
1753
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001754 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001755 n = getvar_i(intvar[NF]);
1756 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001757 /* right here v is invalid. Just to note... */
1758 }
1759}
1760
1761/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001762static node *nextarg(node **pn)
1763{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001764 node *n;
1765
1766 n = *pn;
1767 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1768 *pn = n->r.n;
1769 n = n->l.n;
1770 } else {
1771 *pn = NULL;
1772 }
1773 return n;
1774}
1775
Mike Frysinger10a11e22005-09-27 02:23:02 +00001776static void hashwalk_init(var *v, xhash *array)
1777{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001778 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001779 unsigned i;
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001780 walker_list *w;
1781 walker_list *prev_walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001782
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001783 if (v->type & VF_WALK) {
1784 prev_walker = v->x.walker;
1785 } else {
1786 v->type |= VF_WALK;
1787 prev_walker = NULL;
1788 }
1789 debug_printf_walker("hashwalk_init: prev_walker:%p\n", prev_walker);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001790
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001791 w = v->x.walker = xzalloc(sizeof(*w) + array->glen + 1); /* why + 1? */
1792 debug_printf_walker(" walker@%p=%p\n", &v->x.walker, w);
1793 w->cur = w->end = w->wbuf;
1794 w->prev = prev_walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001795 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001796 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001797 while (hi) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001798 strcpy(w->end, hi->name);
1799 nextword(&w->end);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001800 hi = hi->next;
1801 }
1802 }
1803}
1804
Mike Frysinger10a11e22005-09-27 02:23:02 +00001805static int hashwalk_next(var *v)
1806{
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001807 walker_list *w = v->x.walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001808
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001809 if (w->cur >= w->end) {
1810 walker_list *prev_walker = w->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001811
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001812 debug_printf_walker("end of iteration, free(walker@%p:%p), prev_walker:%p\n", &v->x.walker, w, prev_walker);
1813 free(w);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001814 v->x.walker = prev_walker;
1815 return FALSE;
1816 }
1817
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001818 setvar_s(v, nextword(&w->cur));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001819 return TRUE;
1820}
1821
1822/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001823static int ptest(node *pattern)
1824{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001825 /* ptest__v is "static": to save stack space? */
1826 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001827}
1828
1829/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001830static int awk_getline(rstream *rsm, var *v)
1831{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001832 char *b;
1833 regmatch_t pmatch[2];
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001834 int size, a, p, pp = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001835 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001836 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001837
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02001838 debug_printf_eval("entered %s()\n", __func__);
1839
Glenn L McGrath545106f2002-11-11 06:21:00 +00001840 /* we're using our own buffer since we need access to accumulating
1841 * characters
1842 */
1843 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001844 m = rsm->buffer;
1845 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001846 p = rsm->pos;
1847 size = rsm->size;
1848 c = (char) rsplitter.n.info;
1849 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001850
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001851 if (!m)
1852 m = qrealloc(m, 256, &size);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001853
Glenn L McGrath545106f2002-11-11 06:21:00 +00001854 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001855 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001856 so = eo = p;
1857 r = 1;
1858 if (p > 0) {
1859 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1860 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001861 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001862 so = pmatch[0].rm_so;
1863 eo = pmatch[0].rm_eo;
1864 if (b[eo] != '\0')
1865 break;
1866 }
1867 } else if (c != '\0') {
1868 s = strchr(b+pp, c);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001869 if (!s)
1870 s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001871 if (s) {
1872 so = eo = s-b;
1873 eo++;
1874 break;
1875 }
1876 } else {
1877 while (b[rp] == '\n')
1878 rp++;
1879 s = strstr(b+rp, "\n\n");
1880 if (s) {
1881 so = eo = s-b;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001882 while (b[eo] == '\n')
1883 eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001884 if (b[eo] != '\0')
1885 break;
1886 }
1887 }
1888 }
1889
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001890 if (a > 0) {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001891 memmove(m, m+a, p+1);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001892 b = m;
1893 a = 0;
1894 }
1895
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001896 m = qrealloc(m, a+p+128, &size);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001897 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001898 pp = p;
1899 p += safe_read(fd, b+p, size-p-1);
1900 if (p < pp) {
1901 p = 0;
1902 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001903 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001904 }
1905 b[p] = '\0';
1906
1907 } while (p > pp);
1908
1909 if (p == 0) {
1910 r--;
1911 } else {
1912 c = b[so]; b[so] = '\0';
1913 setvar_s(v, b+rp);
1914 v->type |= VF_USER;
1915 b[so] = c;
1916 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001917 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001918 b[eo] = c;
1919 }
1920
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001921 rsm->buffer = m;
1922 rsm->adv = a + eo;
1923 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001924 rsm->size = size;
1925
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02001926 debug_printf_eval("returning from %s(): %d\n", __func__, r);
1927
Glenn L McGrath545106f2002-11-11 06:21:00 +00001928 return r;
1929}
1930
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001931static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001932{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001933 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001934 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001935 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001936
1937 if (int_as_int && n == (int)n) {
1938 r = snprintf(b, size, "%d", (int)n);
1939 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001940 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001941 if (strchr("diouxX", c)) {
1942 r = snprintf(b, size, format, (int)n);
1943 } else if (strchr("eEfgG", c)) {
1944 r = snprintf(b, size, format, n);
1945 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001946 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001947 }
1948 }
1949 return r;
1950}
1951
Glenn L McGrath545106f2002-11-11 06:21:00 +00001952/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001953static char *awk_printf(node *n)
1954{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001955 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001956 char *fmt, *s, *f;
1957 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001958 int i, j, incr, bsize;
1959 char c, c1;
1960 var *v, *arg;
1961
1962 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001963 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001964
1965 i = 0;
1966 while (*f) {
1967 s = f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001968 while (*f && (*f != '%' || *++f == '%'))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001969 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001970 while (*f && !isalpha(*f)) {
1971 if (*f == '*')
1972 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001973 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001974 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001975
1976 incr = (f - s) + MAXVARFMT;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001977 b = qrealloc(b, incr + i, &bsize);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001978 c = *f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001979 if (c != '\0')
1980 f++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001981 c1 = *f;
1982 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001983 arg = evaluate(nextarg(&n), v);
1984
1985 j = i;
1986 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001987 i += sprintf(b+i, s, is_numeric(arg) ?
1988 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001989 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001990 s1 = getvar_s(arg);
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001991 b = qrealloc(b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001992 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001993 } else {
1994 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1995 }
1996 *f = c1;
1997
1998 /* if there was an error while sprintf, return value is negative */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001999 if (i < j)
2000 i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002001 }
2002
Glenn L McGrath545106f2002-11-11 06:21:00 +00002003 free(fmt);
2004 nvfree(v);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002005 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002006 b[i] = '\0';
2007 return b;
2008}
2009
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002010/* Common substitution routine.
2011 * Replace (nm)'th substring of (src) that matches (rn) with (repl),
2012 * store result into (dest), return number of substitutions.
2013 * If nm = 0, replace all matches.
2014 * If src or dst is NULL, use $0.
2015 * If subexp != 0, enable subexpression matching (\1-\9).
Glenn L McGrath545106f2002-11-11 06:21:00 +00002016 */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002017static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int subexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002018{
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002019 char *resbuf;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002020 const char *sp;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002021 int match_no, residx, replen, resbufsize;
2022 int regexec_flags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002023 regmatch_t pmatch[10];
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002024 regex_t sreg, *regex;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002025
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002026 resbuf = NULL;
2027 residx = 0;
2028 match_no = 0;
2029 regexec_flags = 0;
2030 regex = as_regex(rn, &sreg);
2031 sp = getvar_s(src ? src : intvar[F0]);
2032 replen = strlen(repl);
2033 while (regexec(regex, sp, 10, pmatch, regexec_flags) == 0) {
2034 int so = pmatch[0].rm_so;
2035 int eo = pmatch[0].rm_eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002036
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002037 //bb_error_msg("match %u: [%u,%u] '%s'%p", match_no+1, so, eo, sp,sp);
2038 resbuf = qrealloc(resbuf, residx + eo + replen, &resbufsize);
2039 memcpy(resbuf + residx, sp, eo);
2040 residx += eo;
2041 if (++match_no >= nm) {
2042 const char *s;
2043 int nbs;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002044
Glenn L McGrath545106f2002-11-11 06:21:00 +00002045 /* replace */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002046 residx -= (eo - so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002047 nbs = 0;
2048 for (s = repl; *s; s++) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002049 char c = resbuf[residx++] = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002050 if (c == '\\') {
2051 nbs++;
2052 continue;
2053 }
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002054 if (c == '&' || (subexp && c >= '0' && c <= '9')) {
2055 int j;
2056 residx -= ((nbs + 3) >> 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002057 j = 0;
2058 if (c != '&') {
2059 j = c - '0';
2060 nbs++;
2061 }
2062 if (nbs % 2) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002063 resbuf[residx++] = c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002064 } else {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002065 int n = pmatch[j].rm_eo - pmatch[j].rm_so;
2066 resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize);
2067 memcpy(resbuf + residx, sp + pmatch[j].rm_so, n);
2068 residx += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002069 }
2070 }
2071 nbs = 0;
2072 }
2073 }
2074
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002075 regexec_flags = REG_NOTBOL;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002076 sp += eo;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002077 if (match_no == nm)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002078 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002079 if (eo == so) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002080 /* Empty match (e.g. "b*" will match anywhere).
2081 * Advance by one char. */
2082//BUG (bug 1333):
2083//gsub(/\<b*/,"") on "abc" will reach this point, advance to "bc"
2084//... and will erroneously match "b" even though it is NOT at the word start.
2085//we need REG_NOTBOW but it does not exist...
Denys Vlasenko7379cd12010-04-04 01:48:12 +02002086//TODO: if EXTRA_COMPAT=y, use GNU matching and re_search,
2087//it should be able to do it correctly.
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002088 /* Subtle: this is safe only because
2089 * qrealloc allocated at least one extra byte */
2090 resbuf[residx] = *sp;
2091 if (*sp == '\0')
2092 goto ret;
2093 sp++;
2094 residx++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002095 }
2096 }
2097
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002098 resbuf = qrealloc(resbuf, residx + strlen(sp), &resbufsize);
2099 strcpy(resbuf + residx, sp);
2100 ret:
2101 //bb_error_msg("end sp:'%s'%p", sp,sp);
2102 setvar_p(dest ? dest : intvar[F0], resbuf);
2103 if (regex == &sreg)
2104 regfree(regex);
2105 return match_no;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002106}
2107
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002108static NOINLINE int do_mktime(const char *ds)
2109{
2110 struct tm then;
2111 int count;
2112
2113 /*memset(&then, 0, sizeof(then)); - not needed */
2114 then.tm_isdst = -1; /* default is unknown */
2115
2116 /* manpage of mktime says these fields are ints,
2117 * so we can sscanf stuff directly into them */
2118 count = sscanf(ds, "%u %u %u %u %u %u %d",
2119 &then.tm_year, &then.tm_mon, &then.tm_mday,
2120 &then.tm_hour, &then.tm_min, &then.tm_sec,
2121 &then.tm_isdst);
2122
2123 if (count < 6
2124 || (unsigned)then.tm_mon < 1
2125 || (unsigned)then.tm_year < 1900
2126 ) {
2127 return -1;
2128 }
2129
2130 then.tm_mon -= 1;
Denys Vlasenkobc3e9472009-09-21 04:16:00 +02002131 then.tm_year -= 1900;
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002132
2133 return mktime(&then);
2134}
2135
2136static NOINLINE var *exec_builtin(node *op, var *res)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002137{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002138#define tspl (G.exec_builtin__tspl)
2139
Glenn L McGrath545106f2002-11-11 06:21:00 +00002140 var *tv;
2141 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002142 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002143 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002144 regmatch_t pmatch[2];
2145 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002146 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002147 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002148 int nargs;
2149 time_t tt;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002150 int i, l, ll, n;
2151
2152 tv = nvalloc(4);
2153 isr = info = op->info;
2154 op = op->l.n;
2155
2156 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002157 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002158 an[i] = nextarg(&op);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002159 if (isr & 0x09000000)
2160 av[i] = evaluate(an[i], &tv[i]);
2161 if (isr & 0x08000000)
2162 as[i] = getvar_s(av[i]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002163 isr >>= 1;
2164 }
2165
2166 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002167 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002168 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002169
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002170 info &= OPNMASK;
2171 switch (info) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002172
Denis Vlasenkof782f522007-01-01 23:51:30 +00002173 case B_a2:
Rob Landleyd8205b32010-10-24 03:27:22 +02002174 if (ENABLE_FEATURE_AWK_LIBM)
2175 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
2176 else
2177 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002178 break;
2179
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002180 case B_sp: {
2181 char *s, *s1;
2182
Glenn L McGrath545106f2002-11-11 06:21:00 +00002183 if (nargs > 2) {
2184 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2185 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2186 } else {
2187 spl = &fsplitter.n;
2188 }
2189
2190 n = awk_split(as[0], spl, &s);
2191 s1 = s;
2192 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002193 for (i = 1; i <= n; i++)
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002194 setari_u(av[1], i, nextword(&s));
2195 free(s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002196 setvar_i(res, n);
2197 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002198 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002199
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002200 case B_ss: {
2201 char *s;
2202
Rob Landleya3896512006-05-07 20:20:34 +00002203 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002204 i = getvar_i(av[1]) - 1;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002205 if (i > l)
2206 i = l;
2207 if (i < 0)
2208 i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002209 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002210 if (n < 0)
2211 n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002212 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002213 setvar_p(res, s);
2214 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002215 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002216
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002217 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2218 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002219 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002220 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002221 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002222
Denis Vlasenkof782f522007-01-01 23:51:30 +00002223 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002224 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002225 break;
2226
Denis Vlasenkof782f522007-01-01 23:51:30 +00002227 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002228 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002229 break;
2230
Denis Vlasenkof782f522007-01-01 23:51:30 +00002231 case B_or:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002232 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002233 break;
2234
Denis Vlasenkof782f522007-01-01 23:51:30 +00002235 case B_rs:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002236 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002237 break;
2238
Denis Vlasenkof782f522007-01-01 23:51:30 +00002239 case B_xo:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002240 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002241 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002242
Denis Vlasenkof782f522007-01-01 23:51:30 +00002243 case B_lo:
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002244 case B_up: {
2245 char *s, *s1;
Rob Landleyd921b2e2006-08-03 15:41:12 +00002246 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002247 while (*s1) {
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002248 //*s1 = (info == B_up) ? toupper(*s1) : tolower(*s1);
2249 if ((unsigned char)((*s1 | 0x20) - 'a') <= ('z' - 'a'))
2250 *s1 = (info == B_up) ? (*s1 & 0xdf) : (*s1 | 0x20);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002251 s1++;
2252 }
2253 setvar_p(res, s);
2254 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002255 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002256
Denis Vlasenkof782f522007-01-01 23:51:30 +00002257 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002258 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002259 ll = strlen(as[1]);
2260 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002261 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002262 if (!icase) {
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002263 char *s = strstr(as[0], as[1]);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002264 if (s)
2265 n = (s - as[0]) + 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002266 } else {
2267 /* this piece of code is terribly slow and
2268 * really should be rewritten
2269 */
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002270 for (i = 0; i <= l; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002271 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2272 n = i+1;
2273 break;
2274 }
2275 }
2276 }
2277 }
2278 setvar_i(res, n);
2279 break;
2280
Denis Vlasenkof782f522007-01-01 23:51:30 +00002281 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002282 if (nargs > 1)
2283 tt = getvar_i(av[1]);
2284 else
2285 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002286 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002287 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002288 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2289 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002290 g_buf[i] = '\0';
2291 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002292 break;
2293
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002294 case B_mt:
2295 setvar_i(res, do_mktime(as[0]));
2296 break;
2297
Denis Vlasenkof782f522007-01-01 23:51:30 +00002298 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002299 re = as_regex(an[1], &sreg);
2300 n = regexec(re, as[0], 1, pmatch, 0);
2301 if (n == 0) {
2302 pmatch[0].rm_so++;
2303 pmatch[0].rm_eo++;
2304 } else {
2305 pmatch[0].rm_so = 0;
2306 pmatch[0].rm_eo = -1;
2307 }
2308 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2309 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2310 setvar_i(res, pmatch[0].rm_so);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002311 if (re == &sreg)
2312 regfree(re);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002313 break;
2314
Denis Vlasenkof782f522007-01-01 23:51:30 +00002315 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002316 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2317 break;
2318
Denis Vlasenkof782f522007-01-01 23:51:30 +00002319 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002320 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2321 break;
2322
Denis Vlasenkof782f522007-01-01 23:51:30 +00002323 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002324 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2325 break;
2326 }
2327
2328 nvfree(tv);
2329 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002330#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002331}
2332
2333/*
2334 * Evaluate node - the heart of the program. Supplied with subtree
2335 * and place where to store result. returns ptr to result.
2336 */
2337#define XC(n) ((n) >> 8)
2338
Mike Frysinger10a11e22005-09-27 02:23:02 +00002339static var *evaluate(node *op, var *res)
2340{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002341/* This procedure is recursive so we should count every byte */
2342#define fnargs (G.evaluate__fnargs)
2343/* seed is initialized to 1 */
2344#define seed (G.evaluate__seed)
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002345#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002346
Glenn L McGrath545106f2002-11-11 06:21:00 +00002347 var *v1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002348
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002349 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002350 return setvar_s(res, NULL);
2351
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002352 debug_printf_eval("entered %s()\n", __func__);
2353
Glenn L McGrath545106f2002-11-11 06:21:00 +00002354 v1 = nvalloc(2);
2355
2356 while (op) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002357 struct {
2358 var *v;
2359 const char *s;
2360 } L = L; /* for compiler */
2361 struct {
2362 var *v;
2363 const char *s;
2364 } R = R;
2365 double L_d = L_d;
2366 uint32_t opinfo;
2367 int opn;
2368 node *op1;
2369
Glenn L McGrath545106f2002-11-11 06:21:00 +00002370 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002371 opn = (opinfo & OPNMASK);
2372 g_lineno = op->lineno;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002373 op1 = op->l.n;
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002374 debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002375
Mike Frysingerde2b9382005-09-27 03:18:00 +00002376 /* execute inevitable things */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002377 if (opinfo & OF_RES1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002378 L.v = evaluate(op1, v1);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002379 if (opinfo & OF_RES2)
2380 R.v = evaluate(op->r.n, v1+1);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002381 if (opinfo & OF_STR1) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002382 L.s = getvar_s(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002383 debug_printf_eval("L.s:'%s'\n", L.s);
2384 }
2385 if (opinfo & OF_STR2) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002386 R.s = getvar_s(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002387 debug_printf_eval("R.s:'%s'\n", R.s);
2388 }
2389 if (opinfo & OF_NUM1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002390 L_d = getvar_i(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002391 debug_printf_eval("L_d:%f\n", L_d);
2392 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002393
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002394 debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002395 switch (XC(opinfo & OPCLSMASK)) {
2396
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002397 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002398
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002399 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002400 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002401 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2402 /* it's range pattern */
2403 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2404 op->info |= OF_CHECKED;
2405 if (ptest(op1->r.n))
2406 op->info &= ~OF_CHECKED;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002407 op = op->a.n;
2408 } else {
2409 op = op->r.n;
2410 }
2411 } else {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002412 op = ptest(op1) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002413 }
2414 break;
2415
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002416 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002417 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002418 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002419
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002420 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002421 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002422 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002423 break;
2424
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002425 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002426 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002427 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002428 break;
2429
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002430 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002431 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002432 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2433 break;
2434
Denis Vlasenkof782f522007-01-01 23:51:30 +00002435 case XC( OC_PRINT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002436 case XC( OC_PRINTF ): {
2437 FILE *F = stdout;
2438
Mike Frysingerde2b9382005-09-27 03:18:00 +00002439 if (op->r.n) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002440 rstream *rsm = newfile(R.s);
2441 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002442 if (opn == '|') {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002443 rsm->F = popen(R.s, "w");
2444 if (rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002445 bb_perror_msg_and_die("popen");
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002446 rsm->is_pipe = 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002447 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002448 rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002449 }
2450 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002451 F = rsm->F;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002452 }
2453
2454 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002455 if (!op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002456 fputs(getvar_s(intvar[F0]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002457 } else {
2458 while (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002459 var *v = evaluate(nextarg(&op1), v1);
2460 if (v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002461 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002462 getvar_i(v), TRUE);
2463 fputs(g_buf, F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002464 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002465 fputs(getvar_s(v), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002466 }
2467
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002468 if (op1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002469 fputs(getvar_s(intvar[OFS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002470 }
2471 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002472 fputs(getvar_s(intvar[ORS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002473
2474 } else { /* OC_PRINTF */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002475 char *s = awk_printf(op1);
2476 fputs(s, F);
2477 free(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002478 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002479 fflush(F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002480 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002481 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002482
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002483 case XC( OC_DELETE ): {
2484 uint32_t info = op1->info & OPCLSMASK;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002485 var *v;
2486
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002487 if (info == OC_VAR) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002488 v = op1->l.v;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002489 } else if (info == OC_FNARG) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002490 v = &fnargs[op1->l.aidx];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002491 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002492 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002493 }
2494
Mike Frysingerde2b9382005-09-27 03:18:00 +00002495 if (op1->r.n) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002496 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002497 clrvar(L.v);
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002498 s = getvar_s(evaluate(op1->r.n, v1));
2499 hash_remove(iamarray(v), s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002500 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002501 clear_array(iamarray(v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002502 }
2503 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002504 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002505
Denis Vlasenkof782f522007-01-01 23:51:30 +00002506 case XC( OC_NEWSOURCE ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002507 g_progname = op->l.new_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002508 break;
2509
Denis Vlasenkof782f522007-01-01 23:51:30 +00002510 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002511 copyvar(res, L.v);
2512 break;
2513
Denis Vlasenkof782f522007-01-01 23:51:30 +00002514 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002515 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002516 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002517 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002518 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002519 clrvar(res);
2520 break;
2521
Denis Vlasenkof782f522007-01-01 23:51:30 +00002522 case XC( OC_EXIT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002523 awk_exit(L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002524
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002525 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002526
Denis Vlasenkof782f522007-01-01 23:51:30 +00002527 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002528 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002529 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002530 split_f0();
2531 goto v_cont;
2532
Denis Vlasenkof782f522007-01-01 23:51:30 +00002533 case XC( OC_FNARG ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002534 L.v = &fnargs[op->l.aidx];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002535 v_cont:
2536 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002537 break;
2538
Denis Vlasenkof782f522007-01-01 23:51:30 +00002539 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002540 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2541 break;
2542
Denis Vlasenkof782f522007-01-01 23:51:30 +00002543 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002544 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002545 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002546 goto re_cont;
2547
Denis Vlasenkof782f522007-01-01 23:51:30 +00002548 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002549 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002550 re_cont:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002551 {
2552 regex_t *re = as_regex(op1, &sreg);
2553 int i = regexec(re, L.s, 0, NULL, 0);
2554 if (re == &sreg)
2555 regfree(re);
2556 setvar_i(res, (i == 0) ^ (opn == '!'));
2557 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002558 break;
2559
Denis Vlasenkof782f522007-01-01 23:51:30 +00002560 case XC( OC_MOVE ):
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002561 debug_printf_eval("MOVE\n");
Mike Frysingerde2b9382005-09-27 03:18:00 +00002562 /* if source is a temporary string, jusk relink it to dest */
Denys Vlasenko12847742009-11-30 01:15:04 +01002563//Disabled: if R.v is numeric but happens to have cached R.v->string,
2564//then L.v ends up being a string, which is wrong
2565// if (R.v == v1+1 && R.v->string) {
2566// res = setvar_p(L.v, R.v->string);
2567// R.v->string = NULL;
2568// } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002569 res = copyvar(L.v, R.v);
Denys Vlasenko12847742009-11-30 01:15:04 +01002570// }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002571 break;
2572
Denis Vlasenkof782f522007-01-01 23:51:30 +00002573 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002574 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002575 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002576 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2577 break;
2578
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002579 case XC( OC_FUNC ): {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002580 var *vbeg, *v;
2581 const char *sv_progname;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002582
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002583 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002584 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002585
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002586 vbeg = v = nvalloc(op->r.f->nargs + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002587 while (op1) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002588 var *arg = evaluate(nextarg(&op1), v1);
2589 copyvar(v, arg);
2590 v->type |= VF_CHILD;
2591 v->x.parent = arg;
2592 if (++v - vbeg >= op->r.f->nargs)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002593 break;
2594 }
2595
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002596 v = fnargs;
2597 fnargs = vbeg;
2598 sv_progname = g_progname;
2599
2600 res = evaluate(op->r.f->body.first, res);
2601
2602 g_progname = sv_progname;
2603 nvfree(fnargs);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002604 fnargs = v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002605
Glenn L McGrath545106f2002-11-11 06:21:00 +00002606 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002607 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002608
Denis Vlasenkof782f522007-01-01 23:51:30 +00002609 case XC( OC_GETLINE ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002610 case XC( OC_PGETLINE ): {
2611 rstream *rsm;
2612 int i;
2613
Mike Frysingerde2b9382005-09-27 03:18:00 +00002614 if (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002615 rsm = newfile(L.s);
2616 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002617 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002618 rsm->F = popen(L.s, "r");
2619 rsm->is_pipe = TRUE;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002620 } else {
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002621 rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002622 }
2623 }
2624 } else {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002625 if (!iF)
2626 iF = next_input_file();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002627 rsm = iF;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002628 }
2629
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02002630 if (!rsm || !rsm->F) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002631 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002632 setvar_i(res, -1);
2633 break;
2634 }
2635
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002636 if (!op->r.n)
2637 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002638
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002639 i = awk_getline(rsm, R.v);
2640 if (i > 0 && !op1) {
2641 incvar(intvar[FNR]);
2642 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002643 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002644 setvar_i(res, i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002645 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002646 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002647
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002648 /* simple builtins */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002649 case XC( OC_FBLTIN ): {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002650 double R_d = R_d; /* for compiler */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002651
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002652 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002653 case F_in:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002654 R_d = (int)L_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002655 break;
2656
Denis Vlasenkof782f522007-01-01 23:51:30 +00002657 case F_rn:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002658 R_d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002659 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002660
Denis Vlasenkof782f522007-01-01 23:51:30 +00002661 case F_co:
Rob Landleyd8205b32010-10-24 03:27:22 +02002662 if (ENABLE_FEATURE_AWK_LIBM) {
2663 R_d = cos(L_d);
2664 break;
2665 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002666
Denis Vlasenkof782f522007-01-01 23:51:30 +00002667 case F_ex:
Rob Landleyd8205b32010-10-24 03:27:22 +02002668 if (ENABLE_FEATURE_AWK_LIBM) {
2669 R_d = exp(L_d);
2670 break;
2671 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002672
Denis Vlasenkof782f522007-01-01 23:51:30 +00002673 case F_lg:
Rob Landleyd8205b32010-10-24 03:27:22 +02002674 if (ENABLE_FEATURE_AWK_LIBM) {
2675 R_d = log(L_d);
2676 break;
2677 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002678
Denis Vlasenkof782f522007-01-01 23:51:30 +00002679 case F_si:
Rob Landleyd8205b32010-10-24 03:27:22 +02002680 if (ENABLE_FEATURE_AWK_LIBM) {
2681 R_d = sin(L_d);
2682 break;
2683 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002684
Denis Vlasenkof782f522007-01-01 23:51:30 +00002685 case F_sq:
Rob Landleyd8205b32010-10-24 03:27:22 +02002686 if (ENABLE_FEATURE_AWK_LIBM) {
2687 R_d = sqrt(L_d);
2688 break;
2689 }
2690
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002691 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002692 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002693
Denis Vlasenkof782f522007-01-01 23:51:30 +00002694 case F_sr:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002695 R_d = (double)seed;
2696 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002697 srand(seed);
2698 break;
2699
Denis Vlasenkof782f522007-01-01 23:51:30 +00002700 case F_ti:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002701 R_d = time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002702 break;
2703
Denis Vlasenkof782f522007-01-01 23:51:30 +00002704 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002705 if (!op1)
2706 L.s = getvar_s(intvar[F0]);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002707 R_d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002708 break;
2709
Denis Vlasenkof782f522007-01-01 23:51:30 +00002710 case F_sy:
Denys Vlasenko8131eea2009-11-02 14:19:51 +01002711 fflush_all();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002712 R_d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002713 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002714 break;
2715
Denis Vlasenkof782f522007-01-01 23:51:30 +00002716 case F_ff:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002717 if (!op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002718 fflush(stdout);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002719 } else if (L.s && *L.s) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002720 rstream *rsm = newfile(L.s);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002721 fflush(rsm->F);
2722 } else {
2723 fflush_all();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002724 }
2725 break;
2726
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002727 case F_cl: {
2728 rstream *rsm;
2729 int err = 0;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002730 rsm = (rstream *)hash_search(fdhash, L.s);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002731 debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002732 if (rsm) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002733 debug_printf_eval("OC_FBLTIN F_cl "
2734 "rsm->is_pipe:%d, ->F:%p\n",
2735 rsm->is_pipe, rsm->F);
2736 /* Can be NULL if open failed. Example:
2737 * getline line <"doesnt_exist";
2738 * close("doesnt_exist"); <--- here rsm->F is NULL
2739 */
2740 if (rsm->F)
2741 err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002742 free(rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002743 hash_remove(fdhash, L.s);
2744 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002745 if (err)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002746 setvar_i(intvar[ERRNO], errno);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002747 R_d = (double)err;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002748 break;
2749 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002750 } /* switch */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002751 setvar_i(res, R_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002752 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002753 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002754
Denis Vlasenkof782f522007-01-01 23:51:30 +00002755 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002756 res = exec_builtin(op, res);
2757 break;
2758
Denis Vlasenkof782f522007-01-01 23:51:30 +00002759 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002760 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002761 break;
2762
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002763 case XC( OC_UNARY ): {
2764 double Ld, R_d;
2765
2766 Ld = R_d = getvar_i(R.v);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002767 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002768 case 'P':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002769 Ld = ++R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002770 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002771 case 'p':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002772 R_d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002773 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002774 case 'M':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002775 Ld = --R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002776 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002777 case 'm':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002778 R_d--;
2779 r_op_change:
2780 setvar_i(R.v, R_d);
2781 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002782 case '!':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002783 Ld = !istrue(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002784 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002785 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002786 Ld = -R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002787 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002788 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002789 setvar_i(res, Ld);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002790 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002791 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002792
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002793 case XC( OC_FIELD ): {
2794 int i = (int)getvar_i(R.v);
2795 if (i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002796 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002797 } else {
2798 split_f0();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002799 if (i > nfields)
2800 fsrealloc(i);
2801 res = &Fields[i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002802 }
2803 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002804 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002805
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002806 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002807 case XC( OC_CONCAT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002808 case XC( OC_COMMA ): {
2809 const char *sep = "";
2810 if ((opinfo & OPCLSMASK) == OC_COMMA)
2811 sep = getvar_s(intvar[SUBSEP]);
2812 setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002813 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002814 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002815
Denis Vlasenkof782f522007-01-01 23:51:30 +00002816 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002817 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2818 break;
2819
Denis Vlasenkof782f522007-01-01 23:51:30 +00002820 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002821 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2822 break;
2823
Denis Vlasenkof782f522007-01-01 23:51:30 +00002824 case XC( OC_BINARY ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002825 case XC( OC_REPLACE ): {
2826 double R_d = getvar_i(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002827 debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002828 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002829 case '+':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002830 L_d += R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002831 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002832 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002833 L_d -= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002834 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002835 case '*':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002836 L_d *= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002837 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002838 case '/':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002839 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002840 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002841 L_d /= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002842 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002843 case '&':
Rob Landleyd8205b32010-10-24 03:27:22 +02002844 if (ENABLE_FEATURE_AWK_LIBM)
2845 L_d = pow(L_d, R_d);
2846 else
2847 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002848 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002849 case '%':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002850 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002851 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002852 L_d -= (int)(L_d / R_d) * R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002853 break;
2854 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002855 debug_printf_eval("BINARY/REPLACE result:%f\n", L_d);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002856 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002857 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002858 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002859
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002860 case XC( OC_COMPARE ): {
2861 int i = i; /* for compiler */
2862 double Ld;
2863
Glenn L McGrath545106f2002-11-11 06:21:00 +00002864 if (is_numeric(L.v) && is_numeric(R.v)) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002865 Ld = getvar_i(L.v) - getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002866 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002867 const char *l = getvar_s(L.v);
2868 const char *r = getvar_s(R.v);
2869 Ld = icase ? strcasecmp(l, r) : strcmp(l, r);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002870 }
2871 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002872 case 0:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002873 i = (Ld > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002874 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002875 case 2:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002876 i = (Ld >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002877 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002878 case 4:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002879 i = (Ld == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002880 break;
2881 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002882 setvar_i(res, (i == 0) ^ (opn & 1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002883 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002884 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002885
Denis Vlasenkof782f522007-01-01 23:51:30 +00002886 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002887 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002888 }
2889 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2890 op = op->a.n;
2891 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2892 break;
2893 if (nextrec)
2894 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002895 } /* while (op) */
2896
Glenn L McGrath545106f2002-11-11 06:21:00 +00002897 nvfree(v1);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002898 debug_printf_eval("returning from %s(): %p\n", __func__, res);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002899 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002900#undef fnargs
2901#undef seed
2902#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002903}
2904
2905
2906/* -------- main & co. -------- */
2907
Mike Frysinger10a11e22005-09-27 02:23:02 +00002908static int awk_exit(int r)
2909{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002910 var tv;
2911 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002912 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002913
Denis Vlasenkof782f522007-01-01 23:51:30 +00002914 zero_out_var(&tv);
2915
2916 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002917 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002918 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002919 evaluate(endseq.first, &tv);
2920 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002921
2922 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002923 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002924 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002925 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002926 if (hi->data.rs.F && hi->data.rs.is_pipe)
2927 pclose(hi->data.rs.F);
2928 hi = hi->next;
2929 }
2930 }
2931
2932 exit(r);
2933}
2934
2935/* if expr looks like "var=value", perform assignment and return 1,
2936 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002937static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002938{
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002939 char *exprc, *val, *s, *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002940
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002941 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002942 return FALSE;
2943 }
2944
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002945 exprc = xstrdup(expr);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002946 val = exprc + (val - expr);
2947 *val++ = '\0';
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002948
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002949 s = s1 = val;
2950 while ((*s1 = nextchar(&s)) != '\0')
2951 s1++;
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002952
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002953 setvar_u(newvar(exprc), val);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002954 free(exprc);
2955 return TRUE;
2956}
2957
2958/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002959static rstream *next_input_file(void)
2960{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002961#define rsm (G.next_input_file__rsm)
2962#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002963
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02002964 FILE *F;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002965 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002966
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002967 if (rsm.F)
2968 fclose(rsm.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002969 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002970 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002971
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02002972 for (;;) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002973 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002974 if (files_happen)
2975 return NULL;
2976 fname = "-";
2977 F = stdin;
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02002978 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002979 }
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02002980 ind = getvar_s(incvar(intvar[ARGIND]));
2981 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
2982 if (fname && *fname && !is_assignment(fname)) {
2983 F = xfopen_stdin(fname);
2984 break;
2985 }
2986 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002987
2988 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002989 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002990 rsm.F = F;
2991 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002992#undef rsm
2993#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002994}
2995
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002996int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00002997int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002998{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002999 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00003000 char *opt_F, *opt_W;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003001 llist_t *list_v = NULL;
3002 llist_t *list_f = NULL;
3003 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003004 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003005 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003006 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003007 char *vnames = (char *)vNames; /* cheat */
3008 char *vvalues = (char *)vValues;
3009
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003010 INIT_G();
3011
Denis Vlasenko150f4022007-01-13 21:06:21 +00003012 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00003013 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
3014 if (ENABLE_LOCALE_SUPPORT)
3015 setlocale(LC_NUMERIC, "C");
3016
Denis Vlasenkof782f522007-01-01 23:51:30 +00003017 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003018
3019 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003020 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003021
3022 vhash = hash_init();
3023 ahash = hash_init();
3024 fdhash = hash_init();
3025 fnhash = hash_init();
3026
3027 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003028 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003029 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00003030 if (*vvalues != '\377')
3031 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003032 else
3033 setvar_i(v, 0);
3034
Denis Vlasenkof782f522007-01-01 23:51:30 +00003035 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003036 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003037 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003038 }
3039 }
3040
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003041 handle_special(intvar[FS]);
3042 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003043
Denis Vlasenkof782f522007-01-01 23:51:30 +00003044 newfile("/dev/stdin")->F = stdin;
3045 newfile("/dev/stdout")->F = stdout;
3046 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003047
Denis Vlasenkof71d9162007-05-03 22:57:56 +00003048 /* Huh, people report that sometimes environ is NULL. Oh well. */
3049 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003050 /* environ is writable, thus we don't strdup it needlessly */
3051 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003052 char *s1 = strchr(s, '=');
3053 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003054 *s1 = '\0';
3055 /* Both findvar and setvar_u take const char*
3056 * as 2nd arg -> environment is not trashed */
3057 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
3058 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00003059 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003060 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003061 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
3062 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003063 argv += optind;
3064 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003065 if (opt & 0x1)
3066 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003067 while (list_v) { /* -v */
3068 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00003069 bb_show_usage();
3070 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003071 if (list_f) { /* -f */
3072 do {
3073 char *s = NULL;
3074 FILE *from_file;
3075
3076 g_progname = llist_pop(&list_f);
3077 from_file = xfopen_stdin(g_progname);
3078 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003079 for (i = j = 1; j > 0; i += j) {
3080 s = xrealloc(s, i + 4096);
3081 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00003082 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003083 s[i] = '\0';
3084 fclose(from_file);
3085 parse_program(s + 1);
3086 free(s);
3087 } while (list_f);
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00003088 argc++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003089 } else { // no -f: take program from 1st parameter
3090 if (!argc)
3091 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003092 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00003093 parse_program(*argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003094 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00003095 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00003096 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003097
Glenn L McGrath545106f2002-11-11 06:21:00 +00003098 /* fill in ARGV array */
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00003099 setvar_i(intvar[ARGC], argc);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003100 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00003101 i = 0;
3102 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003103 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003104
3105 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003106 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00003107 awk_exit(EXIT_SUCCESS);
3108
3109 /* input file could already be opened in BEGIN block */
Denys Vlasenkocdeda162009-11-30 01:14:16 +01003110 if (!iF)
3111 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003112
3113 /* passing through input files */
3114 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003115 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003116 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003117
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003118 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003119 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003120 incvar(intvar[NR]);
3121 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003122 evaluate(mainseq.first, &tv);
3123
3124 if (nextfile)
3125 break;
3126 }
3127
Denis Vlasenkof782f522007-01-01 23:51:30 +00003128 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003129 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003130
3131 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003132 }
3133
Glenn L McGrath545106f2002-11-11 06:21:00 +00003134 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003135 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00003136}