blob: 2eeb9d77aa674a3a4e14af6481dab9ded33d5337 [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
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000010#include "libbb.h"
Rob Landleyd921b2e2006-08-03 15:41:12 +000011#include "xregex.h"
12#include <math.h>
Glenn L McGrath545106f2002-11-11 06:21:00 +000013
Denis Vlasenko99912ca2007-04-10 15:43:37 +000014/* This is a NOEXEC applet. Be very careful! */
15
Glenn L McGrath545106f2002-11-11 06:21:00 +000016
Denys Vlasenkoda62b092010-03-11 12:13:18 +010017/* If you comment out one of these below, it will be #defined later
18 * to perform debug printfs to stderr: */
19#define debug_printf_walker(...) do {} while (0)
Denys Vlasenkod527e0c2010-10-05 13:22:11 +020020#define debug_printf_eval(...) do {} while (0)
Denys Vlasenkoda62b092010-03-11 12:13:18 +010021
22#ifndef debug_printf_walker
23# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__))
24#endif
Denys Vlasenkod527e0c2010-10-05 13:22:11 +020025#ifndef debug_printf_eval
26# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__))
27#endif
Denys Vlasenkoda62b092010-03-11 12:13:18 +010028
29
30
Denis Vlasenko629563b2007-02-24 17:05:52 +000031#define MAXVARFMT 240
32#define MINNVBLOCK 64
Glenn L McGrath545106f2002-11-11 06:21:00 +000033
34/* variable flags */
Denis Vlasenko629563b2007-02-24 17:05:52 +000035#define VF_NUMBER 0x0001 /* 1 = primary type is number */
36#define VF_ARRAY 0x0002 /* 1 = it's an array */
Glenn L McGrath545106f2002-11-11 06:21:00 +000037
Denis Vlasenko629563b2007-02-24 17:05:52 +000038#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
39#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
40#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
41#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
42#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
43#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
44#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
Glenn L McGrath545106f2002-11-11 06:21:00 +000045
46/* these flags are static, don't change them when value is changed */
Denis Vlasenko629563b2007-02-24 17:05:52 +000047#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
Glenn L McGrath545106f2002-11-11 06:21:00 +000048
Denys Vlasenkoda62b092010-03-11 12:13:18 +010049typedef struct walker_list {
50 char *end;
51 char *cur;
52 struct walker_list *prev;
53 char wbuf[1];
54} walker_list;
55
Glenn L McGrath545106f2002-11-11 06:21:00 +000056/* Variable */
57typedef struct var_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000058 unsigned type; /* flags */
Glenn L McGrath545106f2002-11-11 06:21:00 +000059 double number;
60 char *string;
61 union {
Denis Vlasenko629563b2007-02-24 17:05:52 +000062 int aidx; /* func arg idx (for compilation stage) */
63 struct xhash_s *array; /* array ptr */
64 struct var_s *parent; /* for func args, ptr to actual parameter */
Denys Vlasenkoda62b092010-03-11 12:13:18 +010065 walker_list *walker; /* list of array elements (for..in) */
Glenn L McGrath545106f2002-11-11 06:21:00 +000066 } x;
67} var;
68
69/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
70typedef struct chain_s {
71 struct node_s *first;
72 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +000073 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +000074} chain;
75
76/* Function */
77typedef struct func_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000078 unsigned nargs;
Glenn L McGrath545106f2002-11-11 06:21:00 +000079 struct chain_s body;
80} func;
81
82/* I/O stream */
83typedef struct rstream_s {
84 FILE *F;
85 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +000086 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +000087 int size;
88 int pos;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000089 smallint is_pipe;
Glenn L McGrath545106f2002-11-11 06:21:00 +000090} rstream;
91
92typedef struct hash_item_s {
93 union {
Denis Vlasenkoffba9412007-05-17 23:03:35 +000094 struct var_s v; /* variable/array hash */
95 struct rstream_s rs; /* redirect streams hash */
96 struct func_s f; /* functions hash */
Glenn L McGrath545106f2002-11-11 06:21:00 +000097 } data;
Denis Vlasenkoffba9412007-05-17 23:03:35 +000098 struct hash_item_s *next; /* next in chain */
99 char name[1]; /* really it's longer */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000100} hash_item;
101
102typedef struct xhash_s {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000103 unsigned nel; /* num of elements */
104 unsigned csize; /* current hash size */
105 unsigned nprime; /* next hash size in PRIMES[] */
106 unsigned glen; /* summary length of item names */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000107 struct hash_item_s **items;
108} xhash;
109
110/* Tree node */
111typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000112 uint32_t info;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000113 unsigned lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000114 union {
115 struct node_s *n;
116 var *v;
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100117 int aidx;
118 char *new_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000119 regex_t *re;
120 } l;
121 union {
122 struct node_s *n;
123 regex_t *ire;
124 func *f;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000125 } r;
126 union {
127 struct node_s *n;
128 } a;
129} node;
130
131/* Block of temporary variables */
132typedef struct nvblock_s {
133 int size;
134 var *pos;
135 struct nvblock_s *prev;
136 struct nvblock_s *next;
Denys Vlasenkod069e532009-09-09 23:12:10 +0200137 var nv[];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000138} nvblock;
139
140typedef struct tsplitter_s {
141 node n;
142 regex_t re[2];
143} tsplitter;
144
145/* simple token classes */
146/* Order and hex values are very important!!! See next_token() */
147#define TC_SEQSTART 1 /* ( */
148#define TC_SEQTERM (1 << 1) /* ) */
149#define TC_REGEXP (1 << 2) /* /.../ */
150#define TC_OUTRDR (1 << 3) /* | > >> */
151#define TC_UOPPOST (1 << 4) /* unary postfix operator */
152#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
153#define TC_BINOPX (1 << 6) /* two-opnd operator */
154#define TC_IN (1 << 7)
155#define TC_COMMA (1 << 8)
156#define TC_PIPE (1 << 9) /* input redirection pipe */
157#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
158#define TC_ARRTERM (1 << 11) /* ] */
159#define TC_GRPSTART (1 << 12) /* { */
160#define TC_GRPTERM (1 << 13) /* } */
161#define TC_SEMICOL (1 << 14)
162#define TC_NEWLINE (1 << 15)
163#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
164#define TC_WHILE (1 << 17)
165#define TC_ELSE (1 << 18)
166#define TC_BUILTIN (1 << 19)
167#define TC_GETLINE (1 << 20)
168#define TC_FUNCDECL (1 << 21) /* `function' `func' */
169#define TC_BEGIN (1 << 22)
170#define TC_END (1 << 23)
171#define TC_EOF (1 << 24)
172#define TC_VARIABLE (1 << 25)
173#define TC_ARRAY (1 << 26)
174#define TC_FUNCTION (1 << 27)
175#define TC_STRING (1 << 28)
176#define TC_NUMBER (1 << 29)
177
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000178#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000179
180/* combined token classes */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000181#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
182#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
183#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
184 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000185
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000186#define TC_STATEMNT (TC_STATX | TC_WHILE)
187#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000188
189/* word tokens, cannot mean something else if not expected */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000190#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
191 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000192
193/* discard newlines after these */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000194#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
195 | TC_BINOP | TC_OPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000196
197/* what can expression begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000198#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000199/* what can group begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000200#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000201
202/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
203/* operator is inserted between them */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000204#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
205 | TC_STRING | TC_NUMBER | TC_UOPPOST)
206#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000207
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000208#define OF_RES1 0x010000
209#define OF_RES2 0x020000
210#define OF_STR1 0x040000
211#define OF_STR2 0x080000
212#define OF_NUM1 0x100000
213#define OF_CHECKED 0x200000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000214
215/* combined operator flags */
216#define xx 0
217#define xV OF_RES2
218#define xS (OF_RES2 | OF_STR2)
219#define Vx OF_RES1
220#define VV (OF_RES1 | OF_RES2)
221#define Nx (OF_RES1 | OF_NUM1)
222#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
223#define Sx (OF_RES1 | OF_STR1)
224#define SV (OF_RES1 | OF_STR1 | OF_RES2)
225#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
226
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000227#define OPCLSMASK 0xFF00
228#define OPNMASK 0x007F
Glenn L McGrath545106f2002-11-11 06:21:00 +0000229
230/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
231 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
232 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
233 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000234#define P(x) (x << 24)
235#define PRIMASK 0x7F000000
236#define PRIMASK2 0x7E000000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000237
238/* Operation classes */
239
240#define SHIFT_TIL_THIS 0x0600
241#define RECUR_FROM_THIS 0x1000
242
243enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000244 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
245 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000246
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000247 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
248 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
249 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000250
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000251 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
252 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
253 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
254 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
255 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
256 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
257 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
258 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
259 OC_DONE = 0x2800,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000260
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000261 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
262 ST_WHILE = 0x3300
Glenn L McGrath545106f2002-11-11 06:21:00 +0000263};
264
265/* simple builtins */
266enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000267 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000268 F_ti, F_le, F_sy, F_ff, F_cl
269};
270
271/* builtins */
272enum {
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +0200273 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 +0000274 B_ge, B_gs, B_su,
275 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000276};
277
278/* tokens and their corresponding info values */
279
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200280#define NTC "\377" /* switch to next token class (tc<<1) */
281#define NTCC '\377'
Glenn L McGrath545106f2002-11-11 06:21:00 +0000282
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200283#define OC_B OC_BUILTIN
Glenn L McGrath545106f2002-11-11 06:21:00 +0000284
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000285static const char tokenlist[] ALIGN1 =
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200286 "\1(" NTC
287 "\1)" NTC
288 "\1/" NTC /* REGEXP */
289 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
290 "\2++" "\2--" NTC /* UOPPOST */
291 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
292 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
293 "\2*=" "\2/=" "\2%=" "\2^="
294 "\1+" "\1-" "\3**=" "\2**"
295 "\1/" "\1%" "\1^" "\1*"
296 "\2!=" "\2>=" "\2<=" "\1>"
297 "\1<" "\2!~" "\1~" "\2&&"
298 "\2||" "\1?" "\1:" NTC
299 "\2in" NTC
300 "\1," NTC
301 "\1|" NTC
302 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
303 "\1]" NTC
304 "\1{" NTC
305 "\1}" NTC
306 "\1;" NTC
307 "\1\n" NTC
308 "\2if" "\2do" "\3for" "\5break" /* STATX */
309 "\10continue" "\6delete" "\5print"
310 "\6printf" "\4next" "\10nextfile"
311 "\6return" "\4exit" NTC
312 "\5while" NTC
313 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000314
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200315 "\3and" "\5compl" "\6lshift" "\2or"
316 "\6rshift" "\3xor"
317 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
318 "\3cos" "\3exp" "\3int" "\3log"
319 "\4rand" "\3sin" "\4sqrt" "\5srand"
320 "\6gensub" "\4gsub" "\5index" "\6length"
321 "\5match" "\5split" "\7sprintf" "\3sub"
322 "\6substr" "\7systime" "\10strftime" "\6mktime"
323 "\7tolower" "\7toupper" NTC
324 "\7getline" NTC
325 "\4func" "\10function" NTC
326 "\5BEGIN" NTC
327 "\3END"
328 /* compiler adds trailing "\0" */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000329 ;
330
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000331static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000332 0,
333 0,
334 OC_REGEXP,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200335 xS|'a', xS|'w', xS|'|',
336 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
337 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5),
338 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
339 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
340 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
341 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
342 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
343 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
344 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':',
345 OC_IN|SV|P(49), /* in */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000346 OC_COMMA|SS|P(80),
347 OC_PGETLINE|SV|P(37),
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200348 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!',
349 0, /* ] */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000350 0,
351 0,
352 0,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200353 0, /* \n */
354 ST_IF, ST_DO, ST_FOR, OC_BREAK,
355 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
356 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
357 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000358 ST_WHILE,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200359 0, /* else */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000360
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000361 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
362 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000363 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
364 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
365 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
366 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
367 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 +0200368 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 +0000369 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
370 OC_GETLINE|SV|P(0),
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200371 0, 0,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000372 0,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200373 0 /* END */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000374};
375
376/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000377/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000378enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000379 CONVFMT, OFMT, FS, OFS,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000380 ORS, RS, RT, FILENAME,
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000381 SUBSEP, F0, ARGIND, ARGC,
382 ARGV, ERRNO, FNR, NR,
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200383 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS
Glenn L McGrath545106f2002-11-11 06:21:00 +0000384};
385
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000386static const char vNames[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000387 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
388 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000389 "SUBSEP\0" "$\0*" "ARGIND\0" "ARGC\0"
390 "ARGV\0" "ERRNO\0" "FNR\0" "NR\0"
391 "NF\0*" "IGNORECASE\0*" "ENVIRON\0" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000392
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000393static const char vValues[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000394 "%.6g\0" "%.6g\0" " \0" " \0"
395 "\n\0" "\n\0" "\0" "\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000396 "\034\0" "\0" "\377";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000397
398/* hash size may grow to these values */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000399#define FIRST_PRIME 61
400static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000401
Glenn L McGrath545106f2002-11-11 06:21:00 +0000402
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000403/* Globals. Split in two parts so that first one is addressed
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000404 * with (mostly short) negative offsets.
405 * NB: it's unsafe to put members of type "double"
406 * into globals2 (gcc may fail to align them).
407 */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000408struct globals {
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000409 double t_double;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000410 chain beginseq, mainseq, endseq;
411 chain *seq;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000412 node *break_ptr, *continue_ptr;
413 rstream *iF;
414 xhash *vhash, *ahash, *fdhash, *fnhash;
415 const char *g_progname;
416 int g_lineno;
417 int nfields;
418 int maxfields; /* used in fsrealloc() only */
419 var *Fields;
420 nvblock *g_cb;
421 char *g_pos;
422 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000423 smallint icase;
424 smallint exiting;
425 smallint nextrec;
426 smallint nextfile;
427 smallint is_f0_split;
428};
429struct globals2 {
430 uint32_t t_info; /* often used */
431 uint32_t t_tclass;
432 char *t_string;
433 int t_lineno;
434 int t_rollback;
435
436 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000437
438 /* former statics from various functions */
439 char *split_f0__fstrings;
440
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000441 uint32_t next_token__save_tclass;
442 uint32_t next_token__save_info;
443 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000444 smallint next_token__concat_inserted;
445
446 smallint next_input_file__files_happen;
447 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000448
449 var *evaluate__fnargs;
450 unsigned evaluate__seed;
451 regex_t evaluate__sreg;
452
453 var ptest__v;
454
455 tsplitter exec_builtin__tspl;
456
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000457 /* biggest and least used members go last */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000458 tsplitter fsplitter, rsplitter;
Denys Vlasenko3dbc5a92010-02-05 14:54:22 +0100459};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000460#define G1 (ptr_to_globals[-1])
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000461#define G (*(struct globals2 *)ptr_to_globals)
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000462/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000463/*char G1size[sizeof(G1)]; - 0x74 */
464/*char Gsize[sizeof(G)]; - 0x1c4 */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000465/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000466/*char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
467#define t_double (G1.t_double )
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000468#define beginseq (G1.beginseq )
469#define mainseq (G1.mainseq )
470#define endseq (G1.endseq )
471#define seq (G1.seq )
472#define break_ptr (G1.break_ptr )
473#define continue_ptr (G1.continue_ptr)
474#define iF (G1.iF )
475#define vhash (G1.vhash )
476#define ahash (G1.ahash )
477#define fdhash (G1.fdhash )
478#define fnhash (G1.fnhash )
479#define g_progname (G1.g_progname )
480#define g_lineno (G1.g_lineno )
481#define nfields (G1.nfields )
482#define maxfields (G1.maxfields )
483#define Fields (G1.Fields )
484#define g_cb (G1.g_cb )
485#define g_pos (G1.g_pos )
486#define g_buf (G1.g_buf )
487#define icase (G1.icase )
488#define exiting (G1.exiting )
489#define nextrec (G1.nextrec )
490#define nextfile (G1.nextfile )
491#define is_f0_split (G1.is_f0_split )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000492#define t_info (G.t_info )
493#define t_tclass (G.t_tclass )
494#define t_string (G.t_string )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000495#define t_lineno (G.t_lineno )
496#define t_rollback (G.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000497#define intvar (G.intvar )
498#define fsplitter (G.fsplitter )
499#define rsplitter (G.rsplitter )
500#define INIT_G() do { \
Denys Vlasenko90a99042009-09-06 02:36:23 +0200501 SET_PTR_TO_GLOBALS((char*)xzalloc(sizeof(G1)+sizeof(G)) + sizeof(G1)); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000502 G.next_token__ltclass = TC_OPTERM; \
503 G.evaluate__seed = 1; \
504} while (0)
505
Glenn L McGrath545106f2002-11-11 06:21:00 +0000506
507/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000508static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000509static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000510static void chain_group(void);
511static var *evaluate(node *, var *);
512static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000513static int fmt_num(char *, int, const char *, double, int);
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000514static int awk_exit(int) NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000515
516/* ---- error handling ---- */
517
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000518static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
519static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
520static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
521static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
522static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
523static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
524static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
525static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
526static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000527static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000528
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100529static void zero_out_var(var *vp)
Denis Vlasenkof782f522007-01-01 23:51:30 +0000530{
531 memset(vp, 0, sizeof(*vp));
532}
533
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000534static void syntax_error(const char *message) NORETURN;
535static void syntax_error(const char *message)
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000536{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000537 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000538}
539
Glenn L McGrath545106f2002-11-11 06:21:00 +0000540/* ---- hash stuff ---- */
541
Denis Vlasenkof782f522007-01-01 23:51:30 +0000542static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000543{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000544 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000545
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100546 while (*name)
547 idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000548 return idx;
549}
550
551/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000552static xhash *hash_init(void)
553{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000554 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000555
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100556 newhash = xzalloc(sizeof(*newhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000557 newhash->csize = FIRST_PRIME;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100558 newhash->items = xzalloc(FIRST_PRIME * sizeof(newhash->items[0]));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000559
560 return newhash;
561}
562
563/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000564static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000565{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000566 hash_item *hi;
567
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100568 hi = hash->items[hashidx(name) % hash->csize];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000569 while (hi) {
570 if (strcmp(hi->name, name) == 0)
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100571 return &hi->data;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000572 hi = hi->next;
573 }
574 return NULL;
575}
576
577/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000578static void hash_rebuild(xhash *hash)
579{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000580 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000581 hash_item **newitems, *hi, *thi;
582
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000583 if (hash->nprime == ARRAY_SIZE(PRIMES))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000584 return;
585
586 newsize = PRIMES[hash->nprime++];
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100587 newitems = xzalloc(newsize * sizeof(newitems[0]));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000588
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000589 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000590 hi = hash->items[i];
591 while (hi) {
592 thi = hi;
593 hi = thi->next;
594 idx = hashidx(thi->name) % newsize;
595 thi->next = newitems[idx];
596 newitems[idx] = thi;
597 }
598 }
599
600 free(hash->items);
601 hash->csize = newsize;
602 hash->items = newitems;
603}
604
605/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000606static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000607{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000608 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000609 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000610 int l;
611
612 hi = hash_search(hash, name);
Denis Vlasenkob78c7822007-07-18 18:31:11 +0000613 if (!hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000614 if (++hash->nel / hash->csize > 10)
615 hash_rebuild(hash);
616
Rob Landleya3896512006-05-07 20:20:34 +0000617 l = strlen(name) + 1;
Denis Vlasenko7a676642009-03-15 22:20:31 +0000618 hi = xzalloc(sizeof(*hi) + l);
619 strcpy(hi->name, name);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000620
621 idx = hashidx(name) % hash->csize;
622 hi->next = hash->items[idx];
623 hash->items[idx] = hi;
624 hash->glen += l;
625 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100626 return &hi->data;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000627}
628
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000629#define findvar(hash, name) ((var*) hash_find((hash), (name)))
630#define newvar(name) ((var*) hash_find(vhash, (name)))
631#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
632#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000633
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000634static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000635{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000636 hash_item *hi, **phi;
637
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100638 phi = &hash->items[hashidx(name) % hash->csize];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000639 while (*phi) {
640 hi = *phi;
641 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000642 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000643 hash->nel--;
644 *phi = hi->next;
645 free(hi);
646 break;
647 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100648 phi = &hi->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000649 }
650}
651
652/* ------ some useful functions ------ */
653
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100654static char *skip_spaces(char *p)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000655{
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000656 while (1) {
657 if (*p == '\\' && p[1] == '\n') {
658 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000659 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000660 } else if (*p != ' ' && *p != '\t') {
661 break;
662 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000663 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000664 }
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100665 return p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000666}
667
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100668/* returns old *s, advances *s past word and terminating NUL */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000669static char *nextword(char **s)
670{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000671 char *p = *s;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100672 while (*(*s)++ != '\0')
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100673 continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000674 return p;
675}
676
Mike Frysinger10a11e22005-09-27 02:23:02 +0000677static char nextchar(char **s)
678{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000679 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000680
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100681 c = *(*s)++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000682 pps = *s;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100683 if (c == '\\')
684 c = bb_process_escape_sequence((const char**)s);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +0200685 if (c == '\\' && *s == pps) { /* unrecognized \z? */
686 c = *(*s); /* yes, fetch z */
687 if (c)
688 (*s)++; /* advance unless z = NUL */
689 }
Glenn L McGrath545106f2002-11-11 06:21:00 +0000690 return c;
691}
692
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000693static ALWAYS_INLINE int isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000694{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000695 return (isalnum(c) || c == '_');
696}
697
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000698static double my_strtod(char **pp)
699{
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200700 char *cp = *pp;
Rob Landleyd8205b32010-10-24 03:27:22 +0200701 if (ENABLE_DESKTOP && cp[0] == '0') {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200702 /* Might be hex or octal integer: 0x123abc or 07777 */
703 char c = (cp[1] | 0x20);
704 if (c == 'x' || isdigit(cp[1])) {
705 unsigned long long ull = strtoull(cp, pp, 0);
706 if (c == 'x')
707 return ull;
708 c = **pp;
709 if (!isdigit(c) && c != '.')
710 return ull;
711 /* else: it may be a floating number. Examples:
712 * 009.123 (*pp points to '9')
713 * 000.123 (*pp points to '.')
714 * fall through to strtod.
715 */
716 }
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000717 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200718 return strtod(cp, pp);
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000719}
720
Glenn L McGrath545106f2002-11-11 06:21:00 +0000721/* -------- working with variables (set/get/copy/etc) -------- */
722
Mike Frysinger10a11e22005-09-27 02:23:02 +0000723static xhash *iamarray(var *v)
724{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000725 var *a = v;
726
727 while (a->type & VF_CHILD)
728 a = a->x.parent;
729
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000730 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000731 a->type |= VF_ARRAY;
732 a->x.array = hash_init();
733 }
734 return a->x.array;
735}
736
Mike Frysinger10a11e22005-09-27 02:23:02 +0000737static void clear_array(xhash *array)
738{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000739 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000740 hash_item *hi, *thi;
741
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000742 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000743 hi = array->items[i];
744 while (hi) {
745 thi = hi;
746 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000747 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000748 free(thi);
749 }
750 array->items[i] = NULL;
751 }
752 array->glen = array->nel = 0;
753}
754
755/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000756static var *clrvar(var *v)
757{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000758 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000759 free(v->string);
760
761 v->type &= VF_DONTTOUCH;
762 v->type |= VF_DIRTY;
763 v->string = NULL;
764 return v;
765}
766
767/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000768static var *setvar_p(var *v, char *value)
769{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000770 clrvar(v);
771 v->string = value;
772 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000773 return v;
774}
775
776/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000777static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000778{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000779 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000780}
781
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100782/* same as setvar_s but sets USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000783static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000784{
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100785 v = setvar_s(v, value);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000786 v->type |= VF_USER;
787 return v;
788}
789
790/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000791static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000792{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000793 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000794
Denys Vlasenko7bb346f2009-10-06 22:09:50 +0200795 v = findvar(iamarray(a), itoa(idx));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000796 setvar_u(v, s);
797}
798
799/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000800static var *setvar_i(var *v, double value)
801{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000802 clrvar(v);
803 v->type |= VF_NUMBER;
804 v->number = value;
805 handle_special(v);
806 return v;
807}
808
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000809static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000810{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000811 /* if v is numeric and has no cached string, convert it to string */
812 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000813 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
814 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000815 v->type |= VF_CACHED;
816 }
817 return (v->string == NULL) ? "" : v->string;
818}
819
Mike Frysinger10a11e22005-09-27 02:23:02 +0000820static double getvar_i(var *v)
821{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000822 char *s;
823
824 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
825 v->number = 0;
826 s = v->string;
827 if (s && *s) {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200828 debug_printf_eval("getvar_i: '%s'->", s);
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000829 v->number = my_strtod(&s);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200830 debug_printf_eval("%f (s:'%s')\n", v->number, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000831 if (v->type & VF_USER) {
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100832 s = skip_spaces(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000833 if (*s != '\0')
834 v->type &= ~VF_USER;
835 }
836 } else {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200837 debug_printf_eval("getvar_i: '%s'->zero\n", s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000838 v->type &= ~VF_USER;
839 }
840 v->type |= VF_CACHED;
841 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200842 debug_printf_eval("getvar_i: %f\n", v->number);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000843 return v->number;
844}
845
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000846/* Used for operands of bitwise ops */
847static unsigned long getvar_i_int(var *v)
848{
849 double d = getvar_i(v);
850
851 /* Casting doubles to longs is undefined for values outside
852 * of target type range. Try to widen it as much as possible */
853 if (d >= 0)
854 return (unsigned long)d;
Denis Vlasenko665eaff2008-09-05 04:59:02 +0000855 /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000856 return - (long) (unsigned long) (-d);
857}
858
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000859static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000860{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000861 if (dest != src) {
862 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000863 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200864 debug_printf_eval("copyvar: number:%f string:'%s'\n", src->number, src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000865 dest->number = src->number;
866 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000867 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000868 }
869 handle_special(dest);
870 return dest;
871}
872
Mike Frysinger10a11e22005-09-27 02:23:02 +0000873static var *incvar(var *v)
874{
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100875 return setvar_i(v, getvar_i(v) + 1.0);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000876}
877
878/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000879static int is_numeric(var *v)
880{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000881 getvar_i(v);
882 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
883}
884
885/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000886static int istrue(var *v)
887{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000888 if (is_numeric(v))
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100889 return (v->number != 0);
890 return (v->string && v->string[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000891}
892
Eric Andersenaff114c2004-04-14 17:51:38 +0000893/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000894static var *nvalloc(int n)
895{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000896 nvblock *pb = NULL;
897 var *v, *r;
898 int size;
899
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000900 while (g_cb) {
901 pb = g_cb;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100902 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size)
903 break;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000904 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000905 }
906
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000907 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000908 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000909 g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000910 g_cb->size = size;
911 g_cb->pos = g_cb->nv;
912 g_cb->prev = pb;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000913 /*g_cb->next = NULL; - xzalloc did it */
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100914 if (pb)
915 pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000916 }
917
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000918 v = r = g_cb->pos;
919 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000920
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000921 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000922 v->type = 0;
923 v->string = NULL;
924 v++;
925 }
926
927 return r;
928}
929
Mike Frysinger10a11e22005-09-27 02:23:02 +0000930static void nvfree(var *v)
931{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000932 var *p;
933
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000934 if (v < g_cb->nv || v >= g_cb->pos)
935 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000936
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000937 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000938 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000939 clear_array(iamarray(p));
940 free(p->x.array->items);
941 free(p->x.array);
942 }
Denys Vlasenko3cb60c32010-03-10 19:20:32 +0100943 if (p->type & VF_WALK) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +0100944 walker_list *n;
945 walker_list *w = p->x.walker;
946 debug_printf_walker("nvfree: freeing walker @%p\n", &p->x.walker);
947 p->x.walker = NULL;
948 while (w) {
949 n = w->prev;
950 debug_printf_walker(" free(%p)\n", w);
951 free(w);
952 w = n;
953 }
Denys Vlasenko3cb60c32010-03-10 19:20:32 +0100954 }
Glenn L McGrath545106f2002-11-11 06:21:00 +0000955 clrvar(p);
956 }
957
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000958 g_cb->pos = v;
959 while (g_cb->prev && g_cb->pos == g_cb->nv) {
960 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000961 }
962}
963
964/* ------- awk program text parsing ------- */
965
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000966/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000967 * If token isn't expected, give away. Return token class
968 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000969static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000970{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000971#define concat_inserted (G.next_token__concat_inserted)
972#define save_tclass (G.next_token__save_tclass)
973#define save_info (G.next_token__save_info)
974/* Initialized to TC_OPTERM: */
975#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000976
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100977 char *p, *s;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000978 const char *tl;
979 uint32_t tc;
980 const uint32_t *ti;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000981
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000982 if (t_rollback) {
983 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000984
985 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000986 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000987 t_tclass = save_tclass;
988 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000989
990 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000991 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +0000992 readnext:
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100993 p = skip_spaces(p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000994 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000995 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000996 while (*p != '\n' && *p != '\0')
997 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000998
999 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001000 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001001
1002 if (*p == '\0') {
1003 tc = TC_EOF;
1004
1005 } else if (*p == '\"') {
1006 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001007 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001008 while (*p != '\"') {
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02001009 char *pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001010 if (*p == '\0' || *p == '\n')
1011 syntax_error(EMSG_UNEXP_EOS);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02001012 pp = p;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001013 *s++ = nextchar(&pp);
1014 p = pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001015 }
1016 p++;
1017 *s = '\0';
1018 tc = TC_STRING;
1019
1020 } else if ((expected & TC_REGEXP) && *p == '/') {
1021 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001022 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001023 while (*p != '/') {
1024 if (*p == '\0' || *p == '\n')
1025 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +00001026 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001027 if (*s++ == '\\') {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001028 char *pp = p;
1029 s[-1] = bb_process_escape_sequence((const char **)&pp);
1030 if (*p == '\\')
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001031 *s++ = '\\';
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001032 if (pp == p)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001033 *s++ = *p++;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001034 else
1035 p = pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001036 }
1037 }
1038 p++;
1039 *s = '\0';
1040 tc = TC_REGEXP;
1041
1042 } else if (*p == '.' || isdigit(*p)) {
1043 /* it's a number */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001044 char *pp = p;
1045 t_double = my_strtod(&pp);
1046 p = pp;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001047 if (*p == '.')
Glenn L McGrath545106f2002-11-11 06:21:00 +00001048 syntax_error(EMSG_UNEXP_TOKEN);
1049 tc = TC_NUMBER;
1050
1051 } else {
1052 /* search for something known */
1053 tl = tokenlist;
1054 tc = 0x00000001;
1055 ti = tokeninfo;
1056 while (*tl) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001057 int l = (unsigned char) *tl++;
1058 if (l == (unsigned char) NTCC) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001059 tc <<= 1;
1060 continue;
1061 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001062 /* if token class is expected,
1063 * token matches,
1064 * and it's not a longer word,
Glenn L McGrath545106f2002-11-11 06:21:00 +00001065 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001066 if ((tc & (expected | TC_WORD | TC_NEWLINE))
Denys Vlasenko28458c62010-10-05 16:49:03 +02001067 && strncmp(p, tl, l) == 0
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001068 && !((tc & TC_WORD) && isalnum_(p[l]))
1069 ) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001070 /* then this is what we are looking for */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001071 t_info = *ti;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001072 p += l;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001073 goto token_found;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001074 }
1075 ti++;
1076 tl += l;
1077 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001078 /* not a known token */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001079
Denys Vlasenko28458c62010-10-05 16:49:03 +02001080 /* is it a name? (var/array/function) */
1081 if (!isalnum_(*p))
1082 syntax_error(EMSG_UNEXP_TOKEN); /* no */
1083 /* yes */
1084 t_string = --p;
1085 while (isalnum_(*++p)) {
1086 p[-1] = *p;
1087 }
1088 p[-1] = '\0';
1089 tc = TC_VARIABLE;
1090 /* also consume whitespace between functionname and bracket */
1091 if (!(expected & TC_VARIABLE) || (expected & TC_ARRAY))
1092 p = skip_spaces(p);
1093 if (*p == '(') {
1094 tc = TC_FUNCTION;
1095 } else {
1096 if (*p == '[') {
1097 p++;
1098 tc = TC_ARRAY;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001099 }
1100 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001101 token_found: ;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001102 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001103 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001104
1105 /* skipping newlines in some cases */
1106 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1107 goto readnext;
1108
1109 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001110 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001111 concat_inserted = TRUE;
1112 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001113 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001114 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001115 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001116 }
1117
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001118 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001119 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001120 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001121
1122 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001123 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001124 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001125 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001126
1127 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001128#undef concat_inserted
1129#undef save_tclass
1130#undef save_info
1131#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001132}
1133
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001134static void rollback_token(void)
1135{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001136 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001137}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001138
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001139static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001140{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001141 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001142
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001143 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001144 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001145 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001146 return n;
1147}
1148
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001149static void mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001150{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001151 n->info = OC_REGEXP;
1152 n->l.re = re;
1153 n->r.ire = re + 1;
1154 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001155 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001156}
1157
Mike Frysinger10a11e22005-09-27 02:23:02 +00001158static node *condition(void)
1159{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001160 next_token(TC_SEQSTART);
1161 return parse_expr(TC_SEQTERM);
1162}
1163
1164/* parse expression terminated by given argument, return ptr
1165 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001166static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001167{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001168 node sn;
1169 node *cn = &sn;
1170 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001171 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001172 var *v;
1173
1174 sn.info = PRIMASK;
1175 sn.r.n = glptr = NULL;
1176 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1177
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001178 while (!((tc = next_token(xtc)) & iexp)) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001179
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001180 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001181 /* input redirection (<) attached to glptr node */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001182 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001183 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001184 xtc = TC_OPERAND | TC_UOPPRE;
1185 glptr = NULL;
1186
1187 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1188 /* for binary and postfix-unary operators, jump back over
1189 * previous operators with higher priority */
1190 vn = cn;
Denys Vlasenkocdeda162009-11-30 01:14:16 +01001191 while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1192 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON))
1193 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001194 vn = vn->a.n;
Denys Vlasenkocdeda162009-11-30 01:14:16 +01001195 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001196 if ((t_info & OPCLSMASK) == OC_TERNARY)
1197 t_info += P(6);
1198 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001199 cn->a.n = vn->a.n;
1200 if (tc & TC_BINOP) {
1201 cn->l.n = vn;
1202 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001203 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001204 /* it's a pipe */
1205 next_token(TC_GETLINE);
1206 /* give maximum priority to this pipe */
1207 cn->info &= ~PRIMASK;
1208 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1209 }
1210 } else {
1211 cn->r.n = vn;
1212 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1213 }
1214 vn->a.n = cn;
1215
1216 } else {
1217 /* for operands and prefix-unary operators, attach them
1218 * to last node */
1219 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001220 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001221 cn->a.n = vn;
1222 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1223 if (tc & (TC_OPERAND | TC_REGEXP)) {
Rob Landleyed830e82005-06-07 02:43:52 +00001224 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001225 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001226 * only simple tclasses should be used! */
1227 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001228 case TC_VARIABLE:
1229 case TC_ARRAY:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001230 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001231 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001232 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001233 cn->info = OC_FNARG;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001234 cn->l.aidx = v->x.aidx;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001235 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001236 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001237 }
1238 if (tc & TC_ARRAY) {
1239 cn->info |= xS;
1240 cn->r.n = parse_expr(TC_ARRTERM);
1241 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001242 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001243
Denis Vlasenkof782f522007-01-01 23:51:30 +00001244 case TC_NUMBER:
1245 case TC_STRING:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001246 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001247 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001248 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001249 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001250 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001251 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001252 break;
1253
Denis Vlasenkof782f522007-01-01 23:51:30 +00001254 case TC_REGEXP:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001255 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001256 break;
1257
Denis Vlasenkof782f522007-01-01 23:51:30 +00001258 case TC_FUNCTION:
Mike Frysingerde2b9382005-09-27 03:18:00 +00001259 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001260 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001261 cn->l.n = condition();
1262 break;
1263
Denis Vlasenkof782f522007-01-01 23:51:30 +00001264 case TC_SEQSTART:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001265 cn = vn->r.n = parse_expr(TC_SEQTERM);
1266 cn->a.n = vn;
1267 break;
1268
Denis Vlasenkof782f522007-01-01 23:51:30 +00001269 case TC_GETLINE:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001270 glptr = cn;
1271 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1272 break;
1273
Denis Vlasenkof782f522007-01-01 23:51:30 +00001274 case TC_BUILTIN:
Glenn L McGrath545106f2002-11-11 06:21:00 +00001275 cn->l.n = condition();
1276 break;
1277 }
1278 }
1279 }
1280 }
1281 return sn.r.n;
1282}
1283
1284/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001285static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001286{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001287 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001288
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001289 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001290 seq->first = seq->last = new_node(0);
1291
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001292 if (seq->programname != g_progname) {
1293 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001294 n = chain_node(OC_NEWSOURCE);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001295 n->l.new_progname = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001296 }
1297
1298 n = seq->last;
1299 n->info = info;
1300 seq->last = n->a.n = new_node(OC_DONE);
1301
1302 return n;
1303}
1304
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001305static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001306{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001307 node *n;
1308
1309 n = chain_node(info);
1310 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001311 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001312 rollback_token();
1313}
1314
Mike Frysinger10a11e22005-09-27 02:23:02 +00001315static node *chain_loop(node *nn)
1316{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001317 node *n, *n2, *save_brk, *save_cont;
1318
1319 save_brk = break_ptr;
1320 save_cont = continue_ptr;
1321
1322 n = chain_node(OC_BR | Vx);
1323 continue_ptr = new_node(OC_EXEC);
1324 break_ptr = new_node(OC_EXEC);
1325 chain_group();
1326 n2 = chain_node(OC_EXEC | Vx);
1327 n2->l.n = nn;
1328 n2->a.n = n;
1329 continue_ptr->a.n = n2;
1330 break_ptr->a.n = n->r.n = seq->last;
1331
1332 continue_ptr = save_cont;
1333 break_ptr = save_brk;
1334
1335 return n;
1336}
1337
1338/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001339static void chain_group(void)
1340{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001341 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001342 node *n, *n2, *n3;
1343
1344 do {
1345 c = next_token(TC_GRPSEQ);
1346 } while (c & TC_NEWLINE);
1347
1348 if (c & TC_GRPSTART) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001349 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001350 if (t_tclass & TC_NEWLINE)
1351 continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001352 rollback_token();
1353 chain_group();
1354 }
1355 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1356 rollback_token();
1357 chain_expr(OC_EXEC | Vx);
1358 } else { /* TC_STATEMNT */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001359 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001360 case ST_IF:
1361 n = chain_node(OC_BR | Vx);
1362 n->l.n = condition();
1363 chain_group();
1364 n2 = chain_node(OC_EXEC);
1365 n->r.n = seq->last;
1366 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001367 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001368 n2->a.n = seq->last;
1369 } else {
1370 rollback_token();
1371 }
1372 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001373
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001374 case ST_WHILE:
1375 n2 = condition();
1376 n = chain_loop(NULL);
1377 n->l.n = n2;
1378 break;
1379
1380 case ST_DO:
1381 n2 = chain_node(OC_EXEC);
1382 n = chain_loop(NULL);
1383 n2->a.n = n->a.n;
1384 next_token(TC_WHILE);
1385 n->l.n = condition();
1386 break;
1387
1388 case ST_FOR:
1389 next_token(TC_SEQSTART);
1390 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001391 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001392 if ((n2->info & OPCLSMASK) != OC_IN)
1393 syntax_error(EMSG_UNEXP_TOKEN);
1394 n = chain_node(OC_WALKINIT | VV);
1395 n->l.n = n2->l.n;
1396 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001397 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001398 n->info = OC_WALKNEXT | Vx;
1399 n->l.n = n2->l.n;
1400 } else { /* for (;;) */
1401 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001402 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001403 n2 = parse_expr(TC_SEMICOL);
1404 n3 = parse_expr(TC_SEQTERM);
1405 n = chain_loop(n3);
1406 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001407 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001408 n->info = OC_EXEC;
1409 }
1410 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001411
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001412 case OC_PRINT:
1413 case OC_PRINTF:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001414 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001415 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001416 if (t_tclass & TC_OUTRDR) {
1417 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001418 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1419 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001420 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001421 rollback_token();
1422 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001423
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001424 case OC_BREAK:
1425 n = chain_node(OC_EXEC);
1426 n->a.n = break_ptr;
1427 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001428
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001429 case OC_CONTINUE:
1430 n = chain_node(OC_EXEC);
1431 n->a.n = continue_ptr;
1432 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001433
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001434 /* delete, next, nextfile, return, exit */
1435 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001436 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001437 }
1438 }
1439}
1440
Mike Frysinger10a11e22005-09-27 02:23:02 +00001441static void parse_program(char *p)
1442{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001443 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001444 node *cn;
1445 func *f;
1446 var *v;
1447
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001448 g_pos = p;
1449 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001450 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001451 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001452
1453 if (tclass & TC_OPTERM)
1454 continue;
1455
1456 seq = &mainseq;
1457 if (tclass & TC_BEGIN) {
1458 seq = &beginseq;
1459 chain_group();
1460
1461 } else if (tclass & TC_END) {
1462 seq = &endseq;
1463 chain_group();
1464
1465 } else if (tclass & TC_FUNCDECL) {
1466 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001467 g_pos++;
1468 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001469 f->body.first = NULL;
1470 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001471 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001472 v = findvar(ahash, t_string);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001473 v->x.aidx = f->nargs++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001474
1475 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1476 break;
1477 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001478 seq = &f->body;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001479 chain_group();
1480 clear_array(ahash);
1481
1482 } else if (tclass & TC_OPSEQ) {
1483 rollback_token();
1484 cn = chain_node(OC_TEST);
1485 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001486 if (t_tclass & TC_GRPSTART) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001487 rollback_token();
1488 chain_group();
1489 } else {
1490 chain_node(OC_PRINT);
1491 }
1492 cn->r.n = mainseq.last;
1493
1494 } else /* if (tclass & TC_GRPSTART) */ {
1495 rollback_token();
1496 chain_group();
1497 }
1498 }
1499}
1500
1501
1502/* -------- program execution part -------- */
1503
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001504static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001505{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001506 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001507 node *n;
1508
1509 re = &spl->re[0];
1510 ire = &spl->re[1];
1511 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001512 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001513 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001514 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001515 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001516 if (s[0] && s[1]) { /* strlen(s) > 1 */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001517 mk_re_node(s, n, re);
1518 } else {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001519 n->info = (uint32_t) s[0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001520 }
1521
1522 return n;
1523}
1524
1525/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001526 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001527 * be later regfree'd manually
1528 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001529static regex_t *as_regex(node *op, regex_t *preg)
1530{
Denis Vlasenko7a676642009-03-15 22:20:31 +00001531 int cflags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001532 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001533 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001534
1535 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1536 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001537 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001538 v = nvalloc(1);
1539 s = getvar_s(evaluate(op, v));
Denis Vlasenko7a676642009-03-15 22:20:31 +00001540
1541 cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED;
1542 /* Testcase where REG_EXTENDED fails (unpaired '{'):
1543 * echo Hi | awk 'gsub("@(samp|code|file)\{","");'
1544 * gawk 3.1.5 eats this. We revert to ~REG_EXTENDED
1545 * (maybe gsub is not supposed to use REG_EXTENDED?).
1546 */
1547 if (regcomp(preg, s, cflags)) {
1548 cflags &= ~REG_EXTENDED;
1549 xregcomp(preg, s, cflags);
1550 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001551 nvfree(v);
1552 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001553}
1554
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001555/* gradually increasing buffer.
1556 * note that we reallocate even if n == old_size,
1557 * and thus there is at least one extra allocated byte.
1558 */
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001559static char* qrealloc(char *b, int n, int *size)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001560{
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001561 if (!b || n >= *size) {
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001562 *size = n + (n>>1) + 80;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001563 b = xrealloc(b, *size);
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001564 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001565 return b;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001566}
1567
1568/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001569static void fsrealloc(int size)
1570{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001571 int i;
1572
1573 if (size >= maxfields) {
1574 i = maxfields;
1575 maxfields = size + 16;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001576 Fields = xrealloc(Fields, maxfields * sizeof(Fields[0]));
Denis Vlasenkof782f522007-01-01 23:51:30 +00001577 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001578 Fields[i].type = VF_SPECIAL;
1579 Fields[i].string = NULL;
1580 }
1581 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001582 /* if size < nfields, clear extra field variables */
1583 for (i = size; i < nfields; i++) {
1584 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001585 }
1586 nfields = size;
1587}
1588
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001589static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001590{
Denys Vlasenko28458c62010-10-05 16:49:03 +02001591 int l, n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001592 char c[4];
1593 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001594 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001595
1596 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001597 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1598 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001599
1600 c[0] = c[1] = (char)spl->info;
1601 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001602 if (*getvar_s(intvar[RS]) == '\0')
1603 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001604
Denys Vlasenko28458c62010-10-05 16:49:03 +02001605 n = 0;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001606 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1607 if (!*s)
1608 return n; /* "": zero fields */
1609 n++; /* at least one field will be there */
1610 do {
1611 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001612 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1613 && pmatch[0].rm_so <= l
1614 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001615 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001616 if (pmatch[0].rm_eo == 0) {
1617 l++;
1618 pmatch[0].rm_eo++;
1619 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001620 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001621 } else {
1622 pmatch[0].rm_eo = l;
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001623 if (s[l])
1624 pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001625 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001626 memcpy(s1, s, l);
Denis Vlasenko67b5eeb2009-04-12 13:54:13 +00001627 /* make sure we remove *all* of the separator chars */
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001628 do {
1629 s1[l] = '\0';
1630 } while (++l < pmatch[0].rm_eo);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001631 nextword(&s1);
1632 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001633 } while (*s);
1634 return n;
1635 }
1636 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001637 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001638 *s1++ = *s++;
1639 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001640 n++;
1641 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001642 return n;
1643 }
1644 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001645 if (icase) {
1646 c[0] = toupper(c[0]);
1647 c[1] = tolower(c[1]);
1648 }
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001649 if (*s1)
1650 n++;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001651 while ((s1 = strpbrk(s1, c)) != NULL) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001652 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001653 n++;
1654 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001655 return n;
1656 }
1657 /* space split */
1658 while (*s) {
1659 s = skip_whitespace(s);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001660 if (!*s)
1661 break;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001662 n++;
1663 while (*s && !isspace(*s))
1664 *s1++ = *s++;
1665 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001666 }
1667 return n;
1668}
1669
Mike Frysinger10a11e22005-09-27 02:23:02 +00001670static void split_f0(void)
1671{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001672/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001673#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001674
Glenn L McGrath545106f2002-11-11 06:21:00 +00001675 int i, n;
1676 char *s;
1677
1678 if (is_f0_split)
1679 return;
1680
1681 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001682 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001683 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001684 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001685 fsrealloc(n);
1686 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001687 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001688 Fields[i].string = nextword(&s);
1689 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1690 }
1691
1692 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001693 clrvar(intvar[NF]);
1694 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1695 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001696#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001697}
1698
1699/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001700static void handle_special(var *v)
1701{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001702 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001703 char *b;
1704 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001705 int sl, l, len, i, bsize;
1706
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001707 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001708 return;
1709
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001710 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001711 n = (int)getvar_i(v);
1712 fsrealloc(n);
1713
1714 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001715 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001716 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001717 b = NULL;
1718 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001719 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001720 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001721 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001722 if (b) {
1723 memcpy(b+len, sep, sl);
1724 len += sl;
1725 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001726 b = qrealloc(b, len+l+sl, &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001727 memcpy(b+len, s, l);
1728 len += l;
1729 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001730 if (b)
1731 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001732 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001733 is_f0_split = TRUE;
1734
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001735 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001736 is_f0_split = FALSE;
1737
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001738 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001739 mk_splitter(getvar_s(v), &fsplitter);
1740
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001741 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001742 mk_splitter(getvar_s(v), &rsplitter);
1743
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001744 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001745 icase = istrue(v);
1746
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001747 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001748 n = getvar_i(intvar[NF]);
1749 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001750 /* right here v is invalid. Just to note... */
1751 }
1752}
1753
1754/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001755static node *nextarg(node **pn)
1756{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001757 node *n;
1758
1759 n = *pn;
1760 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1761 *pn = n->r.n;
1762 n = n->l.n;
1763 } else {
1764 *pn = NULL;
1765 }
1766 return n;
1767}
1768
Mike Frysinger10a11e22005-09-27 02:23:02 +00001769static void hashwalk_init(var *v, xhash *array)
1770{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001771 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001772 unsigned i;
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001773 walker_list *w;
1774 walker_list *prev_walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001775
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001776 if (v->type & VF_WALK) {
1777 prev_walker = v->x.walker;
1778 } else {
1779 v->type |= VF_WALK;
1780 prev_walker = NULL;
1781 }
1782 debug_printf_walker("hashwalk_init: prev_walker:%p\n", prev_walker);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001783
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001784 w = v->x.walker = xzalloc(sizeof(*w) + array->glen + 1); /* why + 1? */
1785 debug_printf_walker(" walker@%p=%p\n", &v->x.walker, w);
1786 w->cur = w->end = w->wbuf;
1787 w->prev = prev_walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001788 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001789 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001790 while (hi) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001791 strcpy(w->end, hi->name);
1792 nextword(&w->end);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001793 hi = hi->next;
1794 }
1795 }
1796}
1797
Mike Frysinger10a11e22005-09-27 02:23:02 +00001798static int hashwalk_next(var *v)
1799{
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001800 walker_list *w = v->x.walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001801
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001802 if (w->cur >= w->end) {
1803 walker_list *prev_walker = w->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001804
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001805 debug_printf_walker("end of iteration, free(walker@%p:%p), prev_walker:%p\n", &v->x.walker, w, prev_walker);
1806 free(w);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001807 v->x.walker = prev_walker;
1808 return FALSE;
1809 }
1810
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001811 setvar_s(v, nextword(&w->cur));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001812 return TRUE;
1813}
1814
1815/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001816static int ptest(node *pattern)
1817{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001818 /* ptest__v is "static": to save stack space? */
1819 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001820}
1821
1822/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001823static int awk_getline(rstream *rsm, var *v)
1824{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001825 char *b;
1826 regmatch_t pmatch[2];
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001827 int size, a, p, pp = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001828 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001829 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001830
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02001831 debug_printf_eval("entered %s()\n", __func__);
1832
Glenn L McGrath545106f2002-11-11 06:21:00 +00001833 /* we're using our own buffer since we need access to accumulating
1834 * characters
1835 */
1836 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001837 m = rsm->buffer;
1838 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001839 p = rsm->pos;
1840 size = rsm->size;
1841 c = (char) rsplitter.n.info;
1842 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001843
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001844 if (!m)
1845 m = qrealloc(m, 256, &size);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001846
Glenn L McGrath545106f2002-11-11 06:21:00 +00001847 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001848 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001849 so = eo = p;
1850 r = 1;
1851 if (p > 0) {
1852 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1853 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001854 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001855 so = pmatch[0].rm_so;
1856 eo = pmatch[0].rm_eo;
1857 if (b[eo] != '\0')
1858 break;
1859 }
1860 } else if (c != '\0') {
1861 s = strchr(b+pp, c);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001862 if (!s)
1863 s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001864 if (s) {
1865 so = eo = s-b;
1866 eo++;
1867 break;
1868 }
1869 } else {
1870 while (b[rp] == '\n')
1871 rp++;
1872 s = strstr(b+rp, "\n\n");
1873 if (s) {
1874 so = eo = s-b;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001875 while (b[eo] == '\n')
1876 eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001877 if (b[eo] != '\0')
1878 break;
1879 }
1880 }
1881 }
1882
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001883 if (a > 0) {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001884 memmove(m, m+a, p+1);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001885 b = m;
1886 a = 0;
1887 }
1888
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001889 m = qrealloc(m, a+p+128, &size);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001890 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001891 pp = p;
1892 p += safe_read(fd, b+p, size-p-1);
1893 if (p < pp) {
1894 p = 0;
1895 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001896 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001897 }
1898 b[p] = '\0';
1899
1900 } while (p > pp);
1901
1902 if (p == 0) {
1903 r--;
1904 } else {
1905 c = b[so]; b[so] = '\0';
1906 setvar_s(v, b+rp);
1907 v->type |= VF_USER;
1908 b[so] = c;
1909 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001910 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001911 b[eo] = c;
1912 }
1913
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001914 rsm->buffer = m;
1915 rsm->adv = a + eo;
1916 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001917 rsm->size = size;
1918
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02001919 debug_printf_eval("returning from %s(): %d\n", __func__, r);
1920
Glenn L McGrath545106f2002-11-11 06:21:00 +00001921 return r;
1922}
1923
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001924static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001925{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001926 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001927 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001928 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001929
1930 if (int_as_int && n == (int)n) {
1931 r = snprintf(b, size, "%d", (int)n);
1932 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001933 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001934 if (strchr("diouxX", c)) {
1935 r = snprintf(b, size, format, (int)n);
1936 } else if (strchr("eEfgG", c)) {
1937 r = snprintf(b, size, format, n);
1938 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001939 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001940 }
1941 }
1942 return r;
1943}
1944
Glenn L McGrath545106f2002-11-11 06:21:00 +00001945/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001946static char *awk_printf(node *n)
1947{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001948 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001949 char *fmt, *s, *f;
1950 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001951 int i, j, incr, bsize;
1952 char c, c1;
1953 var *v, *arg;
1954
1955 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00001956 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001957
1958 i = 0;
1959 while (*f) {
1960 s = f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001961 while (*f && (*f != '%' || *++f == '%'))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001962 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001963 while (*f && !isalpha(*f)) {
1964 if (*f == '*')
1965 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001966 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00001967 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001968
1969 incr = (f - s) + MAXVARFMT;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001970 b = qrealloc(b, incr + i, &bsize);
Denis Vlasenkof782f522007-01-01 23:51:30 +00001971 c = *f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001972 if (c != '\0')
1973 f++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001974 c1 = *f;
1975 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001976 arg = evaluate(nextarg(&n), v);
1977
1978 j = i;
1979 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001980 i += sprintf(b+i, s, is_numeric(arg) ?
1981 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001982 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00001983 s1 = getvar_s(arg);
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001984 b = qrealloc(b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001985 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001986 } else {
1987 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
1988 }
1989 *f = c1;
1990
1991 /* if there was an error while sprintf, return value is negative */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001992 if (i < j)
1993 i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001994 }
1995
Glenn L McGrath545106f2002-11-11 06:21:00 +00001996 free(fmt);
1997 nvfree(v);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001998 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001999 b[i] = '\0';
2000 return b;
2001}
2002
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002003/* Common substitution routine.
2004 * Replace (nm)'th substring of (src) that matches (rn) with (repl),
2005 * store result into (dest), return number of substitutions.
2006 * If nm = 0, replace all matches.
2007 * If src or dst is NULL, use $0.
2008 * If subexp != 0, enable subexpression matching (\1-\9).
Glenn L McGrath545106f2002-11-11 06:21:00 +00002009 */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002010static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int subexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002011{
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002012 char *resbuf;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002013 const char *sp;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002014 int match_no, residx, replen, resbufsize;
2015 int regexec_flags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002016 regmatch_t pmatch[10];
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002017 regex_t sreg, *regex;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002018
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002019 resbuf = NULL;
2020 residx = 0;
2021 match_no = 0;
2022 regexec_flags = 0;
2023 regex = as_regex(rn, &sreg);
2024 sp = getvar_s(src ? src : intvar[F0]);
2025 replen = strlen(repl);
2026 while (regexec(regex, sp, 10, pmatch, regexec_flags) == 0) {
2027 int so = pmatch[0].rm_so;
2028 int eo = pmatch[0].rm_eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002029
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002030 //bb_error_msg("match %u: [%u,%u] '%s'%p", match_no+1, so, eo, sp,sp);
2031 resbuf = qrealloc(resbuf, residx + eo + replen, &resbufsize);
2032 memcpy(resbuf + residx, sp, eo);
2033 residx += eo;
2034 if (++match_no >= nm) {
2035 const char *s;
2036 int nbs;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002037
Glenn L McGrath545106f2002-11-11 06:21:00 +00002038 /* replace */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002039 residx -= (eo - so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002040 nbs = 0;
2041 for (s = repl; *s; s++) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002042 char c = resbuf[residx++] = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002043 if (c == '\\') {
2044 nbs++;
2045 continue;
2046 }
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002047 if (c == '&' || (subexp && c >= '0' && c <= '9')) {
2048 int j;
2049 residx -= ((nbs + 3) >> 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002050 j = 0;
2051 if (c != '&') {
2052 j = c - '0';
2053 nbs++;
2054 }
2055 if (nbs % 2) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002056 resbuf[residx++] = c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002057 } else {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002058 int n = pmatch[j].rm_eo - pmatch[j].rm_so;
2059 resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize);
2060 memcpy(resbuf + residx, sp + pmatch[j].rm_so, n);
2061 residx += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002062 }
2063 }
2064 nbs = 0;
2065 }
2066 }
2067
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002068 regexec_flags = REG_NOTBOL;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002069 sp += eo;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002070 if (match_no == nm)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002071 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002072 if (eo == so) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002073 /* Empty match (e.g. "b*" will match anywhere).
2074 * Advance by one char. */
2075//BUG (bug 1333):
2076//gsub(/\<b*/,"") on "abc" will reach this point, advance to "bc"
2077//... and will erroneously match "b" even though it is NOT at the word start.
2078//we need REG_NOTBOW but it does not exist...
Denys Vlasenko7379cd12010-04-04 01:48:12 +02002079//TODO: if EXTRA_COMPAT=y, use GNU matching and re_search,
2080//it should be able to do it correctly.
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002081 /* Subtle: this is safe only because
2082 * qrealloc allocated at least one extra byte */
2083 resbuf[residx] = *sp;
2084 if (*sp == '\0')
2085 goto ret;
2086 sp++;
2087 residx++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002088 }
2089 }
2090
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002091 resbuf = qrealloc(resbuf, residx + strlen(sp), &resbufsize);
2092 strcpy(resbuf + residx, sp);
2093 ret:
2094 //bb_error_msg("end sp:'%s'%p", sp,sp);
2095 setvar_p(dest ? dest : intvar[F0], resbuf);
2096 if (regex == &sreg)
2097 regfree(regex);
2098 return match_no;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002099}
2100
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002101static NOINLINE int do_mktime(const char *ds)
2102{
2103 struct tm then;
2104 int count;
2105
2106 /*memset(&then, 0, sizeof(then)); - not needed */
2107 then.tm_isdst = -1; /* default is unknown */
2108
2109 /* manpage of mktime says these fields are ints,
2110 * so we can sscanf stuff directly into them */
2111 count = sscanf(ds, "%u %u %u %u %u %u %d",
2112 &then.tm_year, &then.tm_mon, &then.tm_mday,
2113 &then.tm_hour, &then.tm_min, &then.tm_sec,
2114 &then.tm_isdst);
2115
2116 if (count < 6
2117 || (unsigned)then.tm_mon < 1
2118 || (unsigned)then.tm_year < 1900
2119 ) {
2120 return -1;
2121 }
2122
2123 then.tm_mon -= 1;
Denys Vlasenkobc3e9472009-09-21 04:16:00 +02002124 then.tm_year -= 1900;
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002125
2126 return mktime(&then);
2127}
2128
2129static NOINLINE var *exec_builtin(node *op, var *res)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002130{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002131#define tspl (G.exec_builtin__tspl)
2132
Glenn L McGrath545106f2002-11-11 06:21:00 +00002133 var *tv;
2134 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002135 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002136 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002137 regmatch_t pmatch[2];
2138 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002139 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002140 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002141 int nargs;
2142 time_t tt;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002143 int i, l, ll, n;
2144
2145 tv = nvalloc(4);
2146 isr = info = op->info;
2147 op = op->l.n;
2148
2149 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002150 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002151 an[i] = nextarg(&op);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002152 if (isr & 0x09000000)
2153 av[i] = evaluate(an[i], &tv[i]);
2154 if (isr & 0x08000000)
2155 as[i] = getvar_s(av[i]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002156 isr >>= 1;
2157 }
2158
2159 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002160 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002161 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002162
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002163 info &= OPNMASK;
2164 switch (info) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002165
Denis Vlasenkof782f522007-01-01 23:51:30 +00002166 case B_a2:
Rob Landleyd8205b32010-10-24 03:27:22 +02002167 if (ENABLE_FEATURE_AWK_LIBM)
2168 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
2169 else
2170 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002171 break;
2172
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002173 case B_sp: {
2174 char *s, *s1;
2175
Glenn L McGrath545106f2002-11-11 06:21:00 +00002176 if (nargs > 2) {
2177 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2178 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2179 } else {
2180 spl = &fsplitter.n;
2181 }
2182
2183 n = awk_split(as[0], spl, &s);
2184 s1 = s;
2185 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002186 for (i = 1; i <= n; i++)
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002187 setari_u(av[1], i, nextword(&s));
2188 free(s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002189 setvar_i(res, n);
2190 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002191 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002192
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002193 case B_ss: {
2194 char *s;
2195
Rob Landleya3896512006-05-07 20:20:34 +00002196 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002197 i = getvar_i(av[1]) - 1;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002198 if (i > l)
2199 i = l;
2200 if (i < 0)
2201 i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002202 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002203 if (n < 0)
2204 n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002205 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002206 setvar_p(res, s);
2207 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002208 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002209
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002210 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2211 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002212 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002213 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002214 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002215
Denis Vlasenkof782f522007-01-01 23:51:30 +00002216 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002217 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002218 break;
2219
Denis Vlasenkof782f522007-01-01 23:51:30 +00002220 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002221 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002222 break;
2223
Denis Vlasenkof782f522007-01-01 23:51:30 +00002224 case B_or:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002225 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002226 break;
2227
Denis Vlasenkof782f522007-01-01 23:51:30 +00002228 case B_rs:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002229 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002230 break;
2231
Denis Vlasenkof782f522007-01-01 23:51:30 +00002232 case B_xo:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002233 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002234 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002235
Denis Vlasenkof782f522007-01-01 23:51:30 +00002236 case B_lo:
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002237 case B_up: {
2238 char *s, *s1;
Rob Landleyd921b2e2006-08-03 15:41:12 +00002239 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002240 while (*s1) {
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002241 //*s1 = (info == B_up) ? toupper(*s1) : tolower(*s1);
2242 if ((unsigned char)((*s1 | 0x20) - 'a') <= ('z' - 'a'))
2243 *s1 = (info == B_up) ? (*s1 & 0xdf) : (*s1 | 0x20);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002244 s1++;
2245 }
2246 setvar_p(res, s);
2247 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002248 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002249
Denis Vlasenkof782f522007-01-01 23:51:30 +00002250 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002251 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002252 ll = strlen(as[1]);
2253 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002254 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002255 if (!icase) {
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002256 char *s = strstr(as[0], as[1]);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002257 if (s)
2258 n = (s - as[0]) + 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002259 } else {
2260 /* this piece of code is terribly slow and
2261 * really should be rewritten
2262 */
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002263 for (i = 0; i <= l; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002264 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2265 n = i+1;
2266 break;
2267 }
2268 }
2269 }
2270 }
2271 setvar_i(res, n);
2272 break;
2273
Denis Vlasenkof782f522007-01-01 23:51:30 +00002274 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002275 if (nargs > 1)
2276 tt = getvar_i(av[1]);
2277 else
2278 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002279 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002280 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002281 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2282 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002283 g_buf[i] = '\0';
2284 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002285 break;
2286
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002287 case B_mt:
2288 setvar_i(res, do_mktime(as[0]));
2289 break;
2290
Denis Vlasenkof782f522007-01-01 23:51:30 +00002291 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002292 re = as_regex(an[1], &sreg);
2293 n = regexec(re, as[0], 1, pmatch, 0);
2294 if (n == 0) {
2295 pmatch[0].rm_so++;
2296 pmatch[0].rm_eo++;
2297 } else {
2298 pmatch[0].rm_so = 0;
2299 pmatch[0].rm_eo = -1;
2300 }
2301 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2302 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2303 setvar_i(res, pmatch[0].rm_so);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002304 if (re == &sreg)
2305 regfree(re);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002306 break;
2307
Denis Vlasenkof782f522007-01-01 23:51:30 +00002308 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002309 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2310 break;
2311
Denis Vlasenkof782f522007-01-01 23:51:30 +00002312 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002313 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2314 break;
2315
Denis Vlasenkof782f522007-01-01 23:51:30 +00002316 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002317 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2318 break;
2319 }
2320
2321 nvfree(tv);
2322 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002323#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002324}
2325
2326/*
2327 * Evaluate node - the heart of the program. Supplied with subtree
2328 * and place where to store result. returns ptr to result.
2329 */
2330#define XC(n) ((n) >> 8)
2331
Mike Frysinger10a11e22005-09-27 02:23:02 +00002332static var *evaluate(node *op, var *res)
2333{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002334/* This procedure is recursive so we should count every byte */
2335#define fnargs (G.evaluate__fnargs)
2336/* seed is initialized to 1 */
2337#define seed (G.evaluate__seed)
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002338#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002339
Glenn L McGrath545106f2002-11-11 06:21:00 +00002340 var *v1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002341
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002342 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002343 return setvar_s(res, NULL);
2344
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002345 debug_printf_eval("entered %s()\n", __func__);
2346
Glenn L McGrath545106f2002-11-11 06:21:00 +00002347 v1 = nvalloc(2);
2348
2349 while (op) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002350 struct {
2351 var *v;
2352 const char *s;
2353 } L = L; /* for compiler */
2354 struct {
2355 var *v;
2356 const char *s;
2357 } R = R;
2358 double L_d = L_d;
2359 uint32_t opinfo;
2360 int opn;
2361 node *op1;
2362
Glenn L McGrath545106f2002-11-11 06:21:00 +00002363 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002364 opn = (opinfo & OPNMASK);
2365 g_lineno = op->lineno;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002366 op1 = op->l.n;
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002367 debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002368
Mike Frysingerde2b9382005-09-27 03:18:00 +00002369 /* execute inevitable things */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002370 if (opinfo & OF_RES1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002371 L.v = evaluate(op1, v1);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002372 if (opinfo & OF_RES2)
2373 R.v = evaluate(op->r.n, v1+1);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002374 if (opinfo & OF_STR1) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002375 L.s = getvar_s(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002376 debug_printf_eval("L.s:'%s'\n", L.s);
2377 }
2378 if (opinfo & OF_STR2) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002379 R.s = getvar_s(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002380 debug_printf_eval("R.s:'%s'\n", R.s);
2381 }
2382 if (opinfo & OF_NUM1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002383 L_d = getvar_i(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002384 debug_printf_eval("L_d:%f\n", L_d);
2385 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002386
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002387 debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002388 switch (XC(opinfo & OPCLSMASK)) {
2389
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002390 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002391
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002392 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002393 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002394 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2395 /* it's range pattern */
2396 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2397 op->info |= OF_CHECKED;
2398 if (ptest(op1->r.n))
2399 op->info &= ~OF_CHECKED;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002400 op = op->a.n;
2401 } else {
2402 op = op->r.n;
2403 }
2404 } else {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002405 op = ptest(op1) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002406 }
2407 break;
2408
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002409 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002410 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002411 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002412
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002413 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002414 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002415 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002416 break;
2417
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002418 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002419 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002420 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002421 break;
2422
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002423 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002424 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002425 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2426 break;
2427
Denis Vlasenkof782f522007-01-01 23:51:30 +00002428 case XC( OC_PRINT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002429 case XC( OC_PRINTF ): {
2430 FILE *F = stdout;
2431
Mike Frysingerde2b9382005-09-27 03:18:00 +00002432 if (op->r.n) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002433 rstream *rsm = newfile(R.s);
2434 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002435 if (opn == '|') {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002436 rsm->F = popen(R.s, "w");
2437 if (rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002438 bb_perror_msg_and_die("popen");
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002439 rsm->is_pipe = 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002440 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002441 rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002442 }
2443 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002444 F = rsm->F;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002445 }
2446
2447 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002448 if (!op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002449 fputs(getvar_s(intvar[F0]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002450 } else {
2451 while (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002452 var *v = evaluate(nextarg(&op1), v1);
2453 if (v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002454 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002455 getvar_i(v), TRUE);
2456 fputs(g_buf, F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002457 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002458 fputs(getvar_s(v), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002459 }
2460
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002461 if (op1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002462 fputs(getvar_s(intvar[OFS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002463 }
2464 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002465 fputs(getvar_s(intvar[ORS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002466
2467 } else { /* OC_PRINTF */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002468 char *s = awk_printf(op1);
2469 fputs(s, F);
2470 free(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002471 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002472 fflush(F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002473 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002474 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002475
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002476 case XC( OC_DELETE ): {
2477 uint32_t info = op1->info & OPCLSMASK;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002478 var *v;
2479
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002480 if (info == OC_VAR) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002481 v = op1->l.v;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002482 } else if (info == OC_FNARG) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002483 v = &fnargs[op1->l.aidx];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002484 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002485 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002486 }
2487
Mike Frysingerde2b9382005-09-27 03:18:00 +00002488 if (op1->r.n) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002489 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002490 clrvar(L.v);
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002491 s = getvar_s(evaluate(op1->r.n, v1));
2492 hash_remove(iamarray(v), s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002493 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002494 clear_array(iamarray(v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002495 }
2496 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002497 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002498
Denis Vlasenkof782f522007-01-01 23:51:30 +00002499 case XC( OC_NEWSOURCE ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002500 g_progname = op->l.new_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002501 break;
2502
Denis Vlasenkof782f522007-01-01 23:51:30 +00002503 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002504 copyvar(res, L.v);
2505 break;
2506
Denis Vlasenkof782f522007-01-01 23:51:30 +00002507 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002508 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002509 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002510 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002511 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002512 clrvar(res);
2513 break;
2514
Denis Vlasenkof782f522007-01-01 23:51:30 +00002515 case XC( OC_EXIT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002516 awk_exit(L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002517
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002518 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002519
Denis Vlasenkof782f522007-01-01 23:51:30 +00002520 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002521 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002522 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002523 split_f0();
2524 goto v_cont;
2525
Denis Vlasenkof782f522007-01-01 23:51:30 +00002526 case XC( OC_FNARG ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002527 L.v = &fnargs[op->l.aidx];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002528 v_cont:
2529 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002530 break;
2531
Denis Vlasenkof782f522007-01-01 23:51:30 +00002532 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002533 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2534 break;
2535
Denis Vlasenkof782f522007-01-01 23:51:30 +00002536 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002537 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002538 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002539 goto re_cont;
2540
Denis Vlasenkof782f522007-01-01 23:51:30 +00002541 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002542 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002543 re_cont:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002544 {
2545 regex_t *re = as_regex(op1, &sreg);
2546 int i = regexec(re, L.s, 0, NULL, 0);
2547 if (re == &sreg)
2548 regfree(re);
2549 setvar_i(res, (i == 0) ^ (opn == '!'));
2550 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002551 break;
2552
Denis Vlasenkof782f522007-01-01 23:51:30 +00002553 case XC( OC_MOVE ):
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002554 debug_printf_eval("MOVE\n");
Mike Frysingerde2b9382005-09-27 03:18:00 +00002555 /* if source is a temporary string, jusk relink it to dest */
Denys Vlasenko12847742009-11-30 01:15:04 +01002556//Disabled: if R.v is numeric but happens to have cached R.v->string,
2557//then L.v ends up being a string, which is wrong
2558// if (R.v == v1+1 && R.v->string) {
2559// res = setvar_p(L.v, R.v->string);
2560// R.v->string = NULL;
2561// } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002562 res = copyvar(L.v, R.v);
Denys Vlasenko12847742009-11-30 01:15:04 +01002563// }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002564 break;
2565
Denis Vlasenkof782f522007-01-01 23:51:30 +00002566 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002567 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002568 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002569 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2570 break;
2571
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002572 case XC( OC_FUNC ): {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002573 var *vbeg, *v;
2574 const char *sv_progname;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002575
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002576 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002577 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002578
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002579 vbeg = v = nvalloc(op->r.f->nargs + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002580 while (op1) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002581 var *arg = evaluate(nextarg(&op1), v1);
2582 copyvar(v, arg);
2583 v->type |= VF_CHILD;
2584 v->x.parent = arg;
2585 if (++v - vbeg >= op->r.f->nargs)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002586 break;
2587 }
2588
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002589 v = fnargs;
2590 fnargs = vbeg;
2591 sv_progname = g_progname;
2592
2593 res = evaluate(op->r.f->body.first, res);
2594
2595 g_progname = sv_progname;
2596 nvfree(fnargs);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002597 fnargs = v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002598
Glenn L McGrath545106f2002-11-11 06:21:00 +00002599 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002600 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002601
Denis Vlasenkof782f522007-01-01 23:51:30 +00002602 case XC( OC_GETLINE ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002603 case XC( OC_PGETLINE ): {
2604 rstream *rsm;
2605 int i;
2606
Mike Frysingerde2b9382005-09-27 03:18:00 +00002607 if (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002608 rsm = newfile(L.s);
2609 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002610 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002611 rsm->F = popen(L.s, "r");
2612 rsm->is_pipe = TRUE;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002613 } else {
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002614 rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002615 }
2616 }
2617 } else {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002618 if (!iF)
2619 iF = next_input_file();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002620 rsm = iF;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002621 }
2622
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002623 if (!rsm->F) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002624 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002625 setvar_i(res, -1);
2626 break;
2627 }
2628
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002629 if (!op->r.n)
2630 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002631
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002632 i = awk_getline(rsm, R.v);
2633 if (i > 0 && !op1) {
2634 incvar(intvar[FNR]);
2635 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002636 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002637 setvar_i(res, i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002638 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002639 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002640
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002641 /* simple builtins */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002642 case XC( OC_FBLTIN ): {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002643 double R_d = R_d; /* for compiler */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002644
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002645 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002646 case F_in:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002647 R_d = (int)L_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002648 break;
2649
Denis Vlasenkof782f522007-01-01 23:51:30 +00002650 case F_rn:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002651 R_d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002652 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002653
Denis Vlasenkof782f522007-01-01 23:51:30 +00002654 case F_co:
Rob Landleyd8205b32010-10-24 03:27:22 +02002655 if (ENABLE_FEATURE_AWK_LIBM) {
2656 R_d = cos(L_d);
2657 break;
2658 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002659
Denis Vlasenkof782f522007-01-01 23:51:30 +00002660 case F_ex:
Rob Landleyd8205b32010-10-24 03:27:22 +02002661 if (ENABLE_FEATURE_AWK_LIBM) {
2662 R_d = exp(L_d);
2663 break;
2664 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002665
Denis Vlasenkof782f522007-01-01 23:51:30 +00002666 case F_lg:
Rob Landleyd8205b32010-10-24 03:27:22 +02002667 if (ENABLE_FEATURE_AWK_LIBM) {
2668 R_d = log(L_d);
2669 break;
2670 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002671
Denis Vlasenkof782f522007-01-01 23:51:30 +00002672 case F_si:
Rob Landleyd8205b32010-10-24 03:27:22 +02002673 if (ENABLE_FEATURE_AWK_LIBM) {
2674 R_d = sin(L_d);
2675 break;
2676 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002677
Denis Vlasenkof782f522007-01-01 23:51:30 +00002678 case F_sq:
Rob Landleyd8205b32010-10-24 03:27:22 +02002679 if (ENABLE_FEATURE_AWK_LIBM) {
2680 R_d = sqrt(L_d);
2681 break;
2682 }
2683
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002684 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002685 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002686
Denis Vlasenkof782f522007-01-01 23:51:30 +00002687 case F_sr:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002688 R_d = (double)seed;
2689 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002690 srand(seed);
2691 break;
2692
Denis Vlasenkof782f522007-01-01 23:51:30 +00002693 case F_ti:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002694 R_d = time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002695 break;
2696
Denis Vlasenkof782f522007-01-01 23:51:30 +00002697 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002698 if (!op1)
2699 L.s = getvar_s(intvar[F0]);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002700 R_d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002701 break;
2702
Denis Vlasenkof782f522007-01-01 23:51:30 +00002703 case F_sy:
Denys Vlasenko8131eea2009-11-02 14:19:51 +01002704 fflush_all();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002705 R_d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002706 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002707 break;
2708
Denis Vlasenkof782f522007-01-01 23:51:30 +00002709 case F_ff:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002710 if (!op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002711 fflush(stdout);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002712 } else if (L.s && *L.s) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002713 rstream *rsm = newfile(L.s);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002714 fflush(rsm->F);
2715 } else {
2716 fflush_all();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002717 }
2718 break;
2719
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002720 case F_cl: {
2721 rstream *rsm;
2722 int err = 0;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002723 rsm = (rstream *)hash_search(fdhash, L.s);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002724 debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002725 if (rsm) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002726 debug_printf_eval("OC_FBLTIN F_cl "
2727 "rsm->is_pipe:%d, ->F:%p\n",
2728 rsm->is_pipe, rsm->F);
2729 /* Can be NULL if open failed. Example:
2730 * getline line <"doesnt_exist";
2731 * close("doesnt_exist"); <--- here rsm->F is NULL
2732 */
2733 if (rsm->F)
2734 err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002735 free(rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002736 hash_remove(fdhash, L.s);
2737 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002738 if (err)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002739 setvar_i(intvar[ERRNO], errno);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002740 R_d = (double)err;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002741 break;
2742 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002743 } /* switch */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002744 setvar_i(res, R_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002745 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002746 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002747
Denis Vlasenkof782f522007-01-01 23:51:30 +00002748 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002749 res = exec_builtin(op, res);
2750 break;
2751
Denis Vlasenkof782f522007-01-01 23:51:30 +00002752 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002753 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002754 break;
2755
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002756 case XC( OC_UNARY ): {
2757 double Ld, R_d;
2758
2759 Ld = R_d = getvar_i(R.v);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002760 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002761 case 'P':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002762 Ld = ++R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002763 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002764 case 'p':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002765 R_d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002766 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002767 case 'M':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002768 Ld = --R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002769 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002770 case 'm':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002771 R_d--;
2772 r_op_change:
2773 setvar_i(R.v, R_d);
2774 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002775 case '!':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002776 Ld = !istrue(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002777 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002778 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002779 Ld = -R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002780 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002781 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002782 setvar_i(res, Ld);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002783 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002784 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002785
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002786 case XC( OC_FIELD ): {
2787 int i = (int)getvar_i(R.v);
2788 if (i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002789 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002790 } else {
2791 split_f0();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002792 if (i > nfields)
2793 fsrealloc(i);
2794 res = &Fields[i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002795 }
2796 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002797 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002798
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002799 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002800 case XC( OC_CONCAT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002801 case XC( OC_COMMA ): {
2802 const char *sep = "";
2803 if ((opinfo & OPCLSMASK) == OC_COMMA)
2804 sep = getvar_s(intvar[SUBSEP]);
2805 setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002806 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002807 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002808
Denis Vlasenkof782f522007-01-01 23:51:30 +00002809 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002810 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2811 break;
2812
Denis Vlasenkof782f522007-01-01 23:51:30 +00002813 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002814 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2815 break;
2816
Denis Vlasenkof782f522007-01-01 23:51:30 +00002817 case XC( OC_BINARY ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002818 case XC( OC_REPLACE ): {
2819 double R_d = getvar_i(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002820 debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002821 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002822 case '+':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002823 L_d += R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002824 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002825 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002826 L_d -= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002827 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002828 case '*':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002829 L_d *= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002830 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002831 case '/':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002832 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002833 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002834 L_d /= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002835 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002836 case '&':
Rob Landleyd8205b32010-10-24 03:27:22 +02002837 if (ENABLE_FEATURE_AWK_LIBM)
2838 L_d = pow(L_d, R_d);
2839 else
2840 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002841 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002842 case '%':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002843 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002844 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002845 L_d -= (int)(L_d / R_d) * R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002846 break;
2847 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002848 debug_printf_eval("BINARY/REPLACE result:%f\n", L_d);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002849 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002850 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002851 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002852
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002853 case XC( OC_COMPARE ): {
2854 int i = i; /* for compiler */
2855 double Ld;
2856
Glenn L McGrath545106f2002-11-11 06:21:00 +00002857 if (is_numeric(L.v) && is_numeric(R.v)) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002858 Ld = getvar_i(L.v) - getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002859 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002860 const char *l = getvar_s(L.v);
2861 const char *r = getvar_s(R.v);
2862 Ld = icase ? strcasecmp(l, r) : strcmp(l, r);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002863 }
2864 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002865 case 0:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002866 i = (Ld > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002867 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002868 case 2:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002869 i = (Ld >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002870 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002871 case 4:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002872 i = (Ld == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002873 break;
2874 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002875 setvar_i(res, (i == 0) ^ (opn & 1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002876 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002877 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002878
Denis Vlasenkof782f522007-01-01 23:51:30 +00002879 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002880 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002881 }
2882 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2883 op = op->a.n;
2884 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2885 break;
2886 if (nextrec)
2887 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002888 } /* while (op) */
2889
Glenn L McGrath545106f2002-11-11 06:21:00 +00002890 nvfree(v1);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002891 debug_printf_eval("returning from %s(): %p\n", __func__, res);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002892 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002893#undef fnargs
2894#undef seed
2895#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002896}
2897
2898
2899/* -------- main & co. -------- */
2900
Mike Frysinger10a11e22005-09-27 02:23:02 +00002901static int awk_exit(int r)
2902{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002903 var tv;
2904 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002905 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002906
Denis Vlasenkof782f522007-01-01 23:51:30 +00002907 zero_out_var(&tv);
2908
2909 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002910 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002911 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002912 evaluate(endseq.first, &tv);
2913 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002914
2915 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002916 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002917 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002918 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002919 if (hi->data.rs.F && hi->data.rs.is_pipe)
2920 pclose(hi->data.rs.F);
2921 hi = hi->next;
2922 }
2923 }
2924
2925 exit(r);
2926}
2927
2928/* if expr looks like "var=value", perform assignment and return 1,
2929 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002930static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002931{
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002932 char *exprc, *val, *s, *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002933
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002934 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002935 return FALSE;
2936 }
2937
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002938 exprc = xstrdup(expr);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002939 val = exprc + (val - expr);
2940 *val++ = '\0';
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002941
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002942 s = s1 = val;
2943 while ((*s1 = nextchar(&s)) != '\0')
2944 s1++;
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002945
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002946 setvar_u(newvar(exprc), val);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002947 free(exprc);
2948 return TRUE;
2949}
2950
2951/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002952static rstream *next_input_file(void)
2953{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002954#define rsm (G.next_input_file__rsm)
2955#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002956
Glenn L McGrath545106f2002-11-11 06:21:00 +00002957 FILE *F = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002958 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002959
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002960 if (rsm.F)
2961 fclose(rsm.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002962 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002963 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002964
2965 do {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002966 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002967 if (files_happen)
2968 return NULL;
2969 fname = "-";
2970 F = stdin;
2971 } else {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002972 ind = getvar_s(incvar(intvar[ARGIND]));
2973 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002974 if (fname && *fname && !is_assignment(fname))
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002975 F = xfopen_stdin(fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002976 }
2977 } while (!F);
2978
2979 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002980 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002981 rsm.F = F;
2982 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002983#undef rsm
2984#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00002985}
2986
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002987int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00002988int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002989{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002990 unsigned opt;
Denis Vlasenkobe644a82007-03-10 17:22:14 +00002991 char *opt_F, *opt_W;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00002992 llist_t *list_v = NULL;
2993 llist_t *list_f = NULL;
2994 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002995 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002996 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002997 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002998 char *vnames = (char *)vNames; /* cheat */
2999 char *vvalues = (char *)vValues;
3000
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003001 INIT_G();
3002
Denis Vlasenko150f4022007-01-13 21:06:21 +00003003 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00003004 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
3005 if (ENABLE_LOCALE_SUPPORT)
3006 setlocale(LC_NUMERIC, "C");
3007
Denis Vlasenkof782f522007-01-01 23:51:30 +00003008 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003009
3010 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003011 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003012
3013 vhash = hash_init();
3014 ahash = hash_init();
3015 fdhash = hash_init();
3016 fnhash = hash_init();
3017
3018 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003019 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003020 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00003021 if (*vvalues != '\377')
3022 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003023 else
3024 setvar_i(v, 0);
3025
Denis Vlasenkof782f522007-01-01 23:51:30 +00003026 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003027 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003028 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003029 }
3030 }
3031
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003032 handle_special(intvar[FS]);
3033 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003034
Denis Vlasenkof782f522007-01-01 23:51:30 +00003035 newfile("/dev/stdin")->F = stdin;
3036 newfile("/dev/stdout")->F = stdout;
3037 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003038
Denis Vlasenkof71d9162007-05-03 22:57:56 +00003039 /* Huh, people report that sometimes environ is NULL. Oh well. */
3040 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003041 /* environ is writable, thus we don't strdup it needlessly */
3042 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003043 char *s1 = strchr(s, '=');
3044 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003045 *s1 = '\0';
3046 /* Both findvar and setvar_u take const char*
3047 * as 2nd arg -> environment is not trashed */
3048 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
3049 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00003050 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003051 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003052 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
3053 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003054 argv += optind;
3055 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003056 if (opt & 0x1)
3057 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003058 while (list_v) { /* -v */
3059 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00003060 bb_show_usage();
3061 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003062 if (list_f) { /* -f */
3063 do {
3064 char *s = NULL;
3065 FILE *from_file;
3066
3067 g_progname = llist_pop(&list_f);
3068 from_file = xfopen_stdin(g_progname);
3069 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003070 for (i = j = 1; j > 0; i += j) {
3071 s = xrealloc(s, i + 4096);
3072 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00003073 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003074 s[i] = '\0';
3075 fclose(from_file);
3076 parse_program(s + 1);
3077 free(s);
3078 } while (list_f);
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00003079 argc++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003080 } else { // no -f: take program from 1st parameter
3081 if (!argc)
3082 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003083 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00003084 parse_program(*argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003085 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00003086 if (opt & 0x8) // -W
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +00003087 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003088
Glenn L McGrath545106f2002-11-11 06:21:00 +00003089 /* fill in ARGV array */
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00003090 setvar_i(intvar[ARGC], argc);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003091 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00003092 i = 0;
3093 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003094 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003095
3096 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003097 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00003098 awk_exit(EXIT_SUCCESS);
3099
3100 /* input file could already be opened in BEGIN block */
Denys Vlasenkocdeda162009-11-30 01:14:16 +01003101 if (!iF)
3102 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003103
3104 /* passing through input files */
3105 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003106 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003107 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003108
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003109 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003110 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003111 incvar(intvar[NR]);
3112 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003113 evaluate(mainseq.first, &tv);
3114
3115 if (nextfile)
3116 break;
3117 }
3118
Denis Vlasenkof782f522007-01-01 23:51:30 +00003119 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003120 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003121
3122 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003123 }
3124
Glenn L McGrath545106f2002-11-11 06:21:00 +00003125 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003126 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00003127}