blob: 71abca215a4bb3b3942f8cad35c8207cc3fee517 [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() */
158#define TC_SEQSTART 1 /* ( */
159#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 Vlasenko2b299fe2010-10-24 01:58:04 +0200699 if (c == '\\' && *s == pps) { /* unrecognized \z? */
700 c = *(*s); /* yes, fetch z */
701 if (c)
702 (*s)++; /* advance unless z = NUL */
703 }
Glenn L McGrath545106f2002-11-11 06:21:00 +0000704 return c;
705}
706
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000707static ALWAYS_INLINE int isalnum_(int c)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000708{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000709 return (isalnum(c) || c == '_');
710}
711
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000712static double my_strtod(char **pp)
713{
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200714 char *cp = *pp;
Rob Landleyd8205b32010-10-24 03:27:22 +0200715 if (ENABLE_DESKTOP && cp[0] == '0') {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200716 /* Might be hex or octal integer: 0x123abc or 07777 */
717 char c = (cp[1] | 0x20);
718 if (c == 'x' || isdigit(cp[1])) {
719 unsigned long long ull = strtoull(cp, pp, 0);
720 if (c == 'x')
721 return ull;
722 c = **pp;
723 if (!isdigit(c) && c != '.')
724 return ull;
725 /* else: it may be a floating number. Examples:
726 * 009.123 (*pp points to '9')
727 * 000.123 (*pp points to '.')
728 * fall through to strtod.
729 */
730 }
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000731 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200732 return strtod(cp, pp);
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000733}
734
Glenn L McGrath545106f2002-11-11 06:21:00 +0000735/* -------- working with variables (set/get/copy/etc) -------- */
736
Mike Frysinger10a11e22005-09-27 02:23:02 +0000737static xhash *iamarray(var *v)
738{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000739 var *a = v;
740
741 while (a->type & VF_CHILD)
742 a = a->x.parent;
743
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000744 if (!(a->type & VF_ARRAY)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000745 a->type |= VF_ARRAY;
746 a->x.array = hash_init();
747 }
748 return a->x.array;
749}
750
Mike Frysinger10a11e22005-09-27 02:23:02 +0000751static void clear_array(xhash *array)
752{
Denis Vlasenkof782f522007-01-01 23:51:30 +0000753 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000754 hash_item *hi, *thi;
755
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000756 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000757 hi = array->items[i];
758 while (hi) {
759 thi = hi;
760 hi = hi->next;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000761 free(thi->data.v.string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000762 free(thi);
763 }
764 array->items[i] = NULL;
765 }
766 array->glen = array->nel = 0;
767}
768
769/* clear a variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000770static var *clrvar(var *v)
771{
Aaron Lehmanna170e1c2002-11-28 11:27:31 +0000772 if (!(v->type & VF_FSTR))
Glenn L McGrath545106f2002-11-11 06:21:00 +0000773 free(v->string);
774
775 v->type &= VF_DONTTOUCH;
776 v->type |= VF_DIRTY;
777 v->string = NULL;
778 return v;
779}
780
781/* assign string value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000782static var *setvar_p(var *v, char *value)
783{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000784 clrvar(v);
785 v->string = value;
786 handle_special(v);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000787 return v;
788}
789
790/* same as setvar_p but make a copy of string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000791static var *setvar_s(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000792{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000793 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000794}
795
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100796/* same as setvar_s but sets USER flag */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000797static var *setvar_u(var *v, const char *value)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000798{
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100799 v = setvar_s(v, value);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000800 v->type |= VF_USER;
801 return v;
802}
803
804/* set array element to user string */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000805static void setari_u(var *a, int idx, const char *s)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000806{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000807 var *v;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000808
Denys Vlasenko7bb346f2009-10-06 22:09:50 +0200809 v = findvar(iamarray(a), itoa(idx));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000810 setvar_u(v, s);
811}
812
813/* assign numeric value to variable */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000814static var *setvar_i(var *v, double value)
815{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000816 clrvar(v);
817 v->type |= VF_NUMBER;
818 v->number = value;
819 handle_special(v);
820 return v;
821}
822
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000823static const char *getvar_s(var *v)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000824{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000825 /* if v is numeric and has no cached string, convert it to string */
826 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000827 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
828 v->string = xstrdup(g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000829 v->type |= VF_CACHED;
830 }
831 return (v->string == NULL) ? "" : v->string;
832}
833
Mike Frysinger10a11e22005-09-27 02:23:02 +0000834static double getvar_i(var *v)
835{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000836 char *s;
837
838 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
839 v->number = 0;
840 s = v->string;
841 if (s && *s) {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200842 debug_printf_eval("getvar_i: '%s'->", s);
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000843 v->number = my_strtod(&s);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200844 debug_printf_eval("%f (s:'%s')\n", v->number, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000845 if (v->type & VF_USER) {
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +0100846 s = skip_spaces(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000847 if (*s != '\0')
848 v->type &= ~VF_USER;
849 }
850 } else {
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200851 debug_printf_eval("getvar_i: '%s'->zero\n", s);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000852 v->type &= ~VF_USER;
853 }
854 v->type |= VF_CACHED;
855 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200856 debug_printf_eval("getvar_i: %f\n", v->number);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000857 return v->number;
858}
859
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000860/* Used for operands of bitwise ops */
861static unsigned long getvar_i_int(var *v)
862{
863 double d = getvar_i(v);
864
865 /* Casting doubles to longs is undefined for values outside
866 * of target type range. Try to widen it as much as possible */
867 if (d >= 0)
868 return (unsigned long)d;
Denis Vlasenko665eaff2008-09-05 04:59:02 +0000869 /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +0000870 return - (long) (unsigned long) (-d);
871}
872
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +0000873static var *copyvar(var *dest, const var *src)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000874{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000875 if (dest != src) {
876 clrvar(dest);
Denis Vlasenko629563b2007-02-24 17:05:52 +0000877 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
Denys Vlasenkod527e0c2010-10-05 13:22:11 +0200878 debug_printf_eval("copyvar: number:%f string:'%s'\n", src->number, src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000879 dest->number = src->number;
880 if (src->string)
Rob Landleyd921b2e2006-08-03 15:41:12 +0000881 dest->string = xstrdup(src->string);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000882 }
883 handle_special(dest);
884 return dest;
885}
886
Mike Frysinger10a11e22005-09-27 02:23:02 +0000887static var *incvar(var *v)
888{
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100889 return setvar_i(v, getvar_i(v) + 1.0);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000890}
891
892/* return true if v is number or numeric string */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000893static int is_numeric(var *v)
894{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000895 getvar_i(v);
896 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
897}
898
899/* return 1 when value of v corresponds to true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000900static int istrue(var *v)
901{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000902 if (is_numeric(v))
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100903 return (v->number != 0);
904 return (v->string && v->string[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000905}
906
Eric Andersenaff114c2004-04-14 17:51:38 +0000907/* temporary variables allocator. Last allocated should be first freed */
Mike Frysinger10a11e22005-09-27 02:23:02 +0000908static var *nvalloc(int n)
909{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000910 nvblock *pb = NULL;
911 var *v, *r;
912 int size;
913
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000914 while (g_cb) {
915 pb = g_cb;
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100916 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size)
917 break;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000918 g_cb = g_cb->next;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000919 }
920
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000921 if (!g_cb) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000922 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000923 g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000924 g_cb->size = size;
925 g_cb->pos = g_cb->nv;
926 g_cb->prev = pb;
Denis Vlasenkoe0a7fc52008-07-02 11:14:59 +0000927 /*g_cb->next = NULL; - xzalloc did it */
Denys Vlasenkocdeda162009-11-30 01:14:16 +0100928 if (pb)
929 pb->next = g_cb;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000930 }
931
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000932 v = r = g_cb->pos;
933 g_cb->pos += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000934
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000935 while (v < g_cb->pos) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000936 v->type = 0;
937 v->string = NULL;
938 v++;
939 }
940
941 return r;
942}
943
Mike Frysinger10a11e22005-09-27 02:23:02 +0000944static void nvfree(var *v)
945{
Glenn L McGrath545106f2002-11-11 06:21:00 +0000946 var *p;
947
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000948 if (v < g_cb->nv || v >= g_cb->pos)
949 syntax_error(EMSG_INTERNAL_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000950
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000951 for (p = v; p < g_cb->pos; p++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +0000952 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
Glenn L McGrath545106f2002-11-11 06:21:00 +0000953 clear_array(iamarray(p));
954 free(p->x.array->items);
955 free(p->x.array);
956 }
Denys Vlasenko3cb60c32010-03-10 19:20:32 +0100957 if (p->type & VF_WALK) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +0100958 walker_list *n;
959 walker_list *w = p->x.walker;
960 debug_printf_walker("nvfree: freeing walker @%p\n", &p->x.walker);
961 p->x.walker = NULL;
962 while (w) {
963 n = w->prev;
964 debug_printf_walker(" free(%p)\n", w);
965 free(w);
966 w = n;
967 }
Denys Vlasenko3cb60c32010-03-10 19:20:32 +0100968 }
Glenn L McGrath545106f2002-11-11 06:21:00 +0000969 clrvar(p);
970 }
971
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000972 g_cb->pos = v;
973 while (g_cb->prev && g_cb->pos == g_cb->nv) {
974 g_cb = g_cb->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000975 }
976}
977
978/* ------- awk program text parsing ------- */
979
Denis Vlasenkocd5c7862007-05-17 16:37:22 +0000980/* Parse next token pointed by global pos, place results into global ttt.
Glenn L McGrath545106f2002-11-11 06:21:00 +0000981 * If token isn't expected, give away. Return token class
982 */
Mike Frysingerf87b3e32005-09-27 04:16:22 +0000983static uint32_t next_token(uint32_t expected)
Mike Frysinger10a11e22005-09-27 02:23:02 +0000984{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000985#define concat_inserted (G.next_token__concat_inserted)
986#define save_tclass (G.next_token__save_tclass)
987#define save_info (G.next_token__save_info)
988/* Initialized to TC_OPTERM: */
989#define ltclass (G.next_token__ltclass)
Glenn L McGrath545106f2002-11-11 06:21:00 +0000990
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +0100991 char *p, *s;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000992 const char *tl;
993 uint32_t tc;
994 const uint32_t *ti;
Denis Vlasenkof782f522007-01-01 23:51:30 +0000995
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +0000996 if (t_rollback) {
997 t_rollback = FALSE;
Glenn L McGrath545106f2002-11-11 06:21:00 +0000998
999 } else if (concat_inserted) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001000 concat_inserted = FALSE;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001001 t_tclass = save_tclass;
1002 t_info = save_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001003
1004 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001005 p = g_pos;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001006 readnext:
Denys Vlasenkob0a57ab2010-03-11 12:44:25 +01001007 p = skip_spaces(p);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001008 g_lineno = t_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001009 if (*p == '#')
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001010 while (*p != '\n' && *p != '\0')
1011 p++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001012
1013 if (*p == '\n')
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001014 t_lineno++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001015
1016 if (*p == '\0') {
1017 tc = TC_EOF;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001018 debug_printf_parse("%s: token found: TC_EOF\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001019
1020 } else if (*p == '\"') {
1021 /* it's a string */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001022 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001023 while (*p != '\"') {
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02001024 char *pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001025 if (*p == '\0' || *p == '\n')
1026 syntax_error(EMSG_UNEXP_EOS);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02001027 pp = p;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001028 *s++ = nextchar(&pp);
1029 p = pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001030 }
1031 p++;
1032 *s = '\0';
1033 tc = TC_STRING;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001034 debug_printf_parse("%s: token found:'%s' TC_STRING\n", __func__, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001035
1036 } else if ((expected & TC_REGEXP) && *p == '/') {
1037 /* it's regexp */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001038 t_string = s = ++p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001039 while (*p != '/') {
1040 if (*p == '\0' || *p == '\n')
1041 syntax_error(EMSG_UNEXP_EOS);
Denis Vlasenkod9b5ab82007-05-18 07:30:43 +00001042 *s = *p++;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001043 if (*s++ == '\\') {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001044 char *pp = p;
1045 s[-1] = bb_process_escape_sequence((const char **)&pp);
1046 if (*p == '\\')
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001047 *s++ = '\\';
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001048 if (pp == p)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001049 *s++ = *p++;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001050 else
1051 p = pp;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001052 }
1053 }
1054 p++;
1055 *s = '\0';
1056 tc = TC_REGEXP;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001057 debug_printf_parse("%s: token found:'%s' TC_REGEXP\n", __func__, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001058
1059 } else if (*p == '.' || isdigit(*p)) {
1060 /* it's a number */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001061 char *pp = p;
1062 t_double = my_strtod(&pp);
1063 p = pp;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001064 if (*p == '.')
Glenn L McGrath545106f2002-11-11 06:21:00 +00001065 syntax_error(EMSG_UNEXP_TOKEN);
1066 tc = TC_NUMBER;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001067 debug_printf_parse("%s: token found:%f TC_NUMBER\n", __func__, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001068
1069 } else {
1070 /* search for something known */
1071 tl = tokenlist;
1072 tc = 0x00000001;
1073 ti = tokeninfo;
1074 while (*tl) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001075 int l = (unsigned char) *tl++;
1076 if (l == (unsigned char) NTCC) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001077 tc <<= 1;
1078 continue;
1079 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001080 /* if token class is expected,
1081 * token matches,
1082 * and it's not a longer word,
Glenn L McGrath545106f2002-11-11 06:21:00 +00001083 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001084 if ((tc & (expected | TC_WORD | TC_NEWLINE))
Denys Vlasenko28458c62010-10-05 16:49:03 +02001085 && strncmp(p, tl, l) == 0
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001086 && !((tc & TC_WORD) && isalnum_(p[l]))
1087 ) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001088 /* then this is what we are looking for */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001089 t_info = *ti;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001090 debug_printf_parse("%s: token found:'%.*s' t_info:%x\n", __func__, l, p, t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001091 p += l;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001092 goto token_found;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001093 }
1094 ti++;
1095 tl += l;
1096 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001097 /* not a known token */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001098
Denys Vlasenko28458c62010-10-05 16:49:03 +02001099 /* is it a name? (var/array/function) */
1100 if (!isalnum_(*p))
1101 syntax_error(EMSG_UNEXP_TOKEN); /* no */
1102 /* yes */
1103 t_string = --p;
1104 while (isalnum_(*++p)) {
1105 p[-1] = *p;
1106 }
1107 p[-1] = '\0';
1108 tc = TC_VARIABLE;
1109 /* also consume whitespace between functionname and bracket */
1110 if (!(expected & TC_VARIABLE) || (expected & TC_ARRAY))
1111 p = skip_spaces(p);
1112 if (*p == '(') {
1113 tc = TC_FUNCTION;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001114 debug_printf_parse("%s: token found:'%s' TC_FUNCTION\n", __func__, t_string);
Denys Vlasenko28458c62010-10-05 16:49:03 +02001115 } else {
1116 if (*p == '[') {
1117 p++;
1118 tc = TC_ARRAY;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001119 debug_printf_parse("%s: token found:'%s' TC_ARRAY\n", __func__, t_string);
1120 } else
1121 debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001122 }
1123 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001124 token_found:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001125 g_pos = p;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001126
1127 /* skipping newlines in some cases */
1128 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
1129 goto readnext;
1130
1131 /* insert concatenation operator when needed */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001132 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001133 concat_inserted = TRUE;
1134 save_tclass = tc;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001135 save_info = t_info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001136 tc = TC_BINOP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001137 t_info = OC_CONCAT | SS | P(35);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001138 }
1139
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001140 t_tclass = tc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001141 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001142 ltclass = t_tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001143
1144 /* Are we ready for this? */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001145 if (!(ltclass & expected))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001146 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001147 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001148
1149 return ltclass;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001150#undef concat_inserted
1151#undef save_tclass
1152#undef save_info
1153#undef ltclass
Glenn L McGrath545106f2002-11-11 06:21:00 +00001154}
1155
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001156static void rollback_token(void)
1157{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001158 t_rollback = TRUE;
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001159}
Glenn L McGrath545106f2002-11-11 06:21:00 +00001160
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001161static node *new_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001162{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001163 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001164
Denis Vlasenko4cccc032006-12-22 18:37:07 +00001165 n = xzalloc(sizeof(node));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001166 n->info = info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001167 n->lineno = g_lineno;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001168 return n;
1169}
1170
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001171static void mk_re_node(const char *s, node *n, regex_t *re)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001172{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001173 n->info = OC_REGEXP;
1174 n->l.re = re;
1175 n->r.ire = re + 1;
1176 xregcomp(re, s, REG_EXTENDED);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001177 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001178}
1179
Mike Frysinger10a11e22005-09-27 02:23:02 +00001180static node *condition(void)
1181{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001182 next_token(TC_SEQSTART);
1183 return parse_expr(TC_SEQTERM);
1184}
1185
1186/* parse expression terminated by given argument, return ptr
1187 * to built subtree. Terminator is eaten by parse_expr */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001188static node *parse_expr(uint32_t iexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001189{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001190 node sn;
1191 node *cn = &sn;
1192 node *vn, *glptr;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001193 uint32_t tc, xtc;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001194 var *v;
1195
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001196 debug_printf_parse("%s(%x)\n", __func__, iexp);
1197
Glenn L McGrath545106f2002-11-11 06:21:00 +00001198 sn.info = PRIMASK;
1199 sn.r.n = glptr = NULL;
1200 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1201
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001202 while (!((tc = next_token(xtc)) & iexp)) {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001203
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001204 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001205 /* input redirection (<) attached to glptr node */
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001206 debug_printf_parse("%s: input redir\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001207 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
Glenn L McGrath4bded582004-02-22 11:55:09 +00001208 cn->a.n = glptr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001209 xtc = TC_OPERAND | TC_UOPPRE;
1210 glptr = NULL;
1211
1212 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001213 debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001214 /* for binary and postfix-unary operators, jump back over
1215 * previous operators with higher priority */
1216 vn = cn;
Denys Vlasenkocdeda162009-11-30 01:14:16 +01001217 while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
1218 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON))
1219 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001220 vn = vn->a.n;
Denys Vlasenkocdeda162009-11-30 01:14:16 +01001221 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001222 if ((t_info & OPCLSMASK) == OC_TERNARY)
1223 t_info += P(6);
1224 cn = vn->a.n->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001225 cn->a.n = vn->a.n;
1226 if (tc & TC_BINOP) {
1227 cn->l.n = vn;
1228 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001229 if ((t_info & OPCLSMASK) == OC_PGETLINE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001230 /* it's a pipe */
1231 next_token(TC_GETLINE);
1232 /* give maximum priority to this pipe */
1233 cn->info &= ~PRIMASK;
1234 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1235 }
1236 } else {
1237 cn->r.n = vn;
1238 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1239 }
1240 vn->a.n = cn;
1241
1242 } else {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001243 debug_printf_parse("%s: other\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001244 /* for operands and prefix-unary operators, attach them
1245 * to last node */
1246 vn = cn;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001247 cn = vn->r.n = new_node(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001248 cn->a.n = vn;
1249 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1250 if (tc & (TC_OPERAND | TC_REGEXP)) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001251 debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__);
Rob Landleyed830e82005-06-07 02:43:52 +00001252 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00001253 /* one should be very careful with switch on tclass -
Glenn L McGrath545106f2002-11-11 06:21:00 +00001254 * only simple tclasses should be used! */
1255 switch (tc) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001256 case TC_VARIABLE:
1257 case TC_ARRAY:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001258 debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001259 cn->info = OC_VAR;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001260 v = hash_search(ahash, t_string);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001261 if (v != NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001262 cn->info = OC_FNARG;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001263 cn->l.aidx = v->x.aidx;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001264 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001265 cn->l.v = newvar(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001266 }
1267 if (tc & TC_ARRAY) {
1268 cn->info |= xS;
1269 cn->r.n = parse_expr(TC_ARRTERM);
1270 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001271 break;
Mike Frysingerde2b9382005-09-27 03:18:00 +00001272
Denis Vlasenkof782f522007-01-01 23:51:30 +00001273 case TC_NUMBER:
1274 case TC_STRING:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001275 debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001276 cn->info = OC_VAR;
Rob Landley9ffd4232006-05-21 18:30:35 +00001277 v = cn->l.v = xzalloc(sizeof(var));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001278 if (tc & TC_NUMBER)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001279 setvar_i(v, t_double);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001280 else
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001281 setvar_s(v, t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001282 break;
1283
Denis Vlasenkof782f522007-01-01 23:51:30 +00001284 case TC_REGEXP:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001285 debug_printf_parse("%s: TC_REGEXP\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001286 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001287 break;
1288
Denis Vlasenkof782f522007-01-01 23:51:30 +00001289 case TC_FUNCTION:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001290 debug_printf_parse("%s: TC_FUNCTION\n", __func__);
Mike Frysingerde2b9382005-09-27 03:18:00 +00001291 cn->info = OC_FUNC;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001292 cn->r.f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001293 cn->l.n = condition();
1294 break;
1295
Denis Vlasenkof782f522007-01-01 23:51:30 +00001296 case TC_SEQSTART:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001297 debug_printf_parse("%s: TC_SEQSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001298 cn = vn->r.n = parse_expr(TC_SEQTERM);
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001299 if (!cn)
1300 syntax_error("Empty sequence");
Glenn L McGrath545106f2002-11-11 06:21:00 +00001301 cn->a.n = vn;
1302 break;
1303
Denis Vlasenkof782f522007-01-01 23:51:30 +00001304 case TC_GETLINE:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001305 debug_printf_parse("%s: TC_GETLINE\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001306 glptr = cn;
1307 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1308 break;
1309
Denis Vlasenkof782f522007-01-01 23:51:30 +00001310 case TC_BUILTIN:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001311 debug_printf_parse("%s: TC_BUILTIN\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001312 cn->l.n = condition();
1313 break;
1314 }
1315 }
1316 }
1317 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001318
1319 debug_printf_parse("%s() returns %p\n", __func__, sn.r.n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001320 return sn.r.n;
1321}
1322
1323/* add node to chain. Return ptr to alloc'd node */
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001324static node *chain_node(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001325{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001326 node *n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001327
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00001328 if (!seq->first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001329 seq->first = seq->last = new_node(0);
1330
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001331 if (seq->programname != g_progname) {
1332 seq->programname = g_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001333 n = chain_node(OC_NEWSOURCE);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001334 n->l.new_progname = xstrdup(g_progname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001335 }
1336
1337 n = seq->last;
1338 n->info = info;
1339 seq->last = n->a.n = new_node(OC_DONE);
1340
1341 return n;
1342}
1343
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001344static void chain_expr(uint32_t info)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001345{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001346 node *n;
1347
1348 n = chain_node(info);
1349 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001350 if (t_tclass & TC_GRPTERM)
Glenn L McGrath545106f2002-11-11 06:21:00 +00001351 rollback_token();
1352}
1353
Mike Frysinger10a11e22005-09-27 02:23:02 +00001354static node *chain_loop(node *nn)
1355{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001356 node *n, *n2, *save_brk, *save_cont;
1357
1358 save_brk = break_ptr;
1359 save_cont = continue_ptr;
1360
1361 n = chain_node(OC_BR | Vx);
1362 continue_ptr = new_node(OC_EXEC);
1363 break_ptr = new_node(OC_EXEC);
1364 chain_group();
1365 n2 = chain_node(OC_EXEC | Vx);
1366 n2->l.n = nn;
1367 n2->a.n = n;
1368 continue_ptr->a.n = n2;
1369 break_ptr->a.n = n->r.n = seq->last;
1370
1371 continue_ptr = save_cont;
1372 break_ptr = save_brk;
1373
1374 return n;
1375}
1376
1377/* parse group and attach it to chain */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001378static void chain_group(void)
1379{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001380 uint32_t c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001381 node *n, *n2, *n3;
1382
1383 do {
1384 c = next_token(TC_GRPSEQ);
1385 } while (c & TC_NEWLINE);
1386
1387 if (c & TC_GRPSTART) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001388 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001389 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001390 debug_printf_parse("%s: !TC_GRPTERM\n", __func__);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001391 if (t_tclass & TC_NEWLINE)
1392 continue;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001393 rollback_token();
1394 chain_group();
1395 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001396 debug_printf_parse("%s: TC_GRPTERM\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001397 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001398 debug_printf_parse("%s: TC_OPSEQ | TC_OPTERM\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001399 rollback_token();
1400 chain_expr(OC_EXEC | Vx);
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001401 } else {
1402 /* TC_STATEMNT */
1403 debug_printf_parse("%s: TC_STATEMNT(?)\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001404 switch (t_info & OPCLSMASK) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001405 case ST_IF:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001406 debug_printf_parse("%s: ST_IF\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001407 n = chain_node(OC_BR | Vx);
1408 n->l.n = condition();
1409 chain_group();
1410 n2 = chain_node(OC_EXEC);
1411 n->r.n = seq->last;
1412 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001413 chain_group();
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001414 n2->a.n = seq->last;
1415 } else {
1416 rollback_token();
1417 }
1418 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001419
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001420 case ST_WHILE:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001421 debug_printf_parse("%s: ST_WHILE\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001422 n2 = condition();
1423 n = chain_loop(NULL);
1424 n->l.n = n2;
1425 break;
1426
1427 case ST_DO:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001428 debug_printf_parse("%s: ST_DO\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001429 n2 = chain_node(OC_EXEC);
1430 n = chain_loop(NULL);
1431 n2->a.n = n->a.n;
1432 next_token(TC_WHILE);
1433 n->l.n = condition();
1434 break;
1435
1436 case ST_FOR:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001437 debug_printf_parse("%s: ST_FOR\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001438 next_token(TC_SEQSTART);
1439 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001440 if (t_tclass & TC_SEQTERM) { /* for-in */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001441 if ((n2->info & OPCLSMASK) != OC_IN)
1442 syntax_error(EMSG_UNEXP_TOKEN);
1443 n = chain_node(OC_WALKINIT | VV);
1444 n->l.n = n2->l.n;
1445 n->r.n = n2->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001446 n = chain_loop(NULL);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001447 n->info = OC_WALKNEXT | Vx;
1448 n->l.n = n2->l.n;
1449 } else { /* for (;;) */
1450 n = chain_node(OC_EXEC | Vx);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001451 n->l.n = n2;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001452 n2 = parse_expr(TC_SEMICOL);
1453 n3 = parse_expr(TC_SEQTERM);
1454 n = chain_loop(n3);
1455 n->l.n = n2;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001456 if (!n2)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001457 n->info = OC_EXEC;
1458 }
1459 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001460
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001461 case OC_PRINT:
1462 case OC_PRINTF:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001463 debug_printf_parse("%s: OC_PRINT[F]\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001464 n = chain_node(t_info);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001465 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001466 if (t_tclass & TC_OUTRDR) {
1467 n->info |= t_info;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001468 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
1469 }
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001470 if (t_tclass & TC_GRPTERM)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001471 rollback_token();
1472 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001473
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001474 case OC_BREAK:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001475 debug_printf_parse("%s: OC_BREAK\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001476 n = chain_node(OC_EXEC);
1477 n->a.n = break_ptr;
1478 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001479
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001480 case OC_CONTINUE:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001481 debug_printf_parse("%s: OC_CONTINUE\n", __func__);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001482 n = chain_node(OC_EXEC);
1483 n->a.n = continue_ptr;
1484 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001485
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001486 /* delete, next, nextfile, return, exit */
1487 default:
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001488 debug_printf_parse("%s: default\n", __func__);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001489 chain_expr(t_info);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001490 }
1491 }
1492}
1493
Mike Frysinger10a11e22005-09-27 02:23:02 +00001494static void parse_program(char *p)
1495{
Mike Frysingerf87b3e32005-09-27 04:16:22 +00001496 uint32_t tclass;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001497 node *cn;
1498 func *f;
1499 var *v;
1500
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001501 g_pos = p;
1502 t_lineno = 1;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001503 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001504 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001505
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001506 if (tclass & TC_OPTERM) {
1507 debug_printf_parse("%s: TC_OPTERM\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001508 continue;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001509 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001510
1511 seq = &mainseq;
1512 if (tclass & TC_BEGIN) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001513 debug_printf_parse("%s: TC_BEGIN\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001514 seq = &beginseq;
1515 chain_group();
1516
1517 } else if (tclass & TC_END) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001518 debug_printf_parse("%s: TC_END\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001519 seq = &endseq;
1520 chain_group();
1521
1522 } else if (tclass & TC_FUNCDECL) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001523 debug_printf_parse("%s: TC_FUNCDECL\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001524 next_token(TC_FUNCTION);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001525 g_pos++;
1526 f = newfunc(t_string);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001527 f->body.first = NULL;
1528 f->nargs = 0;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001529 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001530 v = findvar(ahash, t_string);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001531 v->x.aidx = f->nargs++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001532
1533 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
1534 break;
1535 }
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001536 seq = &f->body;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001537 chain_group();
1538 clear_array(ahash);
1539
1540 } else if (tclass & TC_OPSEQ) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001541 debug_printf_parse("%s: TC_OPSEQ\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001542 rollback_token();
1543 cn = chain_node(OC_TEST);
1544 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001545 if (t_tclass & TC_GRPSTART) {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001546 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001547 rollback_token();
1548 chain_group();
1549 } else {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001550 debug_printf_parse("%s: !TC_GRPSTART\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001551 chain_node(OC_PRINT);
1552 }
1553 cn->r.n = mainseq.last;
1554
1555 } else /* if (tclass & TC_GRPSTART) */ {
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001556 debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001557 rollback_token();
1558 chain_group();
1559 }
1560 }
Denys Vlasenko7b46d112011-09-11 00:30:56 +02001561 debug_printf_parse("%s: TC_EOF\n", __func__);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001562}
1563
1564
1565/* -------- program execution part -------- */
1566
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001567static node *mk_splitter(const char *s, tsplitter *spl)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001568{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001569 regex_t *re, *ire;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001570 node *n;
1571
1572 re = &spl->re[0];
1573 ire = &spl->re[1];
1574 n = &spl->n;
Denis Vlasenko890ac9d2006-10-07 15:16:19 +00001575 if ((n->info & OPCLSMASK) == OC_REGEXP) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001576 regfree(re);
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001577 regfree(ire); // TODO: nuke ire, use re+1?
Glenn L McGrath545106f2002-11-11 06:21:00 +00001578 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001579 if (s[0] && s[1]) { /* strlen(s) > 1 */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001580 mk_re_node(s, n, re);
1581 } else {
Denys Vlasenko28458c62010-10-05 16:49:03 +02001582 n->info = (uint32_t) s[0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00001583 }
1584
1585 return n;
1586}
1587
1588/* use node as a regular expression. Supplied with node ptr and regex_t
Eric Andersenaff114c2004-04-14 17:51:38 +00001589 * storage space. Return ptr to regex (if result points to preg, it should
Glenn L McGrath545106f2002-11-11 06:21:00 +00001590 * be later regfree'd manually
1591 */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001592static regex_t *as_regex(node *op, regex_t *preg)
1593{
Denis Vlasenko7a676642009-03-15 22:20:31 +00001594 int cflags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001595 var *v;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001596 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001597
1598 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1599 return icase ? op->r.ire : op->l.re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001600 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001601 v = nvalloc(1);
1602 s = getvar_s(evaluate(op, v));
Denis Vlasenko7a676642009-03-15 22:20:31 +00001603
1604 cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED;
1605 /* Testcase where REG_EXTENDED fails (unpaired '{'):
1606 * echo Hi | awk 'gsub("@(samp|code|file)\{","");'
1607 * gawk 3.1.5 eats this. We revert to ~REG_EXTENDED
1608 * (maybe gsub is not supposed to use REG_EXTENDED?).
1609 */
1610 if (regcomp(preg, s, cflags)) {
1611 cflags &= ~REG_EXTENDED;
1612 xregcomp(preg, s, cflags);
1613 }
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001614 nvfree(v);
1615 return preg;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001616}
1617
Denys Vlasenkofab288c2010-04-04 01:17:30 +02001618/* gradually increasing buffer.
1619 * note that we reallocate even if n == old_size,
1620 * and thus there is at least one extra allocated byte.
1621 */
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001622static char* qrealloc(char *b, int n, int *size)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001623{
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001624 if (!b || n >= *size) {
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001625 *size = n + (n>>1) + 80;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001626 b = xrealloc(b, *size);
Denis Vlasenkodeeed592008-07-08 05:14:36 +00001627 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001628 return b;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001629}
1630
1631/* resize field storage space */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001632static void fsrealloc(int size)
1633{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001634 int i;
1635
1636 if (size >= maxfields) {
1637 i = maxfields;
1638 maxfields = size + 16;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001639 Fields = xrealloc(Fields, maxfields * sizeof(Fields[0]));
Denis Vlasenkof782f522007-01-01 23:51:30 +00001640 for (; i < maxfields; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001641 Fields[i].type = VF_SPECIAL;
1642 Fields[i].string = NULL;
1643 }
1644 }
Denys Vlasenko28458c62010-10-05 16:49:03 +02001645 /* if size < nfields, clear extra field variables */
1646 for (i = size; i < nfields; i++) {
1647 clrvar(Fields + i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001648 }
1649 nfields = size;
1650}
1651
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001652static int awk_split(const char *s, node *spl, char **slist)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001653{
Denys Vlasenko28458c62010-10-05 16:49:03 +02001654 int l, n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001655 char c[4];
1656 char *s1;
Denis Vlasenkob78c7822007-07-18 18:31:11 +00001657 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
Glenn L McGrath545106f2002-11-11 06:21:00 +00001658
1659 /* in worst case, each char would be a separate field */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001660 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
1661 strcpy(s1, s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001662
1663 c[0] = c[1] = (char)spl->info;
1664 c[2] = c[3] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001665 if (*getvar_s(intvar[RS]) == '\0')
1666 c[2] = '\n';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001667
Denys Vlasenko28458c62010-10-05 16:49:03 +02001668 n = 0;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001669 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1670 if (!*s)
1671 return n; /* "": zero fields */
1672 n++; /* at least one field will be there */
1673 do {
1674 l = strcspn(s, c+2); /* len till next NUL or \n */
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001675 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
1676 && pmatch[0].rm_so <= l
1677 ) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001678 l = pmatch[0].rm_so;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001679 if (pmatch[0].rm_eo == 0) {
1680 l++;
1681 pmatch[0].rm_eo++;
1682 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001683 n++; /* we saw yet another delimiter */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001684 } else {
1685 pmatch[0].rm_eo = l;
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001686 if (s[l])
1687 pmatch[0].rm_eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001688 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00001689 memcpy(s1, s, l);
Denis Vlasenko67b5eeb2009-04-12 13:54:13 +00001690 /* make sure we remove *all* of the separator chars */
Denys Vlasenkoe4244232009-05-18 23:50:03 +02001691 do {
1692 s1[l] = '\0';
1693 } while (++l < pmatch[0].rm_eo);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001694 nextword(&s1);
1695 s += pmatch[0].rm_eo;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001696 } while (*s);
1697 return n;
1698 }
1699 if (c[0] == '\0') { /* null split */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001700 while (*s) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001701 *s1++ = *s++;
1702 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001703 n++;
1704 }
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001705 return n;
1706 }
1707 if (c[0] != ' ') { /* single-character split */
Glenn L McGrath545106f2002-11-11 06:21:00 +00001708 if (icase) {
1709 c[0] = toupper(c[0]);
1710 c[1] = tolower(c[1]);
1711 }
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001712 if (*s1)
1713 n++;
Denys Vlasenko28458c62010-10-05 16:49:03 +02001714 while ((s1 = strpbrk(s1, c)) != NULL) {
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001715 *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 /* space split */
1721 while (*s) {
1722 s = skip_whitespace(s);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001723 if (!*s)
1724 break;
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001725 n++;
1726 while (*s && !isspace(*s))
1727 *s1++ = *s++;
1728 *s1++ = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00001729 }
1730 return n;
1731}
1732
Mike Frysinger10a11e22005-09-27 02:23:02 +00001733static void split_f0(void)
1734{
Denis Vlasenkoaf1bd092007-07-18 18:32:25 +00001735/* static char *fstrings; */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001736#define fstrings (G.split_f0__fstrings)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001737
Glenn L McGrath545106f2002-11-11 06:21:00 +00001738 int i, n;
1739 char *s;
1740
1741 if (is_f0_split)
1742 return;
1743
1744 is_f0_split = TRUE;
Aaron Lehmanna170e1c2002-11-28 11:27:31 +00001745 free(fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001746 fsrealloc(0);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001747 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001748 fsrealloc(n);
1749 s = fstrings;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001750 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001751 Fields[i].string = nextword(&s);
1752 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
1753 }
1754
1755 /* set NF manually to avoid side effects */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001756 clrvar(intvar[NF]);
1757 intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
1758 intvar[NF]->number = nfields;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001759#undef fstrings
Glenn L McGrath545106f2002-11-11 06:21:00 +00001760}
1761
1762/* perform additional actions when some internal variables changed */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001763static void handle_special(var *v)
1764{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001765 int n;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00001766 char *b;
1767 const char *sep, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001768 int sl, l, len, i, bsize;
1769
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001770 if (!(v->type & VF_SPECIAL))
Glenn L McGrath545106f2002-11-11 06:21:00 +00001771 return;
1772
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001773 if (v == intvar[NF]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001774 n = (int)getvar_i(v);
1775 fsrealloc(n);
1776
1777 /* recalculate $0 */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001778 sep = getvar_s(intvar[OFS]);
Rob Landleya3896512006-05-07 20:20:34 +00001779 sl = strlen(sep);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001780 b = NULL;
1781 len = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001782 for (i = 0; i < n; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001783 s = getvar_s(&Fields[i]);
Rob Landleya3896512006-05-07 20:20:34 +00001784 l = strlen(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001785 if (b) {
1786 memcpy(b+len, sep, sl);
1787 len += sl;
1788 }
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001789 b = qrealloc(b, len+l+sl, &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001790 memcpy(b+len, s, l);
1791 len += l;
1792 }
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001793 if (b)
1794 b[len] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001795 setvar_p(intvar[F0], b);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001796 is_f0_split = TRUE;
1797
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001798 } else if (v == intvar[F0]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001799 is_f0_split = FALSE;
1800
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001801 } else if (v == intvar[FS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001802 mk_splitter(getvar_s(v), &fsplitter);
1803
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001804 } else if (v == intvar[RS]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001805 mk_splitter(getvar_s(v), &rsplitter);
1806
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001807 } else if (v == intvar[IGNORECASE]) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001808 icase = istrue(v);
1809
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00001810 } else { /* $n */
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001811 n = getvar_i(intvar[NF]);
1812 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001813 /* right here v is invalid. Just to note... */
1814 }
1815}
1816
1817/* step through func/builtin/etc arguments */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001818static node *nextarg(node **pn)
1819{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001820 node *n;
1821
1822 n = *pn;
1823 if (n && (n->info & OPCLSMASK) == OC_COMMA) {
1824 *pn = n->r.n;
1825 n = n->l.n;
1826 } else {
1827 *pn = NULL;
1828 }
1829 return n;
1830}
1831
Mike Frysinger10a11e22005-09-27 02:23:02 +00001832static void hashwalk_init(var *v, xhash *array)
1833{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001834 hash_item *hi;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001835 unsigned i;
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001836 walker_list *w;
1837 walker_list *prev_walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001838
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001839 if (v->type & VF_WALK) {
1840 prev_walker = v->x.walker;
1841 } else {
1842 v->type |= VF_WALK;
1843 prev_walker = NULL;
1844 }
1845 debug_printf_walker("hashwalk_init: prev_walker:%p\n", prev_walker);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001846
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001847 w = v->x.walker = xzalloc(sizeof(*w) + array->glen + 1); /* why + 1? */
1848 debug_printf_walker(" walker@%p=%p\n", &v->x.walker, w);
1849 w->cur = w->end = w->wbuf;
1850 w->prev = prev_walker;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001851 for (i = 0; i < array->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001852 hi = array->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001853 while (hi) {
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001854 strcpy(w->end, hi->name);
1855 nextword(&w->end);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001856 hi = hi->next;
1857 }
1858 }
1859}
1860
Mike Frysinger10a11e22005-09-27 02:23:02 +00001861static int hashwalk_next(var *v)
1862{
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001863 walker_list *w = v->x.walker;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001864
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001865 if (w->cur >= w->end) {
1866 walker_list *prev_walker = w->prev;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001867
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001868 debug_printf_walker("end of iteration, free(walker@%p:%p), prev_walker:%p\n", &v->x.walker, w, prev_walker);
1869 free(w);
Denys Vlasenko3cb60c32010-03-10 19:20:32 +01001870 v->x.walker = prev_walker;
1871 return FALSE;
1872 }
1873
Denys Vlasenkoda62b092010-03-11 12:13:18 +01001874 setvar_s(v, nextword(&w->cur));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001875 return TRUE;
1876}
1877
1878/* evaluate node, return 1 when result is true, 0 otherwise */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001879static int ptest(node *pattern)
1880{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00001881 /* ptest__v is "static": to save stack space? */
1882 return istrue(evaluate(pattern, &G.ptest__v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00001883}
1884
1885/* read next record from stream rsm into a variable v */
Mike Frysinger10a11e22005-09-27 02:23:02 +00001886static int awk_getline(rstream *rsm, var *v)
1887{
Glenn L McGrath545106f2002-11-11 06:21:00 +00001888 char *b;
1889 regmatch_t pmatch[2];
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001890 int size, a, p, pp = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001891 int fd, so, eo, r, rp;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001892 char c, *m, *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001893
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02001894 debug_printf_eval("entered %s()\n", __func__);
1895
Glenn L McGrath545106f2002-11-11 06:21:00 +00001896 /* we're using our own buffer since we need access to accumulating
1897 * characters
1898 */
1899 fd = fileno(rsm->F);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001900 m = rsm->buffer;
1901 a = rsm->adv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001902 p = rsm->pos;
1903 size = rsm->size;
1904 c = (char) rsplitter.n.info;
1905 rp = 0;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001906
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001907 if (!m)
1908 m = qrealloc(m, 256, &size);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001909
Glenn L McGrath545106f2002-11-11 06:21:00 +00001910 do {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001911 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001912 so = eo = p;
1913 r = 1;
1914 if (p > 0) {
1915 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
1916 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001917 b, 1, pmatch, 0) == 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00001918 so = pmatch[0].rm_so;
1919 eo = pmatch[0].rm_eo;
1920 if (b[eo] != '\0')
1921 break;
1922 }
1923 } else if (c != '\0') {
1924 s = strchr(b+pp, c);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01001925 if (!s)
1926 s = memchr(b+pp, '\0', p - pp);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001927 if (s) {
1928 so = eo = s-b;
1929 eo++;
1930 break;
1931 }
1932 } else {
1933 while (b[rp] == '\n')
1934 rp++;
1935 s = strstr(b+rp, "\n\n");
1936 if (s) {
1937 so = eo = s-b;
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001938 while (b[eo] == '\n')
1939 eo++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001940 if (b[eo] != '\0')
1941 break;
1942 }
1943 }
1944 }
1945
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001946 if (a > 0) {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01001947 memmove(m, m+a, p+1);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001948 b = m;
1949 a = 0;
1950 }
1951
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01001952 m = qrealloc(m, a+p+128, &size);
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001953 b = m + a;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001954 pp = p;
1955 p += safe_read(fd, b+p, size-p-1);
1956 if (p < pp) {
1957 p = 0;
1958 r = 0;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001959 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001960 }
1961 b[p] = '\0';
1962
1963 } while (p > pp);
1964
1965 if (p == 0) {
1966 r--;
1967 } else {
1968 c = b[so]; b[so] = '\0';
1969 setvar_s(v, b+rp);
1970 v->type |= VF_USER;
1971 b[so] = c;
1972 c = b[eo]; b[eo] = '\0';
Denis Vlasenkoffba9412007-05-17 23:03:35 +00001973 setvar_s(intvar[RT], b+so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001974 b[eo] = c;
1975 }
1976
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00001977 rsm->buffer = m;
1978 rsm->adv = a + eo;
1979 rsm->pos = p - eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001980 rsm->size = size;
1981
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02001982 debug_printf_eval("returning from %s(): %d\n", __func__, r);
1983
Glenn L McGrath545106f2002-11-11 06:21:00 +00001984 return r;
1985}
1986
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001987static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
Mike Frysinger10a11e22005-09-27 02:23:02 +00001988{
Denis Vlasenkof782f522007-01-01 23:51:30 +00001989 int r = 0;
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00001990 char c;
Denis Vlasenkof782f522007-01-01 23:51:30 +00001991 const char *s = format;
Glenn L McGrath545106f2002-11-11 06:21:00 +00001992
1993 if (int_as_int && n == (int)n) {
1994 r = snprintf(b, size, "%d", (int)n);
1995 } else {
Denis Vlasenkof782f522007-01-01 23:51:30 +00001996 do { c = *s; } while (c && *++s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00001997 if (strchr("diouxX", c)) {
1998 r = snprintf(b, size, format, (int)n);
1999 } else if (strchr("eEfgG", c)) {
2000 r = snprintf(b, size, format, n);
2001 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002002 syntax_error(EMSG_INV_FMT);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002003 }
2004 }
2005 return r;
2006}
2007
Glenn L McGrath545106f2002-11-11 06:21:00 +00002008/* formatted output into an allocated buffer, return ptr to buffer */
Mike Frysinger10a11e22005-09-27 02:23:02 +00002009static char *awk_printf(node *n)
2010{
Glenn L McGrath545106f2002-11-11 06:21:00 +00002011 char *b = NULL;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002012 char *fmt, *s, *f;
2013 const char *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002014 int i, j, incr, bsize;
2015 char c, c1;
2016 var *v, *arg;
2017
2018 v = nvalloc(1);
Rob Landleyd921b2e2006-08-03 15:41:12 +00002019 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002020
2021 i = 0;
2022 while (*f) {
2023 s = f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002024 while (*f && (*f != '%' || *++f == '%'))
Glenn L McGrath545106f2002-11-11 06:21:00 +00002025 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00002026 while (*f && !isalpha(*f)) {
2027 if (*f == '*')
2028 syntax_error("%*x formats are not supported");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002029 f++;
Denis Vlasenko389f9d52007-05-09 21:57:23 +00002030 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002031
2032 incr = (f - s) + MAXVARFMT;
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01002033 b = qrealloc(b, incr + i, &bsize);
Denis Vlasenkof782f522007-01-01 23:51:30 +00002034 c = *f;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002035 if (c != '\0')
2036 f++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002037 c1 = *f;
2038 *f = '\0';
Glenn L McGrath545106f2002-11-11 06:21:00 +00002039 arg = evaluate(nextarg(&n), v);
2040
2041 j = i;
2042 if (c == 'c' || !c) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002043 i += sprintf(b+i, s, is_numeric(arg) ?
2044 (char)getvar_i(arg) : *getvar_s(arg));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002045 } else if (c == 's') {
Denis Vlasenko92758142006-10-03 19:56:34 +00002046 s1 = getvar_s(arg);
Denys Vlasenkoc9955f22010-03-10 19:21:54 +01002047 b = qrealloc(b, incr+i+strlen(s1), &bsize);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002048 i += sprintf(b+i, s, s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002049 } else {
2050 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
2051 }
2052 *f = c1;
2053
2054 /* if there was an error while sprintf, return value is negative */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002055 if (i < j)
2056 i = j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002057 }
2058
Glenn L McGrath545106f2002-11-11 06:21:00 +00002059 free(fmt);
2060 nvfree(v);
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002061 b = xrealloc(b, i + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002062 b[i] = '\0';
2063 return b;
2064}
2065
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002066/* Common substitution routine.
2067 * Replace (nm)'th substring of (src) that matches (rn) with (repl),
2068 * store result into (dest), return number of substitutions.
2069 * If nm = 0, replace all matches.
2070 * If src or dst is NULL, use $0.
2071 * If subexp != 0, enable subexpression matching (\1-\9).
Glenn L McGrath545106f2002-11-11 06:21:00 +00002072 */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002073static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int subexp)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002074{
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002075 char *resbuf;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002076 const char *sp;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002077 int match_no, residx, replen, resbufsize;
2078 int regexec_flags;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002079 regmatch_t pmatch[10];
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002080 regex_t sreg, *regex;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002081
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002082 resbuf = NULL;
2083 residx = 0;
2084 match_no = 0;
2085 regexec_flags = 0;
2086 regex = as_regex(rn, &sreg);
2087 sp = getvar_s(src ? src : intvar[F0]);
2088 replen = strlen(repl);
2089 while (regexec(regex, sp, 10, pmatch, regexec_flags) == 0) {
2090 int so = pmatch[0].rm_so;
2091 int eo = pmatch[0].rm_eo;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002092
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002093 //bb_error_msg("match %u: [%u,%u] '%s'%p", match_no+1, so, eo, sp,sp);
2094 resbuf = qrealloc(resbuf, residx + eo + replen, &resbufsize);
2095 memcpy(resbuf + residx, sp, eo);
2096 residx += eo;
2097 if (++match_no >= nm) {
2098 const char *s;
2099 int nbs;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002100
Glenn L McGrath545106f2002-11-11 06:21:00 +00002101 /* replace */
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002102 residx -= (eo - so);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002103 nbs = 0;
2104 for (s = repl; *s; s++) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002105 char c = resbuf[residx++] = *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002106 if (c == '\\') {
2107 nbs++;
2108 continue;
2109 }
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002110 if (c == '&' || (subexp && c >= '0' && c <= '9')) {
2111 int j;
2112 residx -= ((nbs + 3) >> 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002113 j = 0;
2114 if (c != '&') {
2115 j = c - '0';
2116 nbs++;
2117 }
2118 if (nbs % 2) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002119 resbuf[residx++] = c;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002120 } else {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002121 int n = pmatch[j].rm_eo - pmatch[j].rm_so;
2122 resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize);
2123 memcpy(resbuf + residx, sp + pmatch[j].rm_so, n);
2124 residx += n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002125 }
2126 }
2127 nbs = 0;
2128 }
2129 }
2130
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002131 regexec_flags = REG_NOTBOL;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002132 sp += eo;
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002133 if (match_no == nm)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002134 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002135 if (eo == so) {
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002136 /* Empty match (e.g. "b*" will match anywhere).
2137 * Advance by one char. */
2138//BUG (bug 1333):
2139//gsub(/\<b*/,"") on "abc" will reach this point, advance to "bc"
2140//... and will erroneously match "b" even though it is NOT at the word start.
2141//we need REG_NOTBOW but it does not exist...
Denys Vlasenko7379cd12010-04-04 01:48:12 +02002142//TODO: if EXTRA_COMPAT=y, use GNU matching and re_search,
2143//it should be able to do it correctly.
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002144 /* Subtle: this is safe only because
2145 * qrealloc allocated at least one extra byte */
2146 resbuf[residx] = *sp;
2147 if (*sp == '\0')
2148 goto ret;
2149 sp++;
2150 residx++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002151 }
2152 }
2153
Denys Vlasenkofab288c2010-04-04 01:17:30 +02002154 resbuf = qrealloc(resbuf, residx + strlen(sp), &resbufsize);
2155 strcpy(resbuf + residx, sp);
2156 ret:
2157 //bb_error_msg("end sp:'%s'%p", sp,sp);
2158 setvar_p(dest ? dest : intvar[F0], resbuf);
2159 if (regex == &sreg)
2160 regfree(regex);
2161 return match_no;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002162}
2163
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002164static NOINLINE int do_mktime(const char *ds)
2165{
2166 struct tm then;
2167 int count;
2168
2169 /*memset(&then, 0, sizeof(then)); - not needed */
2170 then.tm_isdst = -1; /* default is unknown */
2171
2172 /* manpage of mktime says these fields are ints,
2173 * so we can sscanf stuff directly into them */
2174 count = sscanf(ds, "%u %u %u %u %u %u %d",
2175 &then.tm_year, &then.tm_mon, &then.tm_mday,
2176 &then.tm_hour, &then.tm_min, &then.tm_sec,
2177 &then.tm_isdst);
2178
2179 if (count < 6
2180 || (unsigned)then.tm_mon < 1
2181 || (unsigned)then.tm_year < 1900
2182 ) {
2183 return -1;
2184 }
2185
2186 then.tm_mon -= 1;
Denys Vlasenkobc3e9472009-09-21 04:16:00 +02002187 then.tm_year -= 1900;
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002188
2189 return mktime(&then);
2190}
2191
2192static NOINLINE var *exec_builtin(node *op, var *res)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002193{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002194#define tspl (G.exec_builtin__tspl)
2195
Glenn L McGrath545106f2002-11-11 06:21:00 +00002196 var *tv;
2197 node *an[4];
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002198 var *av[4];
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002199 const char *as[4];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002200 regmatch_t pmatch[2];
2201 regex_t sreg, *re;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002202 node *spl;
Mike Frysingerf87b3e32005-09-27 04:16:22 +00002203 uint32_t isr, info;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002204 int nargs;
2205 time_t tt;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002206 int i, l, ll, n;
2207
2208 tv = nvalloc(4);
2209 isr = info = op->info;
2210 op = op->l.n;
2211
2212 av[2] = av[3] = NULL;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002213 for (i = 0; i < 4 && op; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002214 an[i] = nextarg(&op);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002215 if (isr & 0x09000000)
2216 av[i] = evaluate(an[i], &tv[i]);
2217 if (isr & 0x08000000)
2218 as[i] = getvar_s(av[i]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002219 isr >>= 1;
2220 }
2221
2222 nargs = i;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00002223 if ((uint32_t)nargs < (info >> 30))
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002224 syntax_error(EMSG_TOO_FEW_ARGS);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002225
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002226 info &= OPNMASK;
2227 switch (info) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002228
Denis Vlasenkof782f522007-01-01 23:51:30 +00002229 case B_a2:
Rob Landleyd8205b32010-10-24 03:27:22 +02002230 if (ENABLE_FEATURE_AWK_LIBM)
2231 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
2232 else
2233 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002234 break;
2235
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002236 case B_sp: {
2237 char *s, *s1;
2238
Glenn L McGrath545106f2002-11-11 06:21:00 +00002239 if (nargs > 2) {
2240 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
2241 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
2242 } else {
2243 spl = &fsplitter.n;
2244 }
2245
2246 n = awk_split(as[0], spl, &s);
2247 s1 = s;
2248 clear_array(iamarray(av[1]));
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002249 for (i = 1; i <= n; i++)
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002250 setari_u(av[1], i, nextword(&s));
2251 free(s1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002252 setvar_i(res, n);
2253 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002254 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002255
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002256 case B_ss: {
2257 char *s;
2258
Rob Landleya3896512006-05-07 20:20:34 +00002259 l = strlen(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002260 i = getvar_i(av[1]) - 1;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002261 if (i > l)
2262 i = l;
2263 if (i < 0)
2264 i = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002265 n = (nargs > 2) ? getvar_i(av[2]) : l-i;
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002266 if (n < 0)
2267 n = 0;
Denis Vlasenko8ae5b282008-07-02 22:47:49 +00002268 s = xstrndup(as[0]+i, n);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002269 setvar_p(res, s);
2270 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002271 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002272
Denis Vlasenko7cbcd1c2008-08-28 23:16:58 +00002273 /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
2274 * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002275 case B_an:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002276 setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002277 break;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002278
Denis Vlasenkof782f522007-01-01 23:51:30 +00002279 case B_co:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002280 setvar_i(res, ~getvar_i_int(av[0]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002281 break;
2282
Denis Vlasenkof782f522007-01-01 23:51:30 +00002283 case B_ls:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002284 setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002285 break;
2286
Denis Vlasenkof782f522007-01-01 23:51:30 +00002287 case B_or:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002288 setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002289 break;
2290
Denis Vlasenkof782f522007-01-01 23:51:30 +00002291 case B_rs:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002292 setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002293 break;
2294
Denis Vlasenkof782f522007-01-01 23:51:30 +00002295 case B_xo:
Denis Vlasenkoa2e1eea2008-09-02 09:00:23 +00002296 setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002297 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002298
Denis Vlasenkof782f522007-01-01 23:51:30 +00002299 case B_lo:
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002300 case B_up: {
2301 char *s, *s1;
Rob Landleyd921b2e2006-08-03 15:41:12 +00002302 s1 = s = xstrdup(as[0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002303 while (*s1) {
Denys Vlasenko56b3eec2009-10-23 13:03:59 +02002304 //*s1 = (info == B_up) ? toupper(*s1) : tolower(*s1);
2305 if ((unsigned char)((*s1 | 0x20) - 'a') <= ('z' - 'a'))
2306 *s1 = (info == B_up) ? (*s1 & 0xdf) : (*s1 | 0x20);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002307 s1++;
2308 }
2309 setvar_p(res, s);
2310 break;
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002311 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002312
Denis Vlasenkof782f522007-01-01 23:51:30 +00002313 case B_ix:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002314 n = 0;
Rob Landleya3896512006-05-07 20:20:34 +00002315 ll = strlen(as[1]);
2316 l = strlen(as[0]) - ll;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002317 if (ll > 0 && l >= 0) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002318 if (!icase) {
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002319 char *s = strstr(as[0], as[1]);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002320 if (s)
2321 n = (s - as[0]) + 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002322 } else {
2323 /* this piece of code is terribly slow and
2324 * really should be rewritten
2325 */
Denys Vlasenko39fe4d12010-03-12 16:57:06 +01002326 for (i = 0; i <= l; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002327 if (strncasecmp(as[0]+i, as[1], ll) == 0) {
2328 n = i+1;
2329 break;
2330 }
2331 }
2332 }
2333 }
2334 setvar_i(res, n);
2335 break;
2336
Denis Vlasenkof782f522007-01-01 23:51:30 +00002337 case B_ti:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002338 if (nargs > 1)
2339 tt = getvar_i(av[1]);
2340 else
2341 time(&tt);
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002342 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002343 i = strftime(g_buf, MAXVARFMT,
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00002344 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
2345 localtime(&tt));
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002346 g_buf[i] = '\0';
2347 setvar_s(res, g_buf);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002348 break;
2349
Leonid Lisovskiy46a0be52009-09-21 04:08:08 +02002350 case B_mt:
2351 setvar_i(res, do_mktime(as[0]));
2352 break;
2353
Denis Vlasenkof782f522007-01-01 23:51:30 +00002354 case B_ma:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002355 re = as_regex(an[1], &sreg);
2356 n = regexec(re, as[0], 1, pmatch, 0);
2357 if (n == 0) {
2358 pmatch[0].rm_so++;
2359 pmatch[0].rm_eo++;
2360 } else {
2361 pmatch[0].rm_so = 0;
2362 pmatch[0].rm_eo = -1;
2363 }
2364 setvar_i(newvar("RSTART"), pmatch[0].rm_so);
2365 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
2366 setvar_i(res, pmatch[0].rm_so);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002367 if (re == &sreg)
2368 regfree(re);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002369 break;
2370
Denis Vlasenkof782f522007-01-01 23:51:30 +00002371 case B_ge:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002372 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
2373 break;
2374
Denis Vlasenkof782f522007-01-01 23:51:30 +00002375 case B_gs:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002376 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
2377 break;
2378
Denis Vlasenkof782f522007-01-01 23:51:30 +00002379 case B_su:
Glenn L McGrath545106f2002-11-11 06:21:00 +00002380 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
2381 break;
2382 }
2383
2384 nvfree(tv);
2385 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002386#undef tspl
Glenn L McGrath545106f2002-11-11 06:21:00 +00002387}
2388
2389/*
2390 * Evaluate node - the heart of the program. Supplied with subtree
2391 * and place where to store result. returns ptr to result.
2392 */
2393#define XC(n) ((n) >> 8)
2394
Mike Frysinger10a11e22005-09-27 02:23:02 +00002395static var *evaluate(node *op, var *res)
2396{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002397/* This procedure is recursive so we should count every byte */
2398#define fnargs (G.evaluate__fnargs)
2399/* seed is initialized to 1 */
2400#define seed (G.evaluate__seed)
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002401#define sreg (G.evaluate__sreg)
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002402
Glenn L McGrath545106f2002-11-11 06:21:00 +00002403 var *v1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002404
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002405 if (!op)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002406 return setvar_s(res, NULL);
2407
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002408 debug_printf_eval("entered %s()\n", __func__);
2409
Glenn L McGrath545106f2002-11-11 06:21:00 +00002410 v1 = nvalloc(2);
2411
2412 while (op) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002413 struct {
2414 var *v;
2415 const char *s;
2416 } L = L; /* for compiler */
2417 struct {
2418 var *v;
2419 const char *s;
2420 } R = R;
2421 double L_d = L_d;
2422 uint32_t opinfo;
2423 int opn;
2424 node *op1;
2425
Glenn L McGrath545106f2002-11-11 06:21:00 +00002426 opinfo = op->info;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002427 opn = (opinfo & OPNMASK);
2428 g_lineno = op->lineno;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002429 op1 = op->l.n;
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002430 debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002431
Mike Frysingerde2b9382005-09-27 03:18:00 +00002432 /* execute inevitable things */
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002433 if (opinfo & OF_RES1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002434 L.v = evaluate(op1, v1);
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002435 if (opinfo & OF_RES2)
2436 R.v = evaluate(op->r.n, v1+1);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002437 if (opinfo & OF_STR1) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002438 L.s = getvar_s(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002439 debug_printf_eval("L.s:'%s'\n", L.s);
2440 }
2441 if (opinfo & OF_STR2) {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002442 R.s = getvar_s(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002443 debug_printf_eval("R.s:'%s'\n", R.s);
2444 }
2445 if (opinfo & OF_NUM1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002446 L_d = getvar_i(L.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002447 debug_printf_eval("L_d:%f\n", L_d);
2448 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002449
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002450 debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002451 switch (XC(opinfo & OPCLSMASK)) {
2452
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002453 /* -- iterative node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002454
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002455 /* test pattern */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002456 case XC( OC_TEST ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002457 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2458 /* it's range pattern */
2459 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
2460 op->info |= OF_CHECKED;
2461 if (ptest(op1->r.n))
2462 op->info &= ~OF_CHECKED;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002463 op = op->a.n;
2464 } else {
2465 op = op->r.n;
2466 }
2467 } else {
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002468 op = ptest(op1) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002469 }
2470 break;
2471
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002472 /* just evaluate an expression, also used as unconditional jump */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002473 case XC( OC_EXEC ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002474 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002475
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002476 /* branch, used in if-else and various loops */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002477 case XC( OC_BR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002478 op = istrue(L.v) ? op->a.n : op->r.n;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002479 break;
2480
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002481 /* initialize for-in loop */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002482 case XC( OC_WALKINIT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002483 hashwalk_init(L.v, iamarray(R.v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002484 break;
2485
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002486 /* get next array item */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002487 case XC( OC_WALKNEXT ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002488 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2489 break;
2490
Denis Vlasenkof782f522007-01-01 23:51:30 +00002491 case XC( OC_PRINT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002492 case XC( OC_PRINTF ): {
2493 FILE *F = stdout;
2494
Mike Frysingerde2b9382005-09-27 03:18:00 +00002495 if (op->r.n) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002496 rstream *rsm = newfile(R.s);
2497 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002498 if (opn == '|') {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002499 rsm->F = popen(R.s, "w");
2500 if (rsm->F == NULL)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002501 bb_perror_msg_and_die("popen");
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002502 rsm->is_pipe = 1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002503 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002504 rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
Glenn L McGrath545106f2002-11-11 06:21:00 +00002505 }
2506 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002507 F = rsm->F;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002508 }
2509
2510 if ((opinfo & OPCLSMASK) == OC_PRINT) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002511 if (!op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002512 fputs(getvar_s(intvar[F0]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002513 } else {
2514 while (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002515 var *v = evaluate(nextarg(&op1), v1);
2516 if (v->type & VF_NUMBER) {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002517 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002518 getvar_i(v), TRUE);
2519 fputs(g_buf, F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002520 } else {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002521 fputs(getvar_s(v), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002522 }
2523
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002524 if (op1)
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002525 fputs(getvar_s(intvar[OFS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002526 }
2527 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002528 fputs(getvar_s(intvar[ORS]), F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002529
2530 } else { /* OC_PRINTF */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002531 char *s = awk_printf(op1);
2532 fputs(s, F);
2533 free(s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002534 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002535 fflush(F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002536 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002537 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002538
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002539 case XC( OC_DELETE ): {
2540 uint32_t info = op1->info & OPCLSMASK;
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002541 var *v;
2542
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002543 if (info == OC_VAR) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002544 v = op1->l.v;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002545 } else if (info == OC_FNARG) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002546 v = &fnargs[op1->l.aidx];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002547 } else {
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002548 syntax_error(EMSG_NOT_ARRAY);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002549 }
2550
Mike Frysingerde2b9382005-09-27 03:18:00 +00002551 if (op1->r.n) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002552 const char *s;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002553 clrvar(L.v);
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002554 s = getvar_s(evaluate(op1->r.n, v1));
2555 hash_remove(iamarray(v), s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002556 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002557 clear_array(iamarray(v));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002558 }
2559 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002560 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002561
Denis Vlasenkof782f522007-01-01 23:51:30 +00002562 case XC( OC_NEWSOURCE ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002563 g_progname = op->l.new_progname;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002564 break;
2565
Denis Vlasenkof782f522007-01-01 23:51:30 +00002566 case XC( OC_RETURN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002567 copyvar(res, L.v);
2568 break;
2569
Denis Vlasenkof782f522007-01-01 23:51:30 +00002570 case XC( OC_NEXTFILE ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002571 nextfile = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002572 case XC( OC_NEXT ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002573 nextrec = TRUE;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002574 case XC( OC_DONE ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002575 clrvar(res);
2576 break;
2577
Denis Vlasenkof782f522007-01-01 23:51:30 +00002578 case XC( OC_EXIT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002579 awk_exit(L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002580
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002581 /* -- recursive node type -- */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002582
Denis Vlasenkof782f522007-01-01 23:51:30 +00002583 case XC( OC_VAR ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002584 L.v = op->l.v;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002585 if (L.v == intvar[NF])
Glenn L McGrath545106f2002-11-11 06:21:00 +00002586 split_f0();
2587 goto v_cont;
2588
Denis Vlasenkof782f522007-01-01 23:51:30 +00002589 case XC( OC_FNARG ):
Denys Vlasenko7b81db12010-03-12 21:04:47 +01002590 L.v = &fnargs[op->l.aidx];
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002591 v_cont:
2592 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002593 break;
2594
Denis Vlasenkof782f522007-01-01 23:51:30 +00002595 case XC( OC_IN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002596 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2597 break;
2598
Denis Vlasenkof782f522007-01-01 23:51:30 +00002599 case XC( OC_REGEXP ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002600 op1 = op;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002601 L.s = getvar_s(intvar[F0]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002602 goto re_cont;
2603
Denis Vlasenkof782f522007-01-01 23:51:30 +00002604 case XC( OC_MATCH ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002605 op1 = op->r.n;
Denis Vlasenkoe1d3e032007-01-01 23:53:52 +00002606 re_cont:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002607 {
2608 regex_t *re = as_regex(op1, &sreg);
2609 int i = regexec(re, L.s, 0, NULL, 0);
2610 if (re == &sreg)
2611 regfree(re);
2612 setvar_i(res, (i == 0) ^ (opn == '!'));
2613 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002614 break;
2615
Denis Vlasenkof782f522007-01-01 23:51:30 +00002616 case XC( OC_MOVE ):
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002617 debug_printf_eval("MOVE\n");
Mike Frysingerde2b9382005-09-27 03:18:00 +00002618 /* if source is a temporary string, jusk relink it to dest */
Denys Vlasenko12847742009-11-30 01:15:04 +01002619//Disabled: if R.v is numeric but happens to have cached R.v->string,
2620//then L.v ends up being a string, which is wrong
2621// if (R.v == v1+1 && R.v->string) {
2622// res = setvar_p(L.v, R.v->string);
2623// R.v->string = NULL;
2624// } else {
Mike Frysingerde2b9382005-09-27 03:18:00 +00002625 res = copyvar(L.v, R.v);
Denys Vlasenko12847742009-11-30 01:15:04 +01002626// }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002627 break;
2628
Denis Vlasenkof782f522007-01-01 23:51:30 +00002629 case XC( OC_TERNARY ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002630 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002631 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002632 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
2633 break;
2634
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002635 case XC( OC_FUNC ): {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002636 var *vbeg, *v;
2637 const char *sv_progname;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002638
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002639 if (!op->r.f->body.first)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002640 syntax_error(EMSG_UNDEF_FUNC);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002641
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002642 vbeg = v = nvalloc(op->r.f->nargs + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002643 while (op1) {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002644 var *arg = evaluate(nextarg(&op1), v1);
2645 copyvar(v, arg);
2646 v->type |= VF_CHILD;
2647 v->x.parent = arg;
2648 if (++v - vbeg >= op->r.f->nargs)
Glenn L McGrath545106f2002-11-11 06:21:00 +00002649 break;
2650 }
2651
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002652 v = fnargs;
2653 fnargs = vbeg;
2654 sv_progname = g_progname;
2655
2656 res = evaluate(op->r.f->body.first, res);
2657
2658 g_progname = sv_progname;
2659 nvfree(fnargs);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002660 fnargs = v;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002661
Glenn L McGrath545106f2002-11-11 06:21:00 +00002662 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002663 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002664
Denis Vlasenkof782f522007-01-01 23:51:30 +00002665 case XC( OC_GETLINE ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002666 case XC( OC_PGETLINE ): {
2667 rstream *rsm;
2668 int i;
2669
Mike Frysingerde2b9382005-09-27 03:18:00 +00002670 if (op1) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002671 rsm = newfile(L.s);
2672 if (!rsm->F) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002673 if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002674 rsm->F = popen(L.s, "r");
2675 rsm->is_pipe = TRUE;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002676 } else {
Denys Vlasenkofb132e42010-10-29 11:46:52 +02002677 rsm->F = fopen_for_read(L.s); /* not xfopen! */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002678 }
2679 }
2680 } else {
Denys Vlasenko6ebdf7a2010-03-11 12:41:55 +01002681 if (!iF)
2682 iF = next_input_file();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002683 rsm = iF;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002684 }
2685
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02002686 if (!rsm || !rsm->F) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002687 setvar_i(intvar[ERRNO], errno);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002688 setvar_i(res, -1);
2689 break;
2690 }
2691
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002692 if (!op->r.n)
2693 R.v = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002694
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002695 i = awk_getline(rsm, R.v);
2696 if (i > 0 && !op1) {
2697 incvar(intvar[FNR]);
2698 incvar(intvar[NR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002699 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002700 setvar_i(res, i);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002701 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002702 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002703
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002704 /* simple builtins */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002705 case XC( OC_FBLTIN ): {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002706 double R_d = R_d; /* for compiler */
Glenn L McGrath545106f2002-11-11 06:21:00 +00002707
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002708 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002709 case F_in:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002710 R_d = (int)L_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002711 break;
2712
Denis Vlasenkof782f522007-01-01 23:51:30 +00002713 case F_rn:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002714 R_d = (double)rand() / (double)RAND_MAX;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002715 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002716
Denis Vlasenkof782f522007-01-01 23:51:30 +00002717 case F_co:
Rob Landleyd8205b32010-10-24 03:27:22 +02002718 if (ENABLE_FEATURE_AWK_LIBM) {
2719 R_d = cos(L_d);
2720 break;
2721 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002722
Denis Vlasenkof782f522007-01-01 23:51:30 +00002723 case F_ex:
Rob Landleyd8205b32010-10-24 03:27:22 +02002724 if (ENABLE_FEATURE_AWK_LIBM) {
2725 R_d = exp(L_d);
2726 break;
2727 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002728
Denis Vlasenkof782f522007-01-01 23:51:30 +00002729 case F_lg:
Rob Landleyd8205b32010-10-24 03:27:22 +02002730 if (ENABLE_FEATURE_AWK_LIBM) {
2731 R_d = log(L_d);
2732 break;
2733 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002734
Denis Vlasenkof782f522007-01-01 23:51:30 +00002735 case F_si:
Rob Landleyd8205b32010-10-24 03:27:22 +02002736 if (ENABLE_FEATURE_AWK_LIBM) {
2737 R_d = sin(L_d);
2738 break;
2739 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002740
Denis Vlasenkof782f522007-01-01 23:51:30 +00002741 case F_sq:
Rob Landleyd8205b32010-10-24 03:27:22 +02002742 if (ENABLE_FEATURE_AWK_LIBM) {
2743 R_d = sqrt(L_d);
2744 break;
2745 }
2746
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002747 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002748 break;
Rob Landleyd8205b32010-10-24 03:27:22 +02002749
Denis Vlasenkof782f522007-01-01 23:51:30 +00002750 case F_sr:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002751 R_d = (double)seed;
2752 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002753 srand(seed);
2754 break;
2755
Denis Vlasenkof782f522007-01-01 23:51:30 +00002756 case F_ti:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002757 R_d = time(NULL);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002758 break;
2759
Denis Vlasenkof782f522007-01-01 23:51:30 +00002760 case F_le:
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002761 if (!op1)
2762 L.s = getvar_s(intvar[F0]);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002763 R_d = strlen(L.s);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002764 break;
2765
Denis Vlasenkof782f522007-01-01 23:51:30 +00002766 case F_sy:
Denys Vlasenko8131eea2009-11-02 14:19:51 +01002767 fflush_all();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002768 R_d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
Denis Vlasenko249fabf2006-12-19 00:29:22 +00002769 ? (system(L.s) >> 8) : 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002770 break;
2771
Denis Vlasenkof782f522007-01-01 23:51:30 +00002772 case F_ff:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002773 if (!op1) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002774 fflush(stdout);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002775 } else if (L.s && *L.s) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002776 rstream *rsm = newfile(L.s);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002777 fflush(rsm->F);
2778 } else {
2779 fflush_all();
Glenn L McGrath545106f2002-11-11 06:21:00 +00002780 }
2781 break;
2782
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002783 case F_cl: {
2784 rstream *rsm;
2785 int err = 0;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002786 rsm = (rstream *)hash_search(fdhash, L.s);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002787 debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002788 if (rsm) {
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002789 debug_printf_eval("OC_FBLTIN F_cl "
2790 "rsm->is_pipe:%d, ->F:%p\n",
2791 rsm->is_pipe, rsm->F);
2792 /* Can be NULL if open failed. Example:
2793 * getline line <"doesnt_exist";
2794 * close("doesnt_exist"); <--- here rsm->F is NULL
2795 */
2796 if (rsm->F)
2797 err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002798 free(rsm->buffer);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002799 hash_remove(fdhash, L.s);
2800 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002801 if (err)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002802 setvar_i(intvar[ERRNO], errno);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002803 R_d = (double)err;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002804 break;
2805 }
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002806 } /* switch */
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002807 setvar_i(res, R_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002808 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002809 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002810
Denis Vlasenkof782f522007-01-01 23:51:30 +00002811 case XC( OC_BUILTIN ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002812 res = exec_builtin(op, res);
2813 break;
2814
Denis Vlasenkof782f522007-01-01 23:51:30 +00002815 case XC( OC_SPRINTF ):
Mike Frysingerde2b9382005-09-27 03:18:00 +00002816 setvar_p(res, awk_printf(op1));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002817 break;
2818
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002819 case XC( OC_UNARY ): {
2820 double Ld, R_d;
2821
2822 Ld = R_d = getvar_i(R.v);
Mike Frysingerde2b9382005-09-27 03:18:00 +00002823 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002824 case 'P':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002825 Ld = ++R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002826 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002827 case 'p':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002828 R_d++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002829 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002830 case 'M':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002831 Ld = --R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002832 goto r_op_change;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002833 case 'm':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002834 R_d--;
2835 r_op_change:
2836 setvar_i(R.v, R_d);
2837 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002838 case '!':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002839 Ld = !istrue(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002840 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002841 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002842 Ld = -R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002843 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002844 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002845 setvar_i(res, Ld);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002846 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002847 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002848
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002849 case XC( OC_FIELD ): {
2850 int i = (int)getvar_i(R.v);
2851 if (i == 0) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00002852 res = intvar[F0];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002853 } else {
2854 split_f0();
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002855 if (i > nfields)
2856 fsrealloc(i);
2857 res = &Fields[i - 1];
Glenn L McGrath545106f2002-11-11 06:21:00 +00002858 }
2859 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002860 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002861
Denis Vlasenkocd5c7862007-05-17 16:37:22 +00002862 /* concatenation (" ") and index joining (",") */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002863 case XC( OC_CONCAT ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002864 case XC( OC_COMMA ): {
2865 const char *sep = "";
2866 if ((opinfo & OPCLSMASK) == OC_COMMA)
2867 sep = getvar_s(intvar[SUBSEP]);
2868 setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s));
Glenn L McGrath545106f2002-11-11 06:21:00 +00002869 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002870 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002871
Denis Vlasenkof782f522007-01-01 23:51:30 +00002872 case XC( OC_LAND ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002873 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
2874 break;
2875
Denis Vlasenkof782f522007-01-01 23:51:30 +00002876 case XC( OC_LOR ):
Glenn L McGrath545106f2002-11-11 06:21:00 +00002877 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
2878 break;
2879
Denis Vlasenkof782f522007-01-01 23:51:30 +00002880 case XC( OC_BINARY ):
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002881 case XC( OC_REPLACE ): {
2882 double R_d = getvar_i(R.v);
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002883 debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002884 switch (opn) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002885 case '+':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002886 L_d += R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002887 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002888 case '-':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002889 L_d -= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002890 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002891 case '*':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002892 L_d *= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002893 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002894 case '/':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002895 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002896 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002897 L_d /= R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002898 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002899 case '&':
Rob Landleyd8205b32010-10-24 03:27:22 +02002900 if (ENABLE_FEATURE_AWK_LIBM)
2901 L_d = pow(L_d, R_d);
2902 else
2903 syntax_error(EMSG_NO_MATH);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002904 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002905 case '%':
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002906 if (R_d == 0)
Denys Vlasenkocdeda162009-11-30 01:14:16 +01002907 syntax_error(EMSG_DIV_BY_ZERO);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002908 L_d -= (int)(L_d / R_d) * R_d;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002909 break;
2910 }
Denys Vlasenkod527e0c2010-10-05 13:22:11 +02002911 debug_printf_eval("BINARY/REPLACE result:%f\n", L_d);
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002912 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, L_d);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002913 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002914 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002915
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002916 case XC( OC_COMPARE ): {
2917 int i = i; /* for compiler */
2918 double Ld;
2919
Glenn L McGrath545106f2002-11-11 06:21:00 +00002920 if (is_numeric(L.v) && is_numeric(R.v)) {
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002921 Ld = getvar_i(L.v) - getvar_i(R.v);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002922 } else {
Denys Vlasenkof9782ff2010-03-12 21:32:13 +01002923 const char *l = getvar_s(L.v);
2924 const char *r = getvar_s(R.v);
2925 Ld = icase ? strcasecmp(l, r) : strcmp(l, r);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002926 }
2927 switch (opn & 0xfe) {
Denis Vlasenkof782f522007-01-01 23:51:30 +00002928 case 0:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002929 i = (Ld > 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002930 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002931 case 2:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002932 i = (Ld >= 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002933 break;
Denis Vlasenkof782f522007-01-01 23:51:30 +00002934 case 4:
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002935 i = (Ld == 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002936 break;
2937 }
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002938 setvar_i(res, (i == 0) ^ (opn & 1));
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
Denis Vlasenkof782f522007-01-01 23:51:30 +00002942 default:
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002943 syntax_error(EMSG_POSSIBLE_ERROR);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002944 }
2945 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
2946 op = op->a.n;
2947 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
2948 break;
2949 if (nextrec)
2950 break;
Denys Vlasenkoc6ba9972010-03-12 21:05:09 +01002951 } /* while (op) */
2952
Glenn L McGrath545106f2002-11-11 06:21:00 +00002953 nvfree(v1);
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02002954 debug_printf_eval("returning from %s(): %p\n", __func__, res);
Glenn L McGrath545106f2002-11-11 06:21:00 +00002955 return res;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00002956#undef fnargs
2957#undef seed
2958#undef sreg
Glenn L McGrath545106f2002-11-11 06:21:00 +00002959}
2960
2961
2962/* -------- main & co. -------- */
2963
Mike Frysinger10a11e22005-09-27 02:23:02 +00002964static int awk_exit(int r)
2965{
Denis Vlasenkof782f522007-01-01 23:51:30 +00002966 var tv;
2967 unsigned i;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002968 hash_item *hi;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002969
Denis Vlasenkof782f522007-01-01 23:51:30 +00002970 zero_out_var(&tv);
2971
2972 if (!exiting) {
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002973 exiting = TRUE;
Glenn L McGrathca29ffc2004-09-24 09:24:27 +00002974 nextrec = FALSE;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00002975 evaluate(endseq.first, &tv);
2976 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00002977
2978 /* waiting for children */
Denis Vlasenkof782f522007-01-01 23:51:30 +00002979 for (i = 0; i < fdhash->csize; i++) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002980 hi = fdhash->items[i];
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002981 while (hi) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002982 if (hi->data.rs.F && hi->data.rs.is_pipe)
2983 pclose(hi->data.rs.F);
2984 hi = hi->next;
2985 }
2986 }
2987
2988 exit(r);
2989}
2990
2991/* if expr looks like "var=value", perform assignment and return 1,
2992 * otherwise return 0 */
"Vladimir N. Oleynik"5cf9a032005-10-19 09:21:51 +00002993static int is_assignment(const char *expr)
Mike Frysinger10a11e22005-09-27 02:23:02 +00002994{
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002995 char *exprc, *val, *s, *s1;
Glenn L McGrath545106f2002-11-11 06:21:00 +00002996
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02002997 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00002998 return FALSE;
2999 }
3000
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003001 exprc = xstrdup(expr);
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003002 val = exprc + (val - expr);
3003 *val++ = '\0';
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003004
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003005 s = s1 = val;
3006 while ((*s1 = nextchar(&s)) != '\0')
3007 s1++;
Denys Vlasenko6a0d7492010-10-23 21:02:15 +02003008
Denys Vlasenko2b299fe2010-10-24 01:58:04 +02003009 setvar_u(newvar(exprc), val);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003010 free(exprc);
3011 return TRUE;
3012}
3013
3014/* switch to next input file */
Mike Frysinger10a11e22005-09-27 02:23:02 +00003015static rstream *next_input_file(void)
3016{
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003017#define rsm (G.next_input_file__rsm)
3018#define files_happen (G.next_input_file__files_happen)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003019
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003020 FILE *F;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +00003021 const char *fname, *ind;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003022
Denys Vlasenkocdeda162009-11-30 01:14:16 +01003023 if (rsm.F)
3024 fclose(rsm.F);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003025 rsm.F = NULL;
Glenn L McGrath00ed36f2003-10-30 13:36:39 +00003026 rsm.pos = rsm.adv = 0;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003027
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003028 for (;;) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003029 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003030 if (files_happen)
3031 return NULL;
3032 fname = "-";
3033 F = stdin;
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003034 break;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003035 }
Denys Vlasenkof65c5f52011-09-07 20:01:39 +02003036 ind = getvar_s(incvar(intvar[ARGIND]));
3037 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
3038 if (fname && *fname && !is_assignment(fname)) {
3039 F = xfopen_stdin(fname);
3040 break;
3041 }
3042 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003043
3044 files_happen = TRUE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003045 setvar_s(intvar[FILENAME], fname);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003046 rsm.F = F;
3047 return &rsm;
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003048#undef rsm
3049#undef files_happen
Glenn L McGrath545106f2002-11-11 06:21:00 +00003050}
3051
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00003052int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00003053int awk_main(int argc, char **argv)
Mike Frysinger10a11e22005-09-27 02:23:02 +00003054{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00003055 unsigned opt;
Denys Vlasenko7b46d112011-09-11 00:30:56 +02003056 char *opt_F;
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003057 llist_t *list_v = NULL;
3058 llist_t *list_f = NULL;
3059 int i, j;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003060 var *v;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003061 var tv;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003062 char **envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003063 char *vnames = (char *)vNames; /* cheat */
3064 char *vvalues = (char *)vValues;
3065
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003066 INIT_G();
3067
Denis Vlasenko150f4022007-01-13 21:06:21 +00003068 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
Denis Vlasenko6dc6ebb2007-01-01 23:53:12 +00003069 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
3070 if (ENABLE_LOCALE_SUPPORT)
3071 setlocale(LC_NUMERIC, "C");
3072
Denis Vlasenkof782f522007-01-01 23:51:30 +00003073 zero_out_var(&tv);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003074
3075 /* allocate global buffer */
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003076 g_buf = xmalloc(MAXVARFMT + 1);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003077
3078 vhash = hash_init();
3079 ahash = hash_init();
3080 fdhash = hash_init();
3081 fnhash = hash_init();
3082
3083 /* initialize variables */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003084 for (i = 0; *vnames; i++) {
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003085 intvar[i] = v = newvar(nextword(&vnames));
Denis Vlasenkof782f522007-01-01 23:51:30 +00003086 if (*vvalues != '\377')
3087 setvar_s(v, nextword(&vvalues));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003088 else
3089 setvar_i(v, 0);
3090
Denis Vlasenkof782f522007-01-01 23:51:30 +00003091 if (*vnames == '*') {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003092 v->type |= VF_SPECIAL;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003093 vnames++;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003094 }
3095 }
3096
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003097 handle_special(intvar[FS]);
3098 handle_special(intvar[RS]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003099
Denis Vlasenkof782f522007-01-01 23:51:30 +00003100 newfile("/dev/stdin")->F = stdin;
3101 newfile("/dev/stdout")->F = stdout;
3102 newfile("/dev/stderr")->F = stderr;
Glenn L McGrath545106f2002-11-11 06:21:00 +00003103
Denis Vlasenkof71d9162007-05-03 22:57:56 +00003104 /* Huh, people report that sometimes environ is NULL. Oh well. */
3105 if (environ) for (envp = environ; *envp; envp++) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003106 /* environ is writable, thus we don't strdup it needlessly */
3107 char *s = *envp;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003108 char *s1 = strchr(s, '=');
3109 if (s1) {
Denis Vlasenkob78c7822007-07-18 18:31:11 +00003110 *s1 = '\0';
3111 /* Both findvar and setvar_u take const char*
3112 * as 2nd arg -> environment is not trashed */
3113 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
3114 *s1 = '=';
Eric Andersen67776be2004-07-30 23:52:08 +00003115 }
Glenn L McGrath545106f2002-11-11 06:21:00 +00003116 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003117 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
Denys Vlasenko7b46d112011-09-11 00:30:56 +02003118 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003119 argv += optind;
3120 argc -= optind;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003121 if (opt & 0x1)
3122 setvar_s(intvar[FS], opt_F); // -F
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003123 while (list_v) { /* -v */
3124 if (!is_assignment(llist_pop(&list_v)))
Denis Vlasenkobe644a82007-03-10 17:22:14 +00003125 bb_show_usage();
3126 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003127 if (list_f) { /* -f */
3128 do {
3129 char *s = NULL;
3130 FILE *from_file;
3131
3132 g_progname = llist_pop(&list_f);
3133 from_file = xfopen_stdin(g_progname);
3134 /* one byte is reserved for some trick in next_token */
Denis Vlasenkof782f522007-01-01 23:51:30 +00003135 for (i = j = 1; j > 0; i += j) {
3136 s = xrealloc(s, i + 4096);
3137 j = fread(s + i, 1, 4094, from_file);
Denis Vlasenko099efbf2006-09-22 09:02:30 +00003138 }
Denis Vlasenko3bb2bbd2008-07-01 01:57:36 +00003139 s[i] = '\0';
3140 fclose(from_file);
3141 parse_program(s + 1);
3142 free(s);
3143 } while (list_f);
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00003144 argc++;
Denis Vlasenkof782f522007-01-01 23:51:30 +00003145 } else { // no -f: take program from 1st parameter
3146 if (!argc)
3147 bb_show_usage();
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003148 g_progname = "cmd. line";
Denis Vlasenkof782f522007-01-01 23:51:30 +00003149 parse_program(*argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003150 }
Denis Vlasenko099efbf2006-09-22 09:02:30 +00003151 if (opt & 0x8) // -W
Denys Vlasenko7b46d112011-09-11 00:30:56 +02003152 bb_error_msg("warning: option -W is ignored");
Glenn L McGrath545106f2002-11-11 06:21:00 +00003153
Glenn L McGrath545106f2002-11-11 06:21:00 +00003154 /* fill in ARGV array */
Denis Vlasenko41d5ebe2009-01-25 01:00:15 +00003155 setvar_i(intvar[ARGC], argc);
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003156 setari_u(intvar[ARGV], 0, "awk");
Denis Vlasenkof782f522007-01-01 23:51:30 +00003157 i = 0;
3158 while (*argv)
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003159 setari_u(intvar[ARGV], ++i, *argv++);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003160
3161 evaluate(beginseq.first, &tv);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003162 if (!mainseq.first && !endseq.first)
Glenn L McGrath545106f2002-11-11 06:21:00 +00003163 awk_exit(EXIT_SUCCESS);
3164
3165 /* input file could already be opened in BEGIN block */
Denys Vlasenkocdeda162009-11-30 01:14:16 +01003166 if (!iF)
3167 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003168
3169 /* passing through input files */
3170 while (iF) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003171 nextfile = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003172 setvar_i(intvar[FNR], 0);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003173
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003174 while ((i = awk_getline(iF, intvar[F0])) > 0) {
Glenn L McGrath545106f2002-11-11 06:21:00 +00003175 nextrec = FALSE;
Denis Vlasenkoffba9412007-05-17 23:03:35 +00003176 incvar(intvar[NR]);
3177 incvar(intvar[FNR]);
Glenn L McGrath545106f2002-11-11 06:21:00 +00003178 evaluate(mainseq.first, &tv);
3179
3180 if (nextfile)
3181 break;
3182 }
3183
Denis Vlasenkof782f522007-01-01 23:51:30 +00003184 if (i < 0)
Denis Vlasenkoae5a8aa2007-06-06 17:01:00 +00003185 syntax_error(strerror(errno));
Glenn L McGrath545106f2002-11-11 06:21:00 +00003186
3187 iF = next_input_file();
Glenn L McGrath545106f2002-11-11 06:21:00 +00003188 }
3189
Glenn L McGrath545106f2002-11-11 06:21:00 +00003190 awk_exit(EXIT_SUCCESS);
Denis Vlasenkof782f522007-01-01 23:51:30 +00003191 /*return 0;*/
Glenn L McGrath545106f2002-11-11 06:21:00 +00003192}