blob: 0b573a065c18bfd237886ee563f661c5199acc78 [file] [log] [blame]
Glenn L McGrath545106f2002-11-11 06:21:00 +00001/* vi: set sw=4 ts=4: */
2/*
3 * awk implementation for busybox
4 *
5 * Copyright (C) 2002 by Dmitry Zakharov <dmit@crp.bank.gov.ua>
6 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Glenn L McGrath545106f2002-11-11 06:21:00 +00008 */
9
Pere Orga6a3e01d2011-04-01 22:56:30 +020010//usage:#define awk_trivial_usage
11//usage: "[OPTIONS] [AWK_PROGRAM] [FILE]..."
12//usage:#define awk_full_usage "\n\n"
Denys Vlasenko66426762011-06-05 03:58:28 +020013//usage: " -v VAR=VAL Set variable"
Pere Orga6a3e01d2011-04-01 22:56:30 +020014//usage: "\n -F SEP Use SEP as field separator"
15//usage: "\n -f FILE Read program from FILE"
16
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000017#include "libbb.h"
Rob Landleyd921b2e2006-08-03 15:41:12 +000018#include "xregex.h"
19#include <math.h>
Glenn L McGrath545106f2002-11-11 06:21:00 +000020
Denis Vlasenko99912ca2007-04-10 15:43:37 +000021/* This is a NOEXEC applet. Be very careful! */
22
Glenn L McGrath545106f2002-11-11 06:21:00 +000023
Denys Vlasenkoda62b092010-03-11 12:13:18 +010024/* If you comment out one of these below, it will be #defined later
25 * to perform debug printfs to stderr: */
26#define debug_printf_walker(...) do {} while (0)
Denys Vlasenkod527e0c2010-10-05 13:22:11 +020027#define debug_printf_eval(...) do {} while (0)
Denys Vlasenko7b46d112011-09-11 00:30:56 +020028#define debug_printf_parse(...) do {} while (0)
Denys Vlasenkoda62b092010-03-11 12:13:18 +010029
30#ifndef debug_printf_walker
31# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__))
32#endif
Denys Vlasenkod527e0c2010-10-05 13:22:11 +020033#ifndef debug_printf_eval
34# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__))
35#endif
Denys Vlasenko7b46d112011-09-11 00:30:56 +020036#ifndef debug_printf_parse
37# define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__))
38#endif
Denys Vlasenkoda62b092010-03-11 12:13:18 +010039
40
41
Denis Vlasenko629563b2007-02-24 17:05:52 +000042#define MAXVARFMT 240
43#define MINNVBLOCK 64
Glenn L McGrath545106f2002-11-11 06:21:00 +000044
45/* variable flags */
Denis Vlasenko629563b2007-02-24 17:05:52 +000046#define VF_NUMBER 0x0001 /* 1 = primary type is number */
47#define VF_ARRAY 0x0002 /* 1 = it's an array */
Glenn L McGrath545106f2002-11-11 06:21:00 +000048
Denis Vlasenko629563b2007-02-24 17:05:52 +000049#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
50#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
51#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
52#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
53#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
54#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
55#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
Glenn L McGrath545106f2002-11-11 06:21:00 +000056
57/* these flags are static, don't change them when value is changed */
Denis Vlasenko629563b2007-02-24 17:05:52 +000058#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
Glenn L McGrath545106f2002-11-11 06:21:00 +000059
Denys Vlasenkoda62b092010-03-11 12:13:18 +010060typedef struct walker_list {
61 char *end;
62 char *cur;
63 struct walker_list *prev;
64 char wbuf[1];
65} walker_list;
66
Glenn L McGrath545106f2002-11-11 06:21:00 +000067/* Variable */
68typedef struct var_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000069 unsigned type; /* flags */
Glenn L McGrath545106f2002-11-11 06:21:00 +000070 double number;
71 char *string;
72 union {
Denis Vlasenko629563b2007-02-24 17:05:52 +000073 int aidx; /* func arg idx (for compilation stage) */
74 struct xhash_s *array; /* array ptr */
75 struct var_s *parent; /* for func args, ptr to actual parameter */
Denys Vlasenkoda62b092010-03-11 12:13:18 +010076 walker_list *walker; /* list of array elements (for..in) */
Glenn L McGrath545106f2002-11-11 06:21:00 +000077 } x;
78} var;
79
80/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
81typedef struct chain_s {
82 struct node_s *first;
83 struct node_s *last;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +000084 const char *programname;
Glenn L McGrath545106f2002-11-11 06:21:00 +000085} chain;
86
87/* Function */
88typedef struct func_s {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +000089 unsigned nargs;
Glenn L McGrath545106f2002-11-11 06:21:00 +000090 struct chain_s body;
91} func;
92
93/* I/O stream */
94typedef struct rstream_s {
95 FILE *F;
96 char *buffer;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +000097 int adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +000098 int size;
99 int pos;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000100 smallint is_pipe;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000101} rstream;
102
103typedef struct hash_item_s {
104 union {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000105 struct var_s v; /* variable/array hash */
106 struct rstream_s rs; /* redirect streams hash */
107 struct func_s f; /* functions hash */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000108 } data;
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000109 struct hash_item_s *next; /* next in chain */
110 char name[1]; /* really it's longer */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000111} hash_item;
112
113typedef struct xhash_s {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000114 unsigned nel; /* num of elements */
115 unsigned csize; /* current hash size */
116 unsigned nprime; /* next hash size in PRIMES[] */
117 unsigned glen; /* summary length of item names */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000118 struct hash_item_s **items;
119} xhash;
120
121/* Tree node */
122typedef struct node_s {
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000123 uint32_t info;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000124 unsigned lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000125 union {
126 struct node_s *n;
127 var *v;
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100128 int aidx;
129 char *new_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000130 regex_t *re;
131 } l;
132 union {
133 struct node_s *n;
134 regex_t *ire;
135 func *f;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000136 } r;
137 union {
138 struct node_s *n;
139 } a;
140} node;
141
142/* Block of temporary variables */
143typedef struct nvblock_s {
144 int size;
145 var *pos;
146 struct nvblock_s *prev;
147 struct nvblock_s *next;
Denys Vlasenkod069e532009-09-09 23:12:10 +0200148 var nv[];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000149} nvblock;
150
151typedef struct tsplitter_s {
152 node n;
153 regex_t re[2];
154} tsplitter;
155
156/* simple token classes */
157/* Order and hex values are very important!!! See next_token() */
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100158#define TC_SEQSTART 1 /* ( */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000159#define TC_SEQTERM (1 << 1) /* ) */
160#define TC_REGEXP (1 << 2) /* /.../ */
161#define TC_OUTRDR (1 << 3) /* | > >> */
162#define TC_UOPPOST (1 << 4) /* unary postfix operator */
163#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
164#define TC_BINOPX (1 << 6) /* two-opnd operator */
165#define TC_IN (1 << 7)
166#define TC_COMMA (1 << 8)
167#define TC_PIPE (1 << 9) /* input redirection pipe */
168#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
169#define TC_ARRTERM (1 << 11) /* ] */
170#define TC_GRPSTART (1 << 12) /* { */
171#define TC_GRPTERM (1 << 13) /* } */
172#define TC_SEMICOL (1 << 14)
173#define TC_NEWLINE (1 << 15)
174#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
175#define TC_WHILE (1 << 17)
176#define TC_ELSE (1 << 18)
177#define TC_BUILTIN (1 << 19)
178#define TC_GETLINE (1 << 20)
179#define TC_FUNCDECL (1 << 21) /* `function' `func' */
180#define TC_BEGIN (1 << 22)
181#define TC_END (1 << 23)
182#define TC_EOF (1 << 24)
183#define TC_VARIABLE (1 << 25)
184#define TC_ARRAY (1 << 26)
185#define TC_FUNCTION (1 << 27)
186#define TC_STRING (1 << 28)
187#define TC_NUMBER (1 << 29)
188
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000189#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000190
191/* combined token classes */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000192#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
193#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
194#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
195 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000196
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000197#define TC_STATEMNT (TC_STATX | TC_WHILE)
198#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000199
200/* word tokens, cannot mean something else if not expected */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000201#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
202 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000203
204/* discard newlines after these */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000205#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
206 | TC_BINOP | TC_OPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000207
208/* what can expression begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000209#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000210/* what can group begin with */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000211#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000212
213/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
214/* operator is inserted between them */
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000215#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
216 | TC_STRING | TC_NUMBER | TC_UOPPOST)
217#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000218
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000219#define OF_RES1 0x010000
220#define OF_RES2 0x020000
221#define OF_STR1 0x040000
222#define OF_STR2 0x080000
223#define OF_NUM1 0x100000
224#define OF_CHECKED 0x200000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000225
226/* combined operator flags */
227#define xx 0
228#define xV OF_RES2
229#define xS (OF_RES2 | OF_STR2)
230#define Vx OF_RES1
231#define VV (OF_RES1 | OF_RES2)
232#define Nx (OF_RES1 | OF_NUM1)
233#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
234#define Sx (OF_RES1 | OF_STR1)
235#define SV (OF_RES1 | OF_STR1 | OF_RES2)
236#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
237
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000238#define OPCLSMASK 0xFF00
239#define OPNMASK 0x007F
Glenn L McGrath545106f2002-11-11 06:21:00 +0000240
241/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
242 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
243 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
244 */
Denys Vlasenko202a1b92011-09-10 04:51:09 +0200245#undef P
246#undef PRIMASK
247#undef PRIMASK2
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000248#define P(x) (x << 24)
249#define PRIMASK 0x7F000000
250#define PRIMASK2 0x7E000000
Glenn L McGrath545106f2002-11-11 06:21:00 +0000251
252/* Operation classes */
253
254#define SHIFT_TIL_THIS 0x0600
255#define RECUR_FROM_THIS 0x1000
256
257enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000258 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
259 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000260
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000261 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
262 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
263 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000264
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000265 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
266 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
267 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
268 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
269 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
270 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
271 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
272 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
273 OC_DONE = 0x2800,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000274
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000275 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
276 ST_WHILE = 0x3300
Glenn L McGrath545106f2002-11-11 06:21:00 +0000277};
278
279/* simple builtins */
280enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000281 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000282 F_ti, F_le, F_sy, F_ff, F_cl
283};
284
285/* builtins */
286enum {
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +0200287 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 +0000288 B_ge, B_gs, B_su,
289 B_an, B_co, B_ls, B_or, B_rs, B_xo,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000290};
291
292/* tokens and their corresponding info values */
293
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200294#define NTC "\377" /* switch to next token class (tc<<1) */
295#define NTCC '\377'
Glenn L McGrath545106f2002-11-11 06:21:00 +0000296
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200297#define OC_B OC_BUILTIN
Glenn L McGrath545106f2002-11-11 06:21:00 +0000298
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000299static const char tokenlist[] ALIGN1 =
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200300 "\1(" NTC
301 "\1)" NTC
302 "\1/" NTC /* REGEXP */
303 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
304 "\2++" "\2--" NTC /* UOPPOST */
305 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
306 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
307 "\2*=" "\2/=" "\2%=" "\2^="
308 "\1+" "\1-" "\3**=" "\2**"
309 "\1/" "\1%" "\1^" "\1*"
310 "\2!=" "\2>=" "\2<=" "\1>"
311 "\1<" "\2!~" "\1~" "\2&&"
312 "\2||" "\1?" "\1:" NTC
313 "\2in" NTC
314 "\1," NTC
315 "\1|" NTC
316 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
317 "\1]" NTC
318 "\1{" NTC
319 "\1}" NTC
320 "\1;" NTC
321 "\1\n" NTC
322 "\2if" "\2do" "\3for" "\5break" /* STATX */
323 "\10continue" "\6delete" "\5print"
324 "\6printf" "\4next" "\10nextfile"
325 "\6return" "\4exit" NTC
326 "\5while" NTC
327 "\4else" NTC
Glenn L McGrath545106f2002-11-11 06:21:00 +0000328
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200329 "\3and" "\5compl" "\6lshift" "\2or"
330 "\6rshift" "\3xor"
331 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
332 "\3cos" "\3exp" "\3int" "\3log"
333 "\4rand" "\3sin" "\4sqrt" "\5srand"
334 "\6gensub" "\4gsub" "\5index" "\6length"
335 "\5match" "\5split" "\7sprintf" "\3sub"
336 "\6substr" "\7systime" "\10strftime" "\6mktime"
337 "\7tolower" "\7toupper" NTC
338 "\7getline" NTC
339 "\4func" "\10function" NTC
340 "\5BEGIN" NTC
341 "\3END"
342 /* compiler adds trailing "\0" */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000343 ;
344
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000345static const uint32_t tokeninfo[] = {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000346 0,
347 0,
348 OC_REGEXP,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200349 xS|'a', xS|'w', xS|'|',
350 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
351 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5),
352 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
353 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
354 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
355 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
356 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
357 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
358 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':',
359 OC_IN|SV|P(49), /* in */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000360 OC_COMMA|SS|P(80),
361 OC_PGETLINE|SV|P(37),
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200362 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!',
363 0, /* ] */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000364 0,
365 0,
366 0,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200367 0, /* \n */
368 ST_IF, ST_DO, ST_FOR, OC_BREAK,
369 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
370 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
371 OC_RETURN|Vx, OC_EXIT|Nx,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000372 ST_WHILE,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200373 0, /* else */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000374
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000375 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
376 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
Glenn L McGrath545106f2002-11-11 06:21:00 +0000377 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
378 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
379 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
380 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
381 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 +0200382 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 +0000383 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
384 OC_GETLINE|SV|P(0),
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200385 0, 0,
Glenn L McGrath545106f2002-11-11 06:21:00 +0000386 0,
Denys Vlasenko6a0d7492010-10-23 21:02:15 +0200387 0 /* END */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000388};
389
390/* internal variable names and their initial values */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000391/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000392enum {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000393 CONVFMT, OFMT, FS, OFS,
Denis Vlasenkof782f522007-01-01 23:51:30 +0000394 ORS, RS, RT, FILENAME,
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000395 SUBSEP, F0, ARGIND, ARGC,
396 ARGV, ERRNO, FNR, NR,
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200397 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS
Glenn L McGrath545106f2002-11-11 06:21:00 +0000398};
399
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000400static const char vNames[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000401 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
402 "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000403 "SUBSEP\0" "$\0*" "ARGIND\0" "ARGC\0"
404 "ARGV\0" "ERRNO\0" "FNR\0" "NR\0"
405 "NF\0*" "IGNORECASE\0*" "ENVIRON\0" "\0";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000406
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000407static const char vValues[] ALIGN1 =
Denis Vlasenkof782f522007-01-01 23:51:30 +0000408 "%.6g\0" "%.6g\0" " \0" " \0"
409 "\n\0" "\n\0" "\0" "\0"
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +0000410 "\034\0" "\0" "\377";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000411
412/* hash size may grow to these values */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000413#define FIRST_PRIME 61
414static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
Glenn L McGrath545106f2002-11-11 06:21:00 +0000415
Glenn L McGrath545106f2002-11-11 06:21:00 +0000416
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000417/* Globals. Split in two parts so that first one is addressed
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000418 * with (mostly short) negative offsets.
419 * NB: it's unsafe to put members of type "double"
420 * into globals2 (gcc may fail to align them).
421 */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000422struct globals {
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000423 double t_double;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000424 chain beginseq, mainseq, endseq;
425 chain *seq;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000426 node *break_ptr, *continue_ptr;
427 rstream *iF;
428 xhash *vhash, *ahash, *fdhash, *fnhash;
429 const char *g_progname;
430 int g_lineno;
431 int nfields;
432 int maxfields; /* used in fsrealloc() only */
433 var *Fields;
434 nvblock *g_cb;
435 char *g_pos;
436 char *g_buf;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000437 smallint icase;
438 smallint exiting;
439 smallint nextrec;
440 smallint nextfile;
441 smallint is_f0_split;
Denys Vlasenko7b46d112011-09-11 00:30:56 +0200442 smallint t_rollback;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000443};
444struct globals2 {
445 uint32_t t_info; /* often used */
446 uint32_t t_tclass;
447 char *t_string;
448 int t_lineno;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000449
450 var *intvar[NUM_INTERNAL_VARS]; /* often used */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000451
452 /* former statics from various functions */
453 char *split_f0__fstrings;
454
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000455 uint32_t next_token__save_tclass;
456 uint32_t next_token__save_info;
457 uint32_t next_token__ltclass;
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000458 smallint next_token__concat_inserted;
459
460 smallint next_input_file__files_happen;
461 rstream next_input_file__rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000462
463 var *evaluate__fnargs;
464 unsigned evaluate__seed;
465 regex_t evaluate__sreg;
466
467 var ptest__v;
468
469 tsplitter exec_builtin__tspl;
470
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000471 /* biggest and least used members go last */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000472 tsplitter fsplitter, rsplitter;
Denys Vlasenko3dbc5a92010-02-05 14:54:22 +0100473};
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000474#define G1 (ptr_to_globals[-1])
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000475#define G (*(struct globals2 *)ptr_to_globals)
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000476/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000477/*char G1size[sizeof(G1)]; - 0x74 */
478/*char Gsize[sizeof(G)]; - 0x1c4 */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000479/* Trying to keep most of members accessible with short offsets: */
Denis Vlasenko9aa5c652009-02-26 11:21:04 +0000480/*char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
481#define t_double (G1.t_double )
Denis Vlasenkoe16e6e72007-06-07 13:14:53 +0000482#define beginseq (G1.beginseq )
483#define mainseq (G1.mainseq )
484#define endseq (G1.endseq )
485#define seq (G1.seq )
486#define break_ptr (G1.break_ptr )
487#define continue_ptr (G1.continue_ptr)
488#define iF (G1.iF )
489#define vhash (G1.vhash )
490#define ahash (G1.ahash )
491#define fdhash (G1.fdhash )
492#define fnhash (G1.fnhash )
493#define g_progname (G1.g_progname )
494#define g_lineno (G1.g_lineno )
495#define nfields (G1.nfields )
496#define maxfields (G1.maxfields )
497#define Fields (G1.Fields )
498#define g_cb (G1.g_cb )
499#define g_pos (G1.g_pos )
500#define g_buf (G1.g_buf )
501#define icase (G1.icase )
502#define exiting (G1.exiting )
503#define nextrec (G1.nextrec )
504#define nextfile (G1.nextfile )
505#define is_f0_split (G1.is_f0_split )
Denys Vlasenko7b46d112011-09-11 00:30:56 +0200506#define t_rollback (G1.t_rollback )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000507#define t_info (G.t_info )
508#define t_tclass (G.t_tclass )
509#define t_string (G.t_string )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000510#define t_lineno (G.t_lineno )
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000511#define intvar (G.intvar )
512#define fsplitter (G.fsplitter )
513#define rsplitter (G.rsplitter )
514#define INIT_G() do { \
Denys Vlasenko90a99042009-09-06 02:36:23 +0200515 SET_PTR_TO_GLOBALS((char*)xzalloc(sizeof(G1)+sizeof(G)) + sizeof(G1)); \
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000516 G.next_token__ltclass = TC_OPTERM; \
517 G.evaluate__seed = 1; \
518} while (0)
519
Glenn L McGrath545106f2002-11-11 06:21:00 +0000520
521/* function prototypes */
Glenn L McGrath545106f2002-11-11 06:21:00 +0000522static void handle_special(var *);
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000523static node *parse_expr(uint32_t);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000524static void chain_group(void);
525static var *evaluate(node *, var *);
526static rstream *next_input_file(void);
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000527static int fmt_num(char *, int, const char *, double, int);
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000528static int awk_exit(int) NORETURN;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000529
530/* ---- error handling ---- */
531
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000532static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
533static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
534static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
535static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
536static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
537static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
538static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
539static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
540static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000541static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
Glenn L McGrath545106f2002-11-11 06:21:00 +0000542
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100543static void zero_out_var(var *vp)
Denis Vlasenkof782f522007-01-01 23:51:30 +0000544{
545 memset(vp, 0, sizeof(*vp));
546}
547
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000548static void syntax_error(const char *message) NORETURN;
549static void syntax_error(const char *message)
Glenn L McGrathd4036f82002-11-28 09:30:40 +0000550{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000551 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000552}
553
Glenn L McGrath545106f2002-11-11 06:21:00 +0000554/* ---- hash stuff ---- */
555
Denis Vlasenkof782f522007-01-01 23:51:30 +0000556static unsigned hashidx(const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000557{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000558 unsigned idx = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000559
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100560 while (*name)
561 idx = *name++ + (idx << 6) - idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000562 return idx;
563}
564
565/* create new hash */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000566static xhash *hash_init(void)
567{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000568 xhash *newhash;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000569
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100570 newhash = xzalloc(sizeof(*newhash));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000571 newhash->csize = FIRST_PRIME;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100572 newhash->items = xzalloc(FIRST_PRIME * sizeof(newhash->items[0]));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000573
574 return newhash;
575}
576
577/* find item in hash, return ptr to data, NULL if not found */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000578static void *hash_search(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000579{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000580 hash_item *hi;
581
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100582 hi = hash->items[hashidx(name) % hash->csize];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000583 while (hi) {
584 if (strcmp(hi->name, name) == 0)
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100585 return &hi->data;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000586 hi = hi->next;
587 }
588 return NULL;
589}
590
591/* grow hash if it becomes too big */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000592static void hash_rebuild(xhash *hash)
593{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000594 unsigned newsize, i, idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000595 hash_item **newitems, *hi, *thi;
596
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000597 if (hash->nprime == ARRAY_SIZE(PRIMES))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000598 return;
599
600 newsize = PRIMES[hash->nprime++];
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100601 newitems = xzalloc(newsize * sizeof(newitems[0]));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000602
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000603 for (i = 0; i < hash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000604 hi = hash->items[i];
605 while (hi) {
606 thi = hi;
607 hi = thi->next;
608 idx = hashidx(thi->name) % newsize;
609 thi->next = newitems[idx];
610 newitems[idx] = thi;
611 }
612 }
613
614 free(hash->items);
615 hash->csize = newsize;
616 hash->items = newitems;
617}
618
619/* find item in hash, add it if necessary. Return ptr to data */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000620static void *hash_find(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000621{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000622 hash_item *hi;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000623 unsigned idx;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000624 int l;
625
626 hi = hash_search(hash, name);
Denis Vlasenkob78c7822007-07-18 18:31:11 +0000627 if (!hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000628 if (++hash->nel / hash->csize > 10)
629 hash_rebuild(hash);
630
Rob Landleya3896512006-05-07 20:20:34 +0000631 l = strlen(name) + 1;
Denis Vlasenko7a676642009-03-15 22:20:31 +0000632 hi = xzalloc(sizeof(*hi) + l);
633 strcpy(hi->name, name);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000634
635 idx = hashidx(name) % hash->csize;
636 hi->next = hash->items[idx];
637 hash->items[idx] = hi;
638 hash->glen += l;
639 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100640 return &hi->data;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000641}
642
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000643#define findvar(hash, name) ((var*) hash_find((hash), (name)))
644#define newvar(name) ((var*) hash_find(vhash, (name)))
645#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
646#define newfunc(name) ((func*) hash_find(fnhash, (name)))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000647
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000648static void hash_remove(xhash *hash, const char *name)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000649{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000650 hash_item *hi, **phi;
651
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100652 phi = &hash->items[hashidx(name) % hash->csize];
Glenn L McGrath545106f2002-11-11 06:21:00 +0000653 while (*phi) {
654 hi = *phi;
655 if (strcmp(hi->name, name) == 0) {
Rob Landleya3896512006-05-07 20:20:34 +0000656 hash->glen -= (strlen(name) + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000657 hash->nel--;
658 *phi = hi->next;
659 free(hi);
660 break;
661 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +0100662 phi = &hi->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000663 }
664}
665
666/* ------ some useful functions ------ */
667
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100668static char *skip_spaces(char *p)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000669{
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000670 while (1) {
671 if (*p == '\\' && p[1] == '\n') {
672 p++;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000673 t_lineno++;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000674 } else if (*p != ' ' && *p != '\t') {
675 break;
676 }
Mike Frysingerde2b9382005-09-27 03:18:00 +0000677 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000678 }
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100679 return p;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000680}
681
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100682/* returns old *s, advances *s past word and terminating NUL */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000683static char *nextword(char **s)
684{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000685 char *p = *s;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100686 while (*(*s)++ != '\0')
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100687 continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000688 return p;
689}
690
Mike Frysinger10a11e22005-09-27 02:23:02 +0000691static char nextchar(char **s)
692{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000693 char c, *pps;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000694
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100695 c = *(*s)++;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000696 pps = *s;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100697 if (c == '\\')
698 c = bb_process_escape_sequence((const char**)s);
Denys Vlasenkoea664dd2012-06-22 18:41:01 +0200699 /* Example awk statement:
700 * s = "abc\"def"
701 * we must treat \" as "
702 */
Denys Vlasenko2b299fe2010-10-24 01:58:04 +0200703 if (c == '\\' && *s == pps) { /* unrecognized \z? */
704 c = *(*s); /* yes, fetch z */
705 if (c)
706 (*s)++; /* advance unless z = NUL */
707 }
Glenn L McGrath545106f2002-11-11 06:21:00 +0000708 return c;
709}
710
Denys Vlasenkoea664dd2012-06-22 18:41:01 +0200711/* TODO: merge with strcpy_and_process_escape_sequences()?
712 */
713static void unescape_string_in_place(char *s1)
714{
715 char *s = s1;
716 while ((*s1 = nextchar(&s)) != '\0')
717 s1++;
718}
719
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000720static ALWAYS_INLINE int isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000721{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000722 return (isalnum(c) || c == '_');
723}
724
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000725static double my_strtod(char **pp)
726{
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200727 char *cp = *pp;
Rob Landleyd8205b32010-10-24 03:27:22 +0200728 if (ENABLE_DESKTOP && cp[0] == '0') {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200729 /* Might be hex or octal integer: 0x123abc or 07777 */
730 char c = (cp[1] | 0x20);
731 if (c == 'x' || isdigit(cp[1])) {
732 unsigned long long ull = strtoull(cp, pp, 0);
733 if (c == 'x')
734 return ull;
735 c = **pp;
736 if (!isdigit(c) && c != '.')
737 return ull;
738 /* else: it may be a floating number. Examples:
739 * 009.123 (*pp points to '9')
740 * 000.123 (*pp points to '.')
741 * fall through to strtod.
742 */
743 }
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000744 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200745 return strtod(cp, pp);
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000746}
747
Glenn L McGrath545106f2002-11-11 06:21:00 +0000748/* -------- working with variables (set/get/copy/etc) -------- */
749
Mike Frysinger10a11e22005-09-27 02:23:02 +0000750static xhash *iamarray(var *v)
751{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000752 var *a = v;
753
754 while (a->type & VF_CHILD)
755 a = a->x.parent;
756
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000757 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000758 a->type |= VF_ARRAY;
759 a->x.array = hash_init();
760 }
761 return a->x.array;
762}
763
Mike Frysinger10a11e22005-09-27 02:23:02 +0000764static void clear_array(xhash *array)
765{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000766 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000767 hash_item *hi, *thi;
768
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000769 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000770 hi = array->items[i];
771 while (hi) {
772 thi = hi;
773 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000774 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000775 free(thi);
776 }
777 array->items[i] = NULL;
778 }
779 array->glen = array->nel = 0;
780}
781
782/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000783static var *clrvar(var *v)
784{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000785 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000786 free(v->string);
787
788 v->type &= VF_DONTTOUCH;
789 v->type |= VF_DIRTY;
790 v->string = NULL;
791 return v;
792}
793
794/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000795static var *setvar_p(var *v, char *value)
796{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000797 clrvar(v);
798 v->string = value;
799 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000800 return v;
801}
802
803/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000804static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000805{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000806 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000807}
808
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100809/* same as setvar_s but sets USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000810static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000811{
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100812 v = setvar_s(v, value);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000813 v->type |= VF_USER;
814 return v;
815}
816
817/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000818static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000819{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000820 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000821
Denys Vlasenko7bb346f2009-10-06 22:09:50 +0200822 v = findvar(iamarray(a), itoa(idx));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000823 setvar_u(v, s);
824}
825
826/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000827static var *setvar_i(var *v, double value)
828{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000829 clrvar(v);
830 v->type |= VF_NUMBER;
831 v->number = value;
832 handle_special(v);
833 return v;
834}
835
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000836static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000837{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000838 /* if v is numeric and has no cached string, convert it to string */
839 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000840 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
841 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000842 v->type |= VF_CACHED;
843 }
844 return (v->string == NULL) ? "" : v->string;
845}
846
Mike Frysinger10a11e22005-09-27 02:23:02 +0000847static double getvar_i(var *v)
848{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000849 char *s;
850
851 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
852 v->number = 0;
853 s = v->string;
854 if (s && *s) {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200855 debug_printf_eval("getvar_i: '%s'->", s);
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000856 v->number = my_strtod(&s);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200857 debug_printf_eval("%f (s:'%s')\n", v->number, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000858 if (v->type & VF_USER) {
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100859 s = skip_spaces(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000860 if (*s != '\0')
861 v->type &= ~VF_USER;
862 }
863 } else {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200864 debug_printf_eval("getvar_i: '%s'->zero\n", s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000865 v->type &= ~VF_USER;
866 }
867 v->type |= VF_CACHED;
868 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200869 debug_printf_eval("getvar_i: %f\n", v->number);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000870 return v->number;
871}
872
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000873/* Used for operands of bitwise ops */
874static unsigned long getvar_i_int(var *v)
875{
876 double d = getvar_i(v);
877
878 /* Casting doubles to longs is undefined for values outside
879 * of target type range. Try to widen it as much as possible */
880 if (d >= 0)
881 return (unsigned long)d;
Denis Vlasenko665eaff2008-09-05 04:59:02 +0000882 /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000883 return - (long) (unsigned long) (-d);
884}
885
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000886static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000887{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000888 if (dest != src) {
889 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000890 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200891 debug_printf_eval("copyvar: number:%f string:'%s'\n", src->number, src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000892 dest->number = src->number;
893 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000894 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000895 }
896 handle_special(dest);
897 return dest;
898}
899
Mike Frysinger10a11e22005-09-27 02:23:02 +0000900static var *incvar(var *v)
901{
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100902 return setvar_i(v, getvar_i(v) + 1.0);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000903}
904
905/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000906static int is_numeric(var *v)
907{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000908 getvar_i(v);
909 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
910}
911
912/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000913static int istrue(var *v)
914{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000915 if (is_numeric(v))
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100916 return (v->number != 0);
917 return (v->string && v->string[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000918}
919
Eric Andersenaff114c2004-04-14 17:51:38 +0000920/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000921static var *nvalloc(int n)
922{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000923 nvblock *pb = NULL;
924 var *v, *r;
925 int size;
926
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000927 while (g_cb) {
928 pb = g_cb;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100929 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size)
930 break;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000931 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000932 }
933
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000934 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000935 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000936 g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000937 g_cb->size = size;
938 g_cb->pos = g_cb->nv;
939 g_cb->prev = pb;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000940 /*g_cb->next = NULL; - xzalloc did it */
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100941 if (pb)
942 pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000943 }
944
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000945 v = r = g_cb->pos;
946 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000947
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000948 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000949 v->type = 0;
950 v->string = NULL;
951 v++;
952 }
953
954 return r;
955}
956
Mike Frysinger10a11e22005-09-27 02:23:02 +0000957static void nvfree(var *v)
958{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000959 var *p;
960
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000961 if (v < g_cb->nv || v >= g_cb->pos)
962 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000963
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000964 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000965 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000966 clear_array(iamarray(p));
967 free(p->x.array->items);
968 free(p->x.array);
969 }
Denys Vlasenko3cb60c32010-03-10 19:20:32 +0100970 if (p->type & VF_WALK) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +0100971 walker_list *n;
972 walker_list *w = p->x.walker;
973 debug_printf_walker("nvfree: freeing walker @%p\n", &p->x.walker);
974 p->x.walker = NULL;
975 while (w) {
976 n = w->prev;
977 debug_printf_walker(" free(%p)\n", w);
978 free(w);
979 w = n;
980 }
Denys Vlasenko3cb60c32010-03-10 19:20:32 +0100981 }
Glenn L McGrath545106f2002-11-11 06:21:00 +0000982 clrvar(p);
983 }
984
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000985 g_cb->pos = v;
986 while (g_cb->prev && g_cb->pos == g_cb->nv) {
987 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000988 }
989}
990
991/* ------- awk program text parsing ------- */
992
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000993/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000994 * If token isn't expected, give away. Return token class
995 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000996static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000997{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000998#define concat_inserted (G.next_token__concat_inserted)
999#define save_tclass (G.next_token__save_tclass)
1000#define save_info (G.next_token__save_info)
1001/* Initialized to TC_OPTERM: */
1002#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001003
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001004 char *p, *s;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001005 const char *tl;
1006 uint32_t tc;
1007 const uint32_t *ti;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001008
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001009 if (t_rollback) {
1010 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001011
1012 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001013 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001014 t_tclass = save_tclass;
1015 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001016
1017 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001018 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001019 readnext:
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +01001020 p = skip_spaces(p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001021 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001022 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001023 while (*p != '\n' && *p != '\0')
1024 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001025
1026 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001027 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001028
1029 if (*p == '\0') {
1030 tc = TC_EOF;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001031 debug_printf_parse("%s: token found: TC_EOF\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001032
1033 } else if (*p == '\"') {
1034 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001035 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001036 while (*p != '\"') {
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02001037 char *pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001038 if (*p == '\0' || *p == '\n')
1039 syntax_error(EMSG_UNEXP_EOS);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02001040 pp = p;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001041 *s++ = nextchar(&pp);
1042 p = pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001043 }
1044 p++;
1045 *s = '\0';
1046 tc = TC_STRING;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001047 debug_printf_parse("%s: token found:'%s' TC_STRING\n", __func__, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001048
1049 } else if ((expected & TC_REGEXP) && *p == '/') {
1050 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001051 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001052 while (*p != '/') {
1053 if (*p == '\0' || *p == '\n')
1054 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +00001055 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001056 if (*s++ == '\\') {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001057 char *pp = p;
1058 s[-1] = bb_process_escape_sequence((const char **)&pp);
1059 if (*p == '\\')
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001060 *s++ = '\\';
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001061 if (pp == p)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001062 *s++ = *p++;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001063 else
1064 p = pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001065 }
1066 }
1067 p++;
1068 *s = '\0';
1069 tc = TC_REGEXP;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001070 debug_printf_parse("%s: token found:'%s' TC_REGEXP\n", __func__, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001071
1072 } else if (*p == '.' || isdigit(*p)) {
1073 /* it's a number */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001074 char *pp = p;
1075 t_double = my_strtod(&pp);
1076 p = pp;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001077 if (*p == '.')
Glenn L McGrath545106f2002-11-11 06:21:00 +00001078 syntax_error(EMSG_UNEXP_TOKEN);
1079 tc = TC_NUMBER;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001080 debug_printf_parse("%s: token found:%f TC_NUMBER\n", __func__, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001081
1082 } else {
1083 /* search for something known */
1084 tl = tokenlist;
1085 tc = 0x00000001;
1086 ti = tokeninfo;
1087 while (*tl) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001088 int l = (unsigned char) *tl++;
1089 if (l == (unsigned char) NTCC) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001090 tc <<= 1;
1091 continue;
1092 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001093 /* if token class is expected,
1094 * token matches,
1095 * and it's not a longer word,
Glenn L McGrath545106f2002-11-11 06:21:00 +00001096 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001097 if ((tc & (expected | TC_WORD | TC_NEWLINE))
Denys Vlasenko28458c62010-10-05 16:49:03 +02001098 && strncmp(p, tl, l) == 0
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001099 && !((tc & TC_WORD) && isalnum_(p[l]))
1100 ) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001101 /* then this is what we are looking for */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001102 t_info = *ti;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001103 debug_printf_parse("%s: token found:'%.*s' t_info:%x\n", __func__, l, p, t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001104 p += l;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001105 goto token_found;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001106 }
1107 ti++;
1108 tl += l;
1109 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001110 /* not a known token */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001111
Denys Vlasenko28458c62010-10-05 16:49:03 +02001112 /* is it a name? (var/array/function) */
1113 if (!isalnum_(*p))
1114 syntax_error(EMSG_UNEXP_TOKEN); /* no */
1115 /* yes */
1116 t_string = --p;
1117 while (isalnum_(*++p)) {
1118 p[-1] = *p;
1119 }
1120 p[-1] = '\0';
1121 tc = TC_VARIABLE;
1122 /* also consume whitespace between functionname and bracket */
1123 if (!(expected & TC_VARIABLE) || (expected & TC_ARRAY))
1124 p = skip_spaces(p);
1125 if (*p == '(') {
1126 tc = TC_FUNCTION;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001127 debug_printf_parse("%s: token found:'%s' TC_FUNCTION\n", __func__, t_string);
Denys Vlasenko28458c62010-10-05 16:49:03 +02001128 } else {
1129 if (*p == '[') {
1130 p++;
1131 tc = TC_ARRAY;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001132 debug_printf_parse("%s: token found:'%s' TC_ARRAY\n", __func__, t_string);
1133 } else
1134 debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001135 }
1136 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001137 token_found:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001138 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001139
1140 /* skipping newlines in some cases */
1141 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1142 goto readnext;
1143
1144 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001145 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001146 concat_inserted = TRUE;
1147 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001148 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001149 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001150 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001151 }
1152
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001153 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001154 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001155 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001156
1157 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001158 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001159 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001160 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001161
1162 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001163#undef concat_inserted
1164#undef save_tclass
1165#undef save_info
1166#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001167}
1168
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001169static void rollback_token(void)
1170{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001171 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001172}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001173
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001174static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001175{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001176 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001177
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001178 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001179 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001180 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001181 return n;
1182}
1183
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001184static void mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001185{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001186 n->info = OC_REGEXP;
1187 n->l.re = re;
1188 n->r.ire = re + 1;
1189 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001190 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001191}
1192
Mike Frysinger10a11e22005-09-27 02:23:02 +00001193static node *condition(void)
1194{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001195 next_token(TC_SEQSTART);
1196 return parse_expr(TC_SEQTERM);
1197}
1198
1199/* parse expression terminated by given argument, return ptr
1200 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001201static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001202{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001203 node sn;
1204 node *cn = &sn;
1205 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001206 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001207 var *v;
1208
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001209 debug_printf_parse("%s(%x)\n", __func__, iexp);
1210
Glenn L McGrath545106f2002-11-11 06:21:00 +00001211 sn.info = PRIMASK;
1212 sn.r.n = glptr = NULL;
1213 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1214
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001215 while (!((tc = next_token(xtc)) & iexp)) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001216
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001217 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001218 /* input redirection (<) attached to glptr node */
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001219 debug_printf_parse("%s: input redir\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001220 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001221 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001222 xtc = TC_OPERAND | TC_UOPPRE;
1223 glptr = NULL;
1224
1225 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001226 debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001227 /* for binary and postfix-unary operators, jump back over
1228 * previous operators with higher priority */
1229 vn = cn;
Denys Vlasenkocdeda162009-11-30 01:14:16 +01001230 while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1231 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON))
1232 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001233 vn = vn->a.n;
Denys Vlasenkocdeda162009-11-30 01:14:16 +01001234 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001235 if ((t_info & OPCLSMASK) == OC_TERNARY)
1236 t_info += P(6);
1237 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001238 cn->a.n = vn->a.n;
1239 if (tc & TC_BINOP) {
1240 cn->l.n = vn;
1241 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001242 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001243 /* it's a pipe */
1244 next_token(TC_GETLINE);
1245 /* give maximum priority to this pipe */
1246 cn->info &= ~PRIMASK;
1247 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1248 }
1249 } else {
1250 cn->r.n = vn;
1251 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1252 }
1253 vn->a.n = cn;
1254
1255 } else {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001256 debug_printf_parse("%s: other\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001257 /* for operands and prefix-unary operators, attach them
1258 * to last node */
1259 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001260 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001261 cn->a.n = vn;
1262 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1263 if (tc & (TC_OPERAND | TC_REGEXP)) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001264 debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__);
Rob Landleyed830e82005-06-07 02:43:52 +00001265 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001266 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001267 * only simple tclasses should be used! */
1268 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001269 case TC_VARIABLE:
1270 case TC_ARRAY:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001271 debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001272 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001273 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001274 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001275 cn->info = OC_FNARG;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001276 cn->l.aidx = v->x.aidx;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001277 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001278 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001279 }
1280 if (tc & TC_ARRAY) {
1281 cn->info |= xS;
1282 cn->r.n = parse_expr(TC_ARRTERM);
1283 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001284 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001285
Denis Vlasenkof782f522007-01-01 23:51:30 +00001286 case TC_NUMBER:
1287 case TC_STRING:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001288 debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001289 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001290 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001291 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001292 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001293 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001294 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001295 break;
1296
Denis Vlasenkof782f522007-01-01 23:51:30 +00001297 case TC_REGEXP:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001298 debug_printf_parse("%s: TC_REGEXP\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001299 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001300 break;
1301
Denis Vlasenkof782f522007-01-01 23:51:30 +00001302 case TC_FUNCTION:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001303 debug_printf_parse("%s: TC_FUNCTION\n", __func__);
Mike Frysingerde2b9382005-09-27 03:18:00 +00001304 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001305 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001306 cn->l.n = condition();
1307 break;
1308
Denis Vlasenkof782f522007-01-01 23:51:30 +00001309 case TC_SEQSTART:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001310 debug_printf_parse("%s: TC_SEQSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001311 cn = vn->r.n = parse_expr(TC_SEQTERM);
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001312 if (!cn)
1313 syntax_error("Empty sequence");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001314 cn->a.n = vn;
1315 break;
1316
Denis Vlasenkof782f522007-01-01 23:51:30 +00001317 case TC_GETLINE:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001318 debug_printf_parse("%s: TC_GETLINE\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001319 glptr = cn;
1320 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1321 break;
1322
Denis Vlasenkof782f522007-01-01 23:51:30 +00001323 case TC_BUILTIN:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001324 debug_printf_parse("%s: TC_BUILTIN\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001325 cn->l.n = condition();
1326 break;
1327 }
1328 }
1329 }
1330 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001331
1332 debug_printf_parse("%s() returns %p\n", __func__, sn.r.n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001333 return sn.r.n;
1334}
1335
1336/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001337static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001338{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001339 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001340
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001341 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001342 seq->first = seq->last = new_node(0);
1343
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001344 if (seq->programname != g_progname) {
1345 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001346 n = chain_node(OC_NEWSOURCE);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001347 n->l.new_progname = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001348 }
1349
1350 n = seq->last;
1351 n->info = info;
1352 seq->last = n->a.n = new_node(OC_DONE);
1353
1354 return n;
1355}
1356
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001357static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001358{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001359 node *n;
1360
1361 n = chain_node(info);
1362 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001363 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001364 rollback_token();
1365}
1366
Mike Frysinger10a11e22005-09-27 02:23:02 +00001367static node *chain_loop(node *nn)
1368{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001369 node *n, *n2, *save_brk, *save_cont;
1370
1371 save_brk = break_ptr;
1372 save_cont = continue_ptr;
1373
1374 n = chain_node(OC_BR | Vx);
1375 continue_ptr = new_node(OC_EXEC);
1376 break_ptr = new_node(OC_EXEC);
1377 chain_group();
1378 n2 = chain_node(OC_EXEC | Vx);
1379 n2->l.n = nn;
1380 n2->a.n = n;
1381 continue_ptr->a.n = n2;
1382 break_ptr->a.n = n->r.n = seq->last;
1383
1384 continue_ptr = save_cont;
1385 break_ptr = save_brk;
1386
1387 return n;
1388}
1389
1390/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001391static void chain_group(void)
1392{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001393 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001394 node *n, *n2, *n3;
1395
1396 do {
1397 c = next_token(TC_GRPSEQ);
1398 } while (c & TC_NEWLINE);
1399
1400 if (c & TC_GRPSTART) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001401 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001402 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001403 debug_printf_parse("%s: !TC_GRPTERM\n", __func__);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001404 if (t_tclass & TC_NEWLINE)
1405 continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001406 rollback_token();
1407 chain_group();
1408 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001409 debug_printf_parse("%s: TC_GRPTERM\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001410 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001411 debug_printf_parse("%s: TC_OPSEQ | TC_OPTERM\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001412 rollback_token();
1413 chain_expr(OC_EXEC | Vx);
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001414 } else {
1415 /* TC_STATEMNT */
1416 debug_printf_parse("%s: TC_STATEMNT(?)\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001417 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001418 case ST_IF:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001419 debug_printf_parse("%s: ST_IF\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001420 n = chain_node(OC_BR | Vx);
1421 n->l.n = condition();
1422 chain_group();
1423 n2 = chain_node(OC_EXEC);
1424 n->r.n = seq->last;
1425 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001426 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001427 n2->a.n = seq->last;
1428 } else {
1429 rollback_token();
1430 }
1431 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001432
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001433 case ST_WHILE:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001434 debug_printf_parse("%s: ST_WHILE\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001435 n2 = condition();
1436 n = chain_loop(NULL);
1437 n->l.n = n2;
1438 break;
1439
1440 case ST_DO:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001441 debug_printf_parse("%s: ST_DO\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001442 n2 = chain_node(OC_EXEC);
1443 n = chain_loop(NULL);
1444 n2->a.n = n->a.n;
1445 next_token(TC_WHILE);
1446 n->l.n = condition();
1447 break;
1448
1449 case ST_FOR:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001450 debug_printf_parse("%s: ST_FOR\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001451 next_token(TC_SEQSTART);
1452 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001453 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001454 if ((n2->info & OPCLSMASK) != OC_IN)
1455 syntax_error(EMSG_UNEXP_TOKEN);
1456 n = chain_node(OC_WALKINIT | VV);
1457 n->l.n = n2->l.n;
1458 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001459 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001460 n->info = OC_WALKNEXT | Vx;
1461 n->l.n = n2->l.n;
1462 } else { /* for (;;) */
1463 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001464 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001465 n2 = parse_expr(TC_SEMICOL);
1466 n3 = parse_expr(TC_SEQTERM);
1467 n = chain_loop(n3);
1468 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001469 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001470 n->info = OC_EXEC;
1471 }
1472 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001473
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001474 case OC_PRINT:
1475 case OC_PRINTF:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001476 debug_printf_parse("%s: OC_PRINT[F]\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001477 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001478 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001479 if (t_tclass & TC_OUTRDR) {
1480 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001481 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1482 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001483 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001484 rollback_token();
1485 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001486
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001487 case OC_BREAK:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001488 debug_printf_parse("%s: OC_BREAK\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001489 n = chain_node(OC_EXEC);
1490 n->a.n = break_ptr;
1491 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001492
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001493 case OC_CONTINUE:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001494 debug_printf_parse("%s: OC_CONTINUE\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001495 n = chain_node(OC_EXEC);
1496 n->a.n = continue_ptr;
1497 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001498
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001499 /* delete, next, nextfile, return, exit */
1500 default:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001501 debug_printf_parse("%s: default\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001502 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001503 }
1504 }
1505}
1506
Mike Frysinger10a11e22005-09-27 02:23:02 +00001507static void parse_program(char *p)
1508{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001509 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001510 node *cn;
1511 func *f;
1512 var *v;
1513
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001514 g_pos = p;
1515 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001516 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001517 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001518
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001519 if (tclass & TC_OPTERM) {
1520 debug_printf_parse("%s: TC_OPTERM\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001521 continue;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001522 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001523
1524 seq = &mainseq;
1525 if (tclass & TC_BEGIN) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001526 debug_printf_parse("%s: TC_BEGIN\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001527 seq = &beginseq;
1528 chain_group();
1529
1530 } else if (tclass & TC_END) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001531 debug_printf_parse("%s: TC_END\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001532 seq = &endseq;
1533 chain_group();
1534
1535 } else if (tclass & TC_FUNCDECL) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001536 debug_printf_parse("%s: TC_FUNCDECL\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001537 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001538 g_pos++;
1539 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001540 f->body.first = NULL;
1541 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001542 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001543 v = findvar(ahash, t_string);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001544 v->x.aidx = f->nargs++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001545
1546 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1547 break;
1548 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001549 seq = &f->body;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001550 chain_group();
1551 clear_array(ahash);
1552
1553 } else if (tclass & TC_OPSEQ) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001554 debug_printf_parse("%s: TC_OPSEQ\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001555 rollback_token();
1556 cn = chain_node(OC_TEST);
1557 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001558 if (t_tclass & TC_GRPSTART) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001559 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001560 rollback_token();
1561 chain_group();
1562 } else {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001563 debug_printf_parse("%s: !TC_GRPSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001564 chain_node(OC_PRINT);
1565 }
1566 cn->r.n = mainseq.last;
1567
1568 } else /* if (tclass & TC_GRPSTART) */ {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001569 debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001570 rollback_token();
1571 chain_group();
1572 }
1573 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001574 debug_printf_parse("%s: TC_EOF\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001575}
1576
1577
1578/* -------- program execution part -------- */
1579
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001580static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001581{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001582 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001583 node *n;
1584
1585 re = &spl->re[0];
1586 ire = &spl->re[1];
1587 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001588 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001589 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001590 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001591 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001592 if (s[0] && s[1]) { /* strlen(s) > 1 */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001593 mk_re_node(s, n, re);
1594 } else {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001595 n->info = (uint32_t) s[0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001596 }
1597
1598 return n;
1599}
1600
1601/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001602 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001603 * be later regfree'd manually
1604 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001605static regex_t *as_regex(node *op, regex_t *preg)
1606{
Denis Vlasenko7a676642009-03-15 22:20:31 +00001607 int cflags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001608 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001609 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001610
1611 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1612 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001613 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001614 v = nvalloc(1);
1615 s = getvar_s(evaluate(op, v));
Denis Vlasenko7a676642009-03-15 22:20:31 +00001616
1617 cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED;
1618 /* Testcase where REG_EXTENDED fails (unpaired '{'):
1619 * echo Hi | awk 'gsub("@(samp|code|file)\{","");'
1620 * gawk 3.1.5 eats this. We revert to ~REG_EXTENDED
1621 * (maybe gsub is not supposed to use REG_EXTENDED?).
1622 */
1623 if (regcomp(preg, s, cflags)) {
1624 cflags &= ~REG_EXTENDED;
1625 xregcomp(preg, s, cflags);
1626 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001627 nvfree(v);
1628 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001629}
1630
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001631/* gradually increasing buffer.
1632 * note that we reallocate even if n == old_size,
1633 * and thus there is at least one extra allocated byte.
1634 */
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001635static char* qrealloc(char *b, int n, int *size)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001636{
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001637 if (!b || n >= *size) {
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001638 *size = n + (n>>1) + 80;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001639 b = xrealloc(b, *size);
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001640 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001641 return b;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001642}
1643
1644/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001645static void fsrealloc(int size)
1646{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001647 int i;
1648
1649 if (size >= maxfields) {
1650 i = maxfields;
1651 maxfields = size + 16;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001652 Fields = xrealloc(Fields, maxfields * sizeof(Fields[0]));
Denis Vlasenkof782f522007-01-01 23:51:30 +00001653 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001654 Fields[i].type = VF_SPECIAL;
1655 Fields[i].string = NULL;
1656 }
1657 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001658 /* if size < nfields, clear extra field variables */
1659 for (i = size; i < nfields; i++) {
1660 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001661 }
1662 nfields = size;
1663}
1664
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001665static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001666{
Denys Vlasenko28458c62010-10-05 16:49:03 +02001667 int l, n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001668 char c[4];
1669 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001670 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001671
1672 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001673 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1674 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001675
1676 c[0] = c[1] = (char)spl->info;
1677 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001678 if (*getvar_s(intvar[RS]) == '\0')
1679 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001680
Denys Vlasenko28458c62010-10-05 16:49:03 +02001681 n = 0;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001682 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1683 if (!*s)
1684 return n; /* "": zero fields */
1685 n++; /* at least one field will be there */
1686 do {
1687 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001688 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1689 && pmatch[0].rm_so <= l
1690 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001691 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001692 if (pmatch[0].rm_eo == 0) {
1693 l++;
1694 pmatch[0].rm_eo++;
1695 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001696 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001697 } else {
1698 pmatch[0].rm_eo = l;
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001699 if (s[l])
1700 pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001701 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001702 memcpy(s1, s, l);
Denis Vlasenko67b5eeb2009-04-12 13:54:13 +00001703 /* make sure we remove *all* of the separator chars */
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001704 do {
1705 s1[l] = '\0';
1706 } while (++l < pmatch[0].rm_eo);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001707 nextword(&s1);
1708 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001709 } while (*s);
1710 return n;
1711 }
1712 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001713 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001714 *s1++ = *s++;
1715 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001716 n++;
1717 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001718 return n;
1719 }
1720 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001721 if (icase) {
1722 c[0] = toupper(c[0]);
1723 c[1] = tolower(c[1]);
1724 }
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001725 if (*s1)
1726 n++;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001727 while ((s1 = strpbrk(s1, c)) != NULL) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001728 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001729 n++;
1730 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001731 return n;
1732 }
1733 /* space split */
1734 while (*s) {
1735 s = skip_whitespace(s);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001736 if (!*s)
1737 break;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001738 n++;
1739 while (*s && !isspace(*s))
1740 *s1++ = *s++;
1741 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001742 }
1743 return n;
1744}
1745
Mike Frysinger10a11e22005-09-27 02:23:02 +00001746static void split_f0(void)
1747{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001748/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001749#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001750
Glenn L McGrath545106f2002-11-11 06:21:00 +00001751 int i, n;
1752 char *s;
1753
1754 if (is_f0_split)
1755 return;
1756
1757 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001758 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001759 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001760 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001761 fsrealloc(n);
1762 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001763 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001764 Fields[i].string = nextword(&s);
1765 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1766 }
1767
1768 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001769 clrvar(intvar[NF]);
1770 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1771 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001772#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001773}
1774
1775/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001776static void handle_special(var *v)
1777{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001778 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001779 char *b;
1780 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001781 int sl, l, len, i, bsize;
1782
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001783 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001784 return;
1785
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001786 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001787 n = (int)getvar_i(v);
1788 fsrealloc(n);
1789
1790 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001791 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001792 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001793 b = NULL;
1794 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001795 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001796 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001797 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001798 if (b) {
1799 memcpy(b+len, sep, sl);
1800 len += sl;
1801 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001802 b = qrealloc(b, len+l+sl, &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001803 memcpy(b+len, s, l);
1804 len += l;
1805 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001806 if (b)
1807 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001808 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001809 is_f0_split = TRUE;
1810
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001811 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001812 is_f0_split = FALSE;
1813
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001814 } else if (v == intvar[FS]) {
Denys Vlasenkodf8066a2012-07-11 01:27:15 +02001815 /*
1816 * The POSIX-2008 standard says that changing FS should have no effect on the
1817 * current input line, but only on the next one. The language is:
1818 *
1819 * > Before the first reference to a field in the record is evaluated, the record
1820 * > shall be split into fields, according to the rules in Regular Expressions,
1821 * > using the value of FS that was current at the time the record was read.
1822 *
1823 * So, split up current line before assignment to FS:
1824 */
1825 split_f0();
1826
Glenn L McGrath545106f2002-11-11 06:21:00 +00001827 mk_splitter(getvar_s(v), &fsplitter);
1828
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001829 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001830 mk_splitter(getvar_s(v), &rsplitter);
1831
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001832 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001833 icase = istrue(v);
1834
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001835 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001836 n = getvar_i(intvar[NF]);
1837 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001838 /* right here v is invalid. Just to note... */
1839 }
1840}
1841
1842/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001843static node *nextarg(node **pn)
1844{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001845 node *n;
1846
1847 n = *pn;
1848 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1849 *pn = n->r.n;
1850 n = n->l.n;
1851 } else {
1852 *pn = NULL;
1853 }
1854 return n;
1855}
1856
Mike Frysinger10a11e22005-09-27 02:23:02 +00001857static void hashwalk_init(var *v, xhash *array)
1858{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001859 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001860 unsigned i;
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001861 walker_list *w;
1862 walker_list *prev_walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001863
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001864 if (v->type & VF_WALK) {
1865 prev_walker = v->x.walker;
1866 } else {
1867 v->type |= VF_WALK;
1868 prev_walker = NULL;
1869 }
1870 debug_printf_walker("hashwalk_init: prev_walker:%p\n", prev_walker);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001871
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001872 w = v->x.walker = xzalloc(sizeof(*w) + array->glen + 1); /* why + 1? */
1873 debug_printf_walker(" walker@%p=%p\n", &v->x.walker, w);
1874 w->cur = w->end = w->wbuf;
1875 w->prev = prev_walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001876 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001877 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001878 while (hi) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001879 strcpy(w->end, hi->name);
1880 nextword(&w->end);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001881 hi = hi->next;
1882 }
1883 }
1884}
1885
Mike Frysinger10a11e22005-09-27 02:23:02 +00001886static int hashwalk_next(var *v)
1887{
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001888 walker_list *w = v->x.walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001889
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001890 if (w->cur >= w->end) {
1891 walker_list *prev_walker = w->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001892
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001893 debug_printf_walker("end of iteration, free(walker@%p:%p), prev_walker:%p\n", &v->x.walker, w, prev_walker);
1894 free(w);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001895 v->x.walker = prev_walker;
1896 return FALSE;
1897 }
1898
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001899 setvar_s(v, nextword(&w->cur));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001900 return TRUE;
1901}
1902
1903/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001904static int ptest(node *pattern)
1905{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001906 /* ptest__v is "static": to save stack space? */
1907 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001908}
1909
1910/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001911static int awk_getline(rstream *rsm, var *v)
1912{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001913 char *b;
1914 regmatch_t pmatch[2];
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001915 int size, a, p, pp = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001916 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001917 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001918
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02001919 debug_printf_eval("entered %s()\n", __func__);
1920
Glenn L McGrath545106f2002-11-11 06:21:00 +00001921 /* we're using our own buffer since we need access to accumulating
1922 * characters
1923 */
1924 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001925 m = rsm->buffer;
1926 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001927 p = rsm->pos;
1928 size = rsm->size;
1929 c = (char) rsplitter.n.info;
1930 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001931
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001932 if (!m)
1933 m = qrealloc(m, 256, &size);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001934
Glenn L McGrath545106f2002-11-11 06:21:00 +00001935 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001936 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001937 so = eo = p;
1938 r = 1;
1939 if (p > 0) {
1940 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1941 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001942 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001943 so = pmatch[0].rm_so;
1944 eo = pmatch[0].rm_eo;
1945 if (b[eo] != '\0')
1946 break;
1947 }
1948 } else if (c != '\0') {
1949 s = strchr(b+pp, c);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001950 if (!s)
1951 s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001952 if (s) {
1953 so = eo = s-b;
1954 eo++;
1955 break;
1956 }
1957 } else {
1958 while (b[rp] == '\n')
1959 rp++;
1960 s = strstr(b+rp, "\n\n");
1961 if (s) {
1962 so = eo = s-b;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001963 while (b[eo] == '\n')
1964 eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001965 if (b[eo] != '\0')
1966 break;
1967 }
1968 }
1969 }
1970
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001971 if (a > 0) {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001972 memmove(m, m+a, p+1);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001973 b = m;
1974 a = 0;
1975 }
1976
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001977 m = qrealloc(m, a+p+128, &size);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001978 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001979 pp = p;
1980 p += safe_read(fd, b+p, size-p-1);
1981 if (p < pp) {
1982 p = 0;
1983 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001984 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001985 }
1986 b[p] = '\0';
1987
1988 } while (p > pp);
1989
1990 if (p == 0) {
1991 r--;
1992 } else {
1993 c = b[so]; b[so] = '\0';
1994 setvar_s(v, b+rp);
1995 v->type |= VF_USER;
1996 b[so] = c;
1997 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001998 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001999 b[eo] = c;
2000 }
2001
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002002 rsm->buffer = m;
2003 rsm->adv = a + eo;
2004 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002005 rsm->size = size;
2006
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002007 debug_printf_eval("returning from %s(): %d\n", __func__, r);
2008
Glenn L McGrath545106f2002-11-11 06:21:00 +00002009 return r;
2010}
2011
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002012static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002013{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002014 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002015 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002016 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002017
2018 if (int_as_int && n == (int)n) {
2019 r = snprintf(b, size, "%d", (int)n);
2020 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002021 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002022 if (strchr("diouxX", c)) {
2023 r = snprintf(b, size, format, (int)n);
2024 } else if (strchr("eEfgG", c)) {
2025 r = snprintf(b, size, format, n);
2026 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002027 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002028 }
2029 }
2030 return r;
2031}
2032
Glenn L McGrath545106f2002-11-11 06:21:00 +00002033/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002034static char *awk_printf(node *n)
2035{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002036 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002037 char *fmt, *s, *f;
2038 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002039 int i, j, incr, bsize;
2040 char c, c1;
2041 var *v, *arg;
2042
2043 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00002044 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002045
2046 i = 0;
2047 while (*f) {
2048 s = f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002049 while (*f && (*f != '%' || *++f == '%'))
Glenn L McGrath545106f2002-11-11 06:21:00 +00002050 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00002051 while (*f && !isalpha(*f)) {
2052 if (*f == '*')
2053 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002054 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00002055 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002056
2057 incr = (f - s) + MAXVARFMT;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01002058 b = qrealloc(b, incr + i, &bsize);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002059 c = *f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002060 if (c != '\0')
2061 f++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002062 c1 = *f;
2063 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00002064 arg = evaluate(nextarg(&n), v);
2065
2066 j = i;
2067 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002068 i += sprintf(b+i, s, is_numeric(arg) ?
2069 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002070 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00002071 s1 = getvar_s(arg);
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01002072 b = qrealloc(b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002073 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002074 } else {
2075 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
2076 }
2077 *f = c1;
2078
2079 /* if there was an error while sprintf, return value is negative */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002080 if (i < j)
2081 i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002082 }
2083
Glenn L McGrath545106f2002-11-11 06:21:00 +00002084 free(fmt);
2085 nvfree(v);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002086 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002087 b[i] = '\0';
2088 return b;
2089}
2090
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002091/* Common substitution routine.
2092 * Replace (nm)'th substring of (src) that matches (rn) with (repl),
2093 * store result into (dest), return number of substitutions.
2094 * If nm = 0, replace all matches.
2095 * If src or dst is NULL, use $0.
2096 * If subexp != 0, enable subexpression matching (\1-\9).
Glenn L McGrath545106f2002-11-11 06:21:00 +00002097 */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002098static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int subexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002099{
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002100 char *resbuf;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002101 const char *sp;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002102 int match_no, residx, replen, resbufsize;
2103 int regexec_flags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002104 regmatch_t pmatch[10];
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002105 regex_t sreg, *regex;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002106
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002107 resbuf = NULL;
2108 residx = 0;
2109 match_no = 0;
2110 regexec_flags = 0;
2111 regex = as_regex(rn, &sreg);
2112 sp = getvar_s(src ? src : intvar[F0]);
2113 replen = strlen(repl);
2114 while (regexec(regex, sp, 10, pmatch, regexec_flags) == 0) {
2115 int so = pmatch[0].rm_so;
2116 int eo = pmatch[0].rm_eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002117
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002118 //bb_error_msg("match %u: [%u,%u] '%s'%p", match_no+1, so, eo, sp,sp);
2119 resbuf = qrealloc(resbuf, residx + eo + replen, &resbufsize);
2120 memcpy(resbuf + residx, sp, eo);
2121 residx += eo;
2122 if (++match_no >= nm) {
2123 const char *s;
2124 int nbs;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002125
Glenn L McGrath545106f2002-11-11 06:21:00 +00002126 /* replace */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002127 residx -= (eo - so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002128 nbs = 0;
2129 for (s = repl; *s; s++) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002130 char c = resbuf[residx++] = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002131 if (c == '\\') {
2132 nbs++;
2133 continue;
2134 }
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002135 if (c == '&' || (subexp && c >= '0' && c <= '9')) {
2136 int j;
2137 residx -= ((nbs + 3) >> 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002138 j = 0;
2139 if (c != '&') {
2140 j = c - '0';
2141 nbs++;
2142 }
2143 if (nbs % 2) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002144 resbuf[residx++] = c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002145 } else {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002146 int n = pmatch[j].rm_eo - pmatch[j].rm_so;
2147 resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize);
2148 memcpy(resbuf + residx, sp + pmatch[j].rm_so, n);
2149 residx += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002150 }
2151 }
2152 nbs = 0;
2153 }
2154 }
2155
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002156 regexec_flags = REG_NOTBOL;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002157 sp += eo;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002158 if (match_no == nm)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002159 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002160 if (eo == so) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002161 /* Empty match (e.g. "b*" will match anywhere).
2162 * Advance by one char. */
2163//BUG (bug 1333):
2164//gsub(/\<b*/,"") on "abc" will reach this point, advance to "bc"
2165//... and will erroneously match "b" even though it is NOT at the word start.
2166//we need REG_NOTBOW but it does not exist...
Denys Vlasenko7379cd12010-04-04 01:48:12 +02002167//TODO: if EXTRA_COMPAT=y, use GNU matching and re_search,
2168//it should be able to do it correctly.
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002169 /* Subtle: this is safe only because
2170 * qrealloc allocated at least one extra byte */
2171 resbuf[residx] = *sp;
2172 if (*sp == '\0')
2173 goto ret;
2174 sp++;
2175 residx++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002176 }
2177 }
2178
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002179 resbuf = qrealloc(resbuf, residx + strlen(sp), &resbufsize);
2180 strcpy(resbuf + residx, sp);
2181 ret:
2182 //bb_error_msg("end sp:'%s'%p", sp,sp);
2183 setvar_p(dest ? dest : intvar[F0], resbuf);
2184 if (regex == &sreg)
2185 regfree(regex);
2186 return match_no;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002187}
2188
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002189static NOINLINE int do_mktime(const char *ds)
2190{
2191 struct tm then;
2192 int count;
2193
2194 /*memset(&then, 0, sizeof(then)); - not needed */
2195 then.tm_isdst = -1; /* default is unknown */
2196
2197 /* manpage of mktime says these fields are ints,
2198 * so we can sscanf stuff directly into them */
2199 count = sscanf(ds, "%u %u %u %u %u %u %d",
2200 &then.tm_year, &then.tm_mon, &then.tm_mday,
2201 &then.tm_hour, &then.tm_min, &then.tm_sec,
2202 &then.tm_isdst);
2203
2204 if (count < 6
2205 || (unsigned)then.tm_mon < 1
2206 || (unsigned)then.tm_year < 1900
2207 ) {
2208 return -1;
2209 }
2210
2211 then.tm_mon -= 1;
Denys Vlasenkobc3e9472009-09-21 04:16:00 +02002212 then.tm_year -= 1900;
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002213
2214 return mktime(&then);
2215}
2216
2217static NOINLINE var *exec_builtin(node *op, var *res)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002218{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002219#define tspl (G.exec_builtin__tspl)
2220
Glenn L McGrath545106f2002-11-11 06:21:00 +00002221 var *tv;
2222 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002223 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002224 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002225 regmatch_t pmatch[2];
2226 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002227 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002228 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002229 int nargs;
2230 time_t tt;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002231 int i, l, ll, n;
2232
2233 tv = nvalloc(4);
2234 isr = info = op->info;
2235 op = op->l.n;
2236
2237 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002238 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002239 an[i] = nextarg(&op);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002240 if (isr & 0x09000000)
2241 av[i] = evaluate(an[i], &tv[i]);
2242 if (isr & 0x08000000)
2243 as[i] = getvar_s(av[i]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002244 isr >>= 1;
2245 }
2246
2247 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002248 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002249 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002250
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002251 info &= OPNMASK;
2252 switch (info) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002253
Denis Vlasenkof782f522007-01-01 23:51:30 +00002254 case B_a2:
Rob Landleyd8205b32010-10-24 03:27:22 +02002255 if (ENABLE_FEATURE_AWK_LIBM)
2256 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
2257 else
2258 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002259 break;
2260
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002261 case B_sp: {
2262 char *s, *s1;
2263
Glenn L McGrath545106f2002-11-11 06:21:00 +00002264 if (nargs > 2) {
2265 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2266 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2267 } else {
2268 spl = &fsplitter.n;
2269 }
2270
2271 n = awk_split(as[0], spl, &s);
2272 s1 = s;
2273 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002274 for (i = 1; i <= n; i++)
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002275 setari_u(av[1], i, nextword(&s));
2276 free(s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002277 setvar_i(res, n);
2278 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002279 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002280
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002281 case B_ss: {
2282 char *s;
2283
Rob Landleya3896512006-05-07 20:20:34 +00002284 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002285 i = getvar_i(av[1]) - 1;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002286 if (i > l)
2287 i = l;
2288 if (i < 0)
2289 i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002290 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002291 if (n < 0)
2292 n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002293 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002294 setvar_p(res, s);
2295 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002296 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002297
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002298 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2299 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002300 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002301 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002302 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002303
Denis Vlasenkof782f522007-01-01 23:51:30 +00002304 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002305 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002306 break;
2307
Denis Vlasenkof782f522007-01-01 23:51:30 +00002308 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002309 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002310 break;
2311
Denis Vlasenkof782f522007-01-01 23:51:30 +00002312 case B_or:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002313 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002314 break;
2315
Denis Vlasenkof782f522007-01-01 23:51:30 +00002316 case B_rs:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002317 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002318 break;
2319
Denis Vlasenkof782f522007-01-01 23:51:30 +00002320 case B_xo:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002321 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002322 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002323
Denis Vlasenkof782f522007-01-01 23:51:30 +00002324 case B_lo:
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002325 case B_up: {
2326 char *s, *s1;
Rob Landleyd921b2e2006-08-03 15:41:12 +00002327 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002328 while (*s1) {
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002329 //*s1 = (info == B_up) ? toupper(*s1) : tolower(*s1);
2330 if ((unsigned char)((*s1 | 0x20) - 'a') <= ('z' - 'a'))
2331 *s1 = (info == B_up) ? (*s1 & 0xdf) : (*s1 | 0x20);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002332 s1++;
2333 }
2334 setvar_p(res, s);
2335 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002336 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002337
Denis Vlasenkof782f522007-01-01 23:51:30 +00002338 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002339 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002340 ll = strlen(as[1]);
2341 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002342 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002343 if (!icase) {
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002344 char *s = strstr(as[0], as[1]);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002345 if (s)
2346 n = (s - as[0]) + 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002347 } else {
2348 /* this piece of code is terribly slow and
2349 * really should be rewritten
2350 */
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002351 for (i = 0; i <= l; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002352 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2353 n = i+1;
2354 break;
2355 }
2356 }
2357 }
2358 }
2359 setvar_i(res, n);
2360 break;
2361
Denis Vlasenkof782f522007-01-01 23:51:30 +00002362 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002363 if (nargs > 1)
2364 tt = getvar_i(av[1]);
2365 else
2366 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002367 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002368 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002369 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2370 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002371 g_buf[i] = '\0';
2372 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002373 break;
2374
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002375 case B_mt:
2376 setvar_i(res, do_mktime(as[0]));
2377 break;
2378
Denis Vlasenkof782f522007-01-01 23:51:30 +00002379 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002380 re = as_regex(an[1], &sreg);
2381 n = regexec(re, as[0], 1, pmatch, 0);
2382 if (n == 0) {
2383 pmatch[0].rm_so++;
2384 pmatch[0].rm_eo++;
2385 } else {
2386 pmatch[0].rm_so = 0;
2387 pmatch[0].rm_eo = -1;
2388 }
2389 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2390 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2391 setvar_i(res, pmatch[0].rm_so);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002392 if (re == &sreg)
2393 regfree(re);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002394 break;
2395
Denis Vlasenkof782f522007-01-01 23:51:30 +00002396 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002397 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2398 break;
2399
Denis Vlasenkof782f522007-01-01 23:51:30 +00002400 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002401 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2402 break;
2403
Denis Vlasenkof782f522007-01-01 23:51:30 +00002404 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002405 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2406 break;
2407 }
2408
2409 nvfree(tv);
2410 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002411#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002412}
2413
2414/*
2415 * Evaluate node - the heart of the program. Supplied with subtree
2416 * and place where to store result. returns ptr to result.
2417 */
2418#define XC(n) ((n) >> 8)
2419
Mike Frysinger10a11e22005-09-27 02:23:02 +00002420static var *evaluate(node *op, var *res)
2421{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002422/* This procedure is recursive so we should count every byte */
2423#define fnargs (G.evaluate__fnargs)
2424/* seed is initialized to 1 */
2425#define seed (G.evaluate__seed)
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002426#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002427
Glenn L McGrath545106f2002-11-11 06:21:00 +00002428 var *v1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002429
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002430 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002431 return setvar_s(res, NULL);
2432
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002433 debug_printf_eval("entered %s()\n", __func__);
2434
Glenn L McGrath545106f2002-11-11 06:21:00 +00002435 v1 = nvalloc(2);
2436
2437 while (op) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002438 struct {
2439 var *v;
2440 const char *s;
2441 } L = L; /* for compiler */
2442 struct {
2443 var *v;
2444 const char *s;
2445 } R = R;
2446 double L_d = L_d;
2447 uint32_t opinfo;
2448 int opn;
2449 node *op1;
2450
Glenn L McGrath545106f2002-11-11 06:21:00 +00002451 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002452 opn = (opinfo & OPNMASK);
2453 g_lineno = op->lineno;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002454 op1 = op->l.n;
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002455 debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002456
Mike Frysingerde2b9382005-09-27 03:18:00 +00002457 /* execute inevitable things */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002458 if (opinfo & OF_RES1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002459 L.v = evaluate(op1, v1);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002460 if (opinfo & OF_RES2)
2461 R.v = evaluate(op->r.n, v1+1);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002462 if (opinfo & OF_STR1) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002463 L.s = getvar_s(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002464 debug_printf_eval("L.s:'%s'\n", L.s);
2465 }
2466 if (opinfo & OF_STR2) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002467 R.s = getvar_s(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002468 debug_printf_eval("R.s:'%s'\n", R.s);
2469 }
2470 if (opinfo & OF_NUM1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002471 L_d = getvar_i(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002472 debug_printf_eval("L_d:%f\n", L_d);
2473 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002474
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002475 debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002476 switch (XC(opinfo & OPCLSMASK)) {
2477
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002478 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002479
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002480 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002481 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002482 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2483 /* it's range pattern */
2484 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2485 op->info |= OF_CHECKED;
2486 if (ptest(op1->r.n))
2487 op->info &= ~OF_CHECKED;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002488 op = op->a.n;
2489 } else {
2490 op = op->r.n;
2491 }
2492 } else {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002493 op = ptest(op1) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002494 }
2495 break;
2496
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002497 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002498 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002499 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002500
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002501 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002502 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002503 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002504 break;
2505
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002506 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002507 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002508 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002509 break;
2510
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002511 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002512 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002513 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2514 break;
2515
Denis Vlasenkof782f522007-01-01 23:51:30 +00002516 case XC( OC_PRINT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002517 case XC( OC_PRINTF ): {
2518 FILE *F = stdout;
2519
Mike Frysingerde2b9382005-09-27 03:18:00 +00002520 if (op->r.n) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002521 rstream *rsm = newfile(R.s);
2522 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002523 if (opn == '|') {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002524 rsm->F = popen(R.s, "w");
2525 if (rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002526 bb_perror_msg_and_die("popen");
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002527 rsm->is_pipe = 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002528 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002529 rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002530 }
2531 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002532 F = rsm->F;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002533 }
2534
2535 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002536 if (!op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002537 fputs(getvar_s(intvar[F0]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002538 } else {
2539 while (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002540 var *v = evaluate(nextarg(&op1), v1);
2541 if (v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002542 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002543 getvar_i(v), TRUE);
2544 fputs(g_buf, F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002545 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002546 fputs(getvar_s(v), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002547 }
2548
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002549 if (op1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002550 fputs(getvar_s(intvar[OFS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002551 }
2552 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002553 fputs(getvar_s(intvar[ORS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002554
2555 } else { /* OC_PRINTF */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002556 char *s = awk_printf(op1);
2557 fputs(s, F);
2558 free(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002559 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002560 fflush(F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002561 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002562 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002563
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002564 case XC( OC_DELETE ): {
2565 uint32_t info = op1->info & OPCLSMASK;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002566 var *v;
2567
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002568 if (info == OC_VAR) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002569 v = op1->l.v;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002570 } else if (info == OC_FNARG) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002571 v = &fnargs[op1->l.aidx];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002572 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002573 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002574 }
2575
Mike Frysingerde2b9382005-09-27 03:18:00 +00002576 if (op1->r.n) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002577 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002578 clrvar(L.v);
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002579 s = getvar_s(evaluate(op1->r.n, v1));
2580 hash_remove(iamarray(v), s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002581 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002582 clear_array(iamarray(v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002583 }
2584 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002585 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002586
Denis Vlasenkof782f522007-01-01 23:51:30 +00002587 case XC( OC_NEWSOURCE ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002588 g_progname = op->l.new_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002589 break;
2590
Denis Vlasenkof782f522007-01-01 23:51:30 +00002591 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002592 copyvar(res, L.v);
2593 break;
2594
Denis Vlasenkof782f522007-01-01 23:51:30 +00002595 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002596 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002597 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002598 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002599 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002600 clrvar(res);
2601 break;
2602
Denis Vlasenkof782f522007-01-01 23:51:30 +00002603 case XC( OC_EXIT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002604 awk_exit(L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002605
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002606 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002607
Denis Vlasenkof782f522007-01-01 23:51:30 +00002608 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002609 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002610 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002611 split_f0();
2612 goto v_cont;
2613
Denis Vlasenkof782f522007-01-01 23:51:30 +00002614 case XC( OC_FNARG ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002615 L.v = &fnargs[op->l.aidx];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002616 v_cont:
2617 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002618 break;
2619
Denis Vlasenkof782f522007-01-01 23:51:30 +00002620 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002621 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2622 break;
2623
Denis Vlasenkof782f522007-01-01 23:51:30 +00002624 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002625 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002626 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002627 goto re_cont;
2628
Denis Vlasenkof782f522007-01-01 23:51:30 +00002629 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002630 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002631 re_cont:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002632 {
2633 regex_t *re = as_regex(op1, &sreg);
2634 int i = regexec(re, L.s, 0, NULL, 0);
2635 if (re == &sreg)
2636 regfree(re);
2637 setvar_i(res, (i == 0) ^ (opn == '!'));
2638 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002639 break;
2640
Denis Vlasenkof782f522007-01-01 23:51:30 +00002641 case XC( OC_MOVE ):
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002642 debug_printf_eval("MOVE\n");
Mike Frysingerde2b9382005-09-27 03:18:00 +00002643 /* if source is a temporary string, jusk relink it to dest */
Denys Vlasenko12847742009-11-30 01:15:04 +01002644//Disabled: if R.v is numeric but happens to have cached R.v->string,
2645//then L.v ends up being a string, which is wrong
2646// if (R.v == v1+1 && R.v->string) {
2647// res = setvar_p(L.v, R.v->string);
2648// R.v->string = NULL;
2649// } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002650 res = copyvar(L.v, R.v);
Denys Vlasenko12847742009-11-30 01:15:04 +01002651// }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002652 break;
2653
Denis Vlasenkof782f522007-01-01 23:51:30 +00002654 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002655 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002656 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002657 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2658 break;
2659
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002660 case XC( OC_FUNC ): {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002661 var *vbeg, *v;
2662 const char *sv_progname;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002663
Bernhard Reutner-Fischerb79a0fe2013-03-06 21:01:05 +01002664 /* The body might be empty, still has to eval the args */
2665 if (!op->r.n->info)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002666 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002667
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002668 vbeg = v = nvalloc(op->r.f->nargs + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002669 while (op1) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002670 var *arg = evaluate(nextarg(&op1), v1);
2671 copyvar(v, arg);
2672 v->type |= VF_CHILD;
2673 v->x.parent = arg;
2674 if (++v - vbeg >= op->r.f->nargs)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002675 break;
2676 }
2677
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002678 v = fnargs;
2679 fnargs = vbeg;
2680 sv_progname = g_progname;
2681
2682 res = evaluate(op->r.f->body.first, res);
2683
2684 g_progname = sv_progname;
2685 nvfree(fnargs);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002686 fnargs = v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002687
Glenn L McGrath545106f2002-11-11 06:21:00 +00002688 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002689 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002690
Denis Vlasenkof782f522007-01-01 23:51:30 +00002691 case XC( OC_GETLINE ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002692 case XC( OC_PGETLINE ): {
2693 rstream *rsm;
2694 int i;
2695
Mike Frysingerde2b9382005-09-27 03:18:00 +00002696 if (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002697 rsm = newfile(L.s);
2698 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002699 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002700 rsm->F = popen(L.s, "r");
2701 rsm->is_pipe = TRUE;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002702 } else {
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002703 rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002704 }
2705 }
2706 } else {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002707 if (!iF)
2708 iF = next_input_file();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002709 rsm = iF;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002710 }
2711
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02002712 if (!rsm || !rsm->F) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002713 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002714 setvar_i(res, -1);
2715 break;
2716 }
2717
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002718 if (!op->r.n)
2719 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002720
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002721 i = awk_getline(rsm, R.v);
2722 if (i > 0 && !op1) {
2723 incvar(intvar[FNR]);
2724 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002725 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002726 setvar_i(res, i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002727 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002728 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002729
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002730 /* simple builtins */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002731 case XC( OC_FBLTIN ): {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002732 double R_d = R_d; /* for compiler */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002733
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002734 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002735 case F_in:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002736 R_d = (int)L_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002737 break;
2738
Denis Vlasenkof782f522007-01-01 23:51:30 +00002739 case F_rn:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002740 R_d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002741 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002742
Denis Vlasenkof782f522007-01-01 23:51:30 +00002743 case F_co:
Rob Landleyd8205b32010-10-24 03:27:22 +02002744 if (ENABLE_FEATURE_AWK_LIBM) {
2745 R_d = cos(L_d);
2746 break;
2747 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002748
Denis Vlasenkof782f522007-01-01 23:51:30 +00002749 case F_ex:
Rob Landleyd8205b32010-10-24 03:27:22 +02002750 if (ENABLE_FEATURE_AWK_LIBM) {
2751 R_d = exp(L_d);
2752 break;
2753 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002754
Denis Vlasenkof782f522007-01-01 23:51:30 +00002755 case F_lg:
Rob Landleyd8205b32010-10-24 03:27:22 +02002756 if (ENABLE_FEATURE_AWK_LIBM) {
2757 R_d = log(L_d);
2758 break;
2759 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002760
Denis Vlasenkof782f522007-01-01 23:51:30 +00002761 case F_si:
Rob Landleyd8205b32010-10-24 03:27:22 +02002762 if (ENABLE_FEATURE_AWK_LIBM) {
2763 R_d = sin(L_d);
2764 break;
2765 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002766
Denis Vlasenkof782f522007-01-01 23:51:30 +00002767 case F_sq:
Rob Landleyd8205b32010-10-24 03:27:22 +02002768 if (ENABLE_FEATURE_AWK_LIBM) {
2769 R_d = sqrt(L_d);
2770 break;
2771 }
2772
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002773 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002774 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002775
Denis Vlasenkof782f522007-01-01 23:51:30 +00002776 case F_sr:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002777 R_d = (double)seed;
2778 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002779 srand(seed);
2780 break;
2781
Denis Vlasenkof782f522007-01-01 23:51:30 +00002782 case F_ti:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002783 R_d = time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002784 break;
2785
Denis Vlasenkof782f522007-01-01 23:51:30 +00002786 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002787 if (!op1)
2788 L.s = getvar_s(intvar[F0]);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002789 R_d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002790 break;
2791
Denis Vlasenkof782f522007-01-01 23:51:30 +00002792 case F_sy:
Denys Vlasenko8131eea2009-11-02 14:19:51 +01002793 fflush_all();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002794 R_d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002795 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002796 break;
2797
Denis Vlasenkof782f522007-01-01 23:51:30 +00002798 case F_ff:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002799 if (!op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002800 fflush(stdout);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002801 } else if (L.s && *L.s) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002802 rstream *rsm = newfile(L.s);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002803 fflush(rsm->F);
2804 } else {
2805 fflush_all();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002806 }
2807 break;
2808
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002809 case F_cl: {
2810 rstream *rsm;
2811 int err = 0;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002812 rsm = (rstream *)hash_search(fdhash, L.s);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002813 debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002814 if (rsm) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002815 debug_printf_eval("OC_FBLTIN F_cl "
2816 "rsm->is_pipe:%d, ->F:%p\n",
2817 rsm->is_pipe, rsm->F);
2818 /* Can be NULL if open failed. Example:
2819 * getline line <"doesnt_exist";
2820 * close("doesnt_exist"); <--- here rsm->F is NULL
2821 */
2822 if (rsm->F)
2823 err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002824 free(rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002825 hash_remove(fdhash, L.s);
2826 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002827 if (err)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002828 setvar_i(intvar[ERRNO], errno);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002829 R_d = (double)err;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002830 break;
2831 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002832 } /* switch */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002833 setvar_i(res, R_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002834 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002835 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002836
Denis Vlasenkof782f522007-01-01 23:51:30 +00002837 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002838 res = exec_builtin(op, res);
2839 break;
2840
Denis Vlasenkof782f522007-01-01 23:51:30 +00002841 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002842 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002843 break;
2844
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002845 case XC( OC_UNARY ): {
2846 double Ld, R_d;
2847
2848 Ld = R_d = getvar_i(R.v);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002849 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002850 case 'P':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002851 Ld = ++R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002852 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002853 case 'p':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002854 R_d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002855 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002856 case 'M':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002857 Ld = --R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002858 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002859 case 'm':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002860 R_d--;
2861 r_op_change:
2862 setvar_i(R.v, R_d);
2863 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002864 case '!':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002865 Ld = !istrue(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002866 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002867 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002868 Ld = -R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002869 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002870 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002871 setvar_i(res, Ld);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002872 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002873 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002874
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002875 case XC( OC_FIELD ): {
2876 int i = (int)getvar_i(R.v);
2877 if (i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002878 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002879 } else {
2880 split_f0();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002881 if (i > nfields)
2882 fsrealloc(i);
2883 res = &Fields[i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002884 }
2885 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002886 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002887
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002888 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002889 case XC( OC_CONCAT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002890 case XC( OC_COMMA ): {
2891 const char *sep = "";
2892 if ((opinfo & OPCLSMASK) == OC_COMMA)
2893 sep = getvar_s(intvar[SUBSEP]);
2894 setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002895 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002896 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002897
Denis Vlasenkof782f522007-01-01 23:51:30 +00002898 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002899 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2900 break;
2901
Denis Vlasenkof782f522007-01-01 23:51:30 +00002902 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002903 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2904 break;
2905
Denis Vlasenkof782f522007-01-01 23:51:30 +00002906 case XC( OC_BINARY ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002907 case XC( OC_REPLACE ): {
2908 double R_d = getvar_i(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002909 debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002910 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002911 case '+':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002912 L_d += R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002913 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002914 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002915 L_d -= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002916 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002917 case '*':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002918 L_d *= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002919 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002920 case '/':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002921 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002922 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002923 L_d /= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002924 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002925 case '&':
Rob Landleyd8205b32010-10-24 03:27:22 +02002926 if (ENABLE_FEATURE_AWK_LIBM)
2927 L_d = pow(L_d, R_d);
2928 else
2929 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002930 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002931 case '%':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002932 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002933 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002934 L_d -= (int)(L_d / R_d) * R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002935 break;
2936 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002937 debug_printf_eval("BINARY/REPLACE result:%f\n", L_d);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002938 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002939 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002940 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002941
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002942 case XC( OC_COMPARE ): {
2943 int i = i; /* for compiler */
2944 double Ld;
2945
Glenn L McGrath545106f2002-11-11 06:21:00 +00002946 if (is_numeric(L.v) && is_numeric(R.v)) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002947 Ld = getvar_i(L.v) - getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002948 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002949 const char *l = getvar_s(L.v);
2950 const char *r = getvar_s(R.v);
2951 Ld = icase ? strcasecmp(l, r) : strcmp(l, r);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002952 }
2953 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002954 case 0:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002955 i = (Ld > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002956 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002957 case 2:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002958 i = (Ld >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002959 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002960 case 4:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002961 i = (Ld == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002962 break;
2963 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002964 setvar_i(res, (i == 0) ^ (opn & 1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002965 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002966 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002967
Denis Vlasenkof782f522007-01-01 23:51:30 +00002968 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002969 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002970 }
2971 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2972 op = op->a.n;
2973 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2974 break;
2975 if (nextrec)
2976 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002977 } /* while (op) */
2978
Glenn L McGrath545106f2002-11-11 06:21:00 +00002979 nvfree(v1);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002980 debug_printf_eval("returning from %s(): %p\n", __func__, res);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002981 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002982#undef fnargs
2983#undef seed
2984#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002985}
2986
2987
2988/* -------- main & co. -------- */
2989
Mike Frysinger10a11e22005-09-27 02:23:02 +00002990static int awk_exit(int r)
2991{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002992 var tv;
2993 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002994 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002995
Denis Vlasenkof782f522007-01-01 23:51:30 +00002996 zero_out_var(&tv);
2997
2998 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002999 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00003000 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003001 evaluate(endseq.first, &tv);
3002 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003003
3004 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003005 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003006 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00003007 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003008 if (hi->data.rs.F && hi->data.rs.is_pipe)
3009 pclose(hi->data.rs.F);
3010 hi = hi->next;
3011 }
3012 }
3013
3014 exit(r);
3015}
3016
3017/* if expr looks like "var=value", perform assignment and return 1,
3018 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00003019static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00003020{
Denys Vlasenkoea664dd2012-06-22 18:41:01 +02003021 char *exprc, *val;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003022
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003023 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003024 return FALSE;
3025 }
3026
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003027 exprc = xstrdup(expr);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003028 val = exprc + (val - expr);
3029 *val++ = '\0';
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003030
Denys Vlasenkoea664dd2012-06-22 18:41:01 +02003031 unescape_string_in_place(val);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003032 setvar_u(newvar(exprc), val);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003033 free(exprc);
3034 return TRUE;
3035}
3036
3037/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00003038static rstream *next_input_file(void)
3039{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003040#define rsm (G.next_input_file__rsm)
3041#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003042
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003043 FILE *F;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00003044 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003045
Denys Vlasenkocdeda162009-11-30 01:14:16 +01003046 if (rsm.F)
3047 fclose(rsm.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003048 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003049 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003050
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003051 for (;;) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003052 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003053 if (files_happen)
3054 return NULL;
3055 fname = "-";
3056 F = stdin;
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003057 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003058 }
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003059 ind = getvar_s(incvar(intvar[ARGIND]));
3060 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
3061 if (fname && *fname && !is_assignment(fname)) {
3062 F = xfopen_stdin(fname);
3063 break;
3064 }
3065 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003066
3067 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003068 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003069 rsm.F = F;
3070 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003071#undef rsm
3072#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00003073}
3074
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00003075int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00003076int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00003077{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00003078 unsigned opt;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02003079 char *opt_F;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003080 llist_t *list_v = NULL;
3081 llist_t *list_f = NULL;
3082 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003083 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003084 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003085 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003086 char *vnames = (char *)vNames; /* cheat */
3087 char *vvalues = (char *)vValues;
3088
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003089 INIT_G();
3090
Denis Vlasenko150f4022007-01-13 21:06:21 +00003091 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00003092 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
3093 if (ENABLE_LOCALE_SUPPORT)
3094 setlocale(LC_NUMERIC, "C");
3095
Denis Vlasenkof782f522007-01-01 23:51:30 +00003096 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003097
3098 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003099 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003100
3101 vhash = hash_init();
3102 ahash = hash_init();
3103 fdhash = hash_init();
3104 fnhash = hash_init();
3105
3106 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003107 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003108 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00003109 if (*vvalues != '\377')
3110 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003111 else
3112 setvar_i(v, 0);
3113
Denis Vlasenkof782f522007-01-01 23:51:30 +00003114 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003115 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003116 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003117 }
3118 }
3119
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003120 handle_special(intvar[FS]);
3121 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003122
Denis Vlasenkof782f522007-01-01 23:51:30 +00003123 newfile("/dev/stdin")->F = stdin;
3124 newfile("/dev/stdout")->F = stdout;
3125 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003126
Denis Vlasenkof71d9162007-05-03 22:57:56 +00003127 /* Huh, people report that sometimes environ is NULL. Oh well. */
3128 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003129 /* environ is writable, thus we don't strdup it needlessly */
3130 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003131 char *s1 = strchr(s, '=');
3132 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003133 *s1 = '\0';
3134 /* Both findvar and setvar_u take const char*
3135 * as 2nd arg -> environment is not trashed */
3136 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
3137 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00003138 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003139 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003140 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
Denys Vlasenko7b46d112011-09-11 00:30:56 +02003141 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003142 argv += optind;
3143 argc -= optind;
Denys Vlasenkoea664dd2012-06-22 18:41:01 +02003144 if (opt & 0x1) { /* -F */
3145 unescape_string_in_place(opt_F);
3146 setvar_s(intvar[FS], opt_F);
3147 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003148 while (list_v) { /* -v */
3149 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00003150 bb_show_usage();
3151 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003152 if (list_f) { /* -f */
3153 do {
3154 char *s = NULL;
3155 FILE *from_file;
3156
3157 g_progname = llist_pop(&list_f);
3158 from_file = xfopen_stdin(g_progname);
3159 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003160 for (i = j = 1; j > 0; i += j) {
3161 s = xrealloc(s, i + 4096);
3162 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00003163 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003164 s[i] = '\0';
3165 fclose(from_file);
3166 parse_program(s + 1);
3167 free(s);
3168 } while (list_f);
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00003169 argc++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003170 } else { // no -f: take program from 1st parameter
3171 if (!argc)
3172 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003173 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00003174 parse_program(*argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003175 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00003176 if (opt & 0x8) // -W
Denys Vlasenko7b46d112011-09-11 00:30:56 +02003177 bb_error_msg("warning: option -W is ignored");
Glenn L McGrath545106f2002-11-11 06:21:00 +00003178
Glenn L McGrath545106f2002-11-11 06:21:00 +00003179 /* fill in ARGV array */
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00003180 setvar_i(intvar[ARGC], argc);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003181 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00003182 i = 0;
3183 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003184 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003185
3186 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003187 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00003188 awk_exit(EXIT_SUCCESS);
3189
3190 /* input file could already be opened in BEGIN block */
Denys Vlasenkocdeda162009-11-30 01:14:16 +01003191 if (!iF)
3192 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003193
3194 /* passing through input files */
3195 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003196 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003197 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003198
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003199 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003200 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003201 incvar(intvar[NR]);
3202 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003203 evaluate(mainseq.first, &tv);
3204
3205 if (nextfile)
3206 break;
3207 }
3208
Denis Vlasenkof782f522007-01-01 23:51:30 +00003209 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003210 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003211
3212 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003213 }
3214
Glenn L McGrath545106f2002-11-11 06:21:00 +00003215 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003216 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00003217}