7 |
* Licensed under the GPL v2 or later, see the file LICENSE in this tarball. |
* Licensed under the GPL v2 or later, see the file LICENSE in this tarball. |
8 |
*/ |
*/ |
9 |
|
|
10 |
#include "busybox.h" |
#include "libbb.h" |
11 |
#include "xregex.h" |
#include "xregex.h" |
12 |
#include <math.h> |
#include <math.h> |
13 |
|
|
14 |
|
/* This is a NOEXEC applet. Be very careful! */ |
15 |
|
|
16 |
#define MAXVARFMT 240 |
|
17 |
#define MINNVBLOCK 64 |
#define MAXVARFMT 240 |
18 |
|
#define MINNVBLOCK 64 |
19 |
|
|
20 |
/* variable flags */ |
/* variable flags */ |
21 |
#define VF_NUMBER 0x0001 /* 1 = primary type is number */ |
#define VF_NUMBER 0x0001 /* 1 = primary type is number */ |
22 |
#define VF_ARRAY 0x0002 /* 1 = it's an array */ |
#define VF_ARRAY 0x0002 /* 1 = it's an array */ |
23 |
|
|
24 |
#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */ |
#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */ |
25 |
#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */ |
#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */ |
26 |
#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */ |
#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */ |
27 |
#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */ |
#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */ |
28 |
#define VF_FSTR 0x1000 /* 1 = string points to fstring buffer */ |
#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */ |
29 |
#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */ |
#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */ |
30 |
#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */ |
#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */ |
31 |
|
|
32 |
/* these flags are static, don't change them when value is changed */ |
/* these flags are static, don't change them when value is changed */ |
33 |
#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY) |
#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY) |
34 |
|
|
35 |
/* Variable */ |
/* Variable */ |
36 |
typedef struct var_s { |
typedef struct var_s { |
37 |
unsigned short type; /* flags */ |
unsigned type; /* flags */ |
38 |
double number; |
double number; |
39 |
char *string; |
char *string; |
40 |
union { |
union { |
41 |
int aidx; /* func arg idx (for compilation stage) */ |
int aidx; /* func arg idx (for compilation stage) */ |
42 |
struct xhash_s *array; /* array ptr */ |
struct xhash_s *array; /* array ptr */ |
43 |
struct var_s *parent; /* for func args, ptr to actual parameter */ |
struct var_s *parent; /* for func args, ptr to actual parameter */ |
44 |
char **walker; /* list of array elements (for..in) */ |
char **walker; /* list of array elements (for..in) */ |
45 |
} x; |
} x; |
46 |
} var; |
} var; |
47 |
|
|
49 |
typedef struct chain_s { |
typedef struct chain_s { |
50 |
struct node_s *first; |
struct node_s *first; |
51 |
struct node_s *last; |
struct node_s *last; |
52 |
char *programname; |
const char *programname; |
53 |
} chain; |
} chain; |
54 |
|
|
55 |
/* Function */ |
/* Function */ |
56 |
typedef struct func_s { |
typedef struct func_s { |
57 |
unsigned short nargs; |
unsigned nargs; |
58 |
struct chain_s body; |
struct chain_s body; |
59 |
} func; |
} func; |
60 |
|
|
65 |
int adv; |
int adv; |
66 |
int size; |
int size; |
67 |
int pos; |
int pos; |
68 |
unsigned short is_pipe; |
smallint is_pipe; |
69 |
} rstream; |
} rstream; |
70 |
|
|
71 |
typedef struct hash_item_s { |
typedef struct hash_item_s { |
72 |
union { |
union { |
73 |
struct var_s v; /* variable/array hash */ |
struct var_s v; /* variable/array hash */ |
74 |
struct rstream_s rs; /* redirect streams hash */ |
struct rstream_s rs; /* redirect streams hash */ |
75 |
struct func_s f; /* functions hash */ |
struct func_s f; /* functions hash */ |
76 |
} data; |
} data; |
77 |
struct hash_item_s *next; /* next in chain */ |
struct hash_item_s *next; /* next in chain */ |
78 |
char name[1]; /* really it's longer */ |
char name[1]; /* really it's longer */ |
79 |
} hash_item; |
} hash_item; |
80 |
|
|
81 |
typedef struct xhash_s { |
typedef struct xhash_s { |
82 |
unsigned nel; /* num of elements */ |
unsigned nel; /* num of elements */ |
83 |
unsigned csize; /* current hash size */ |
unsigned csize; /* current hash size */ |
84 |
unsigned nprime; /* next hash size in PRIMES[] */ |
unsigned nprime; /* next hash size in PRIMES[] */ |
85 |
unsigned glen; /* summary length of item names */ |
unsigned glen; /* summary length of item names */ |
86 |
struct hash_item_s **items; |
struct hash_item_s **items; |
87 |
} xhash; |
} xhash; |
88 |
|
|
89 |
/* Tree node */ |
/* Tree node */ |
90 |
typedef struct node_s { |
typedef struct node_s { |
91 |
uint32_t info; |
uint32_t info; |
92 |
unsigned short lineno; |
unsigned lineno; |
93 |
union { |
union { |
94 |
struct node_s *n; |
struct node_s *n; |
95 |
var *v; |
var *v; |
155 |
#define TC_STRING (1 << 28) |
#define TC_STRING (1 << 28) |
156 |
#define TC_NUMBER (1 << 29) |
#define TC_NUMBER (1 << 29) |
157 |
|
|
158 |
#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) |
#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) |
159 |
|
|
160 |
/* combined token classes */ |
/* combined token classes */ |
161 |
#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) |
#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) |
162 |
#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) |
#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) |
163 |
#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION | \ |
#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \ |
164 |
TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER) |
| TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER) |
165 |
|
|
166 |
#define TC_STATEMNT (TC_STATX | TC_WHILE) |
#define TC_STATEMNT (TC_STATX | TC_WHILE) |
167 |
#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE) |
#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE) |
168 |
|
|
169 |
/* word tokens, cannot mean something else if not expected */ |
/* word tokens, cannot mean something else if not expected */ |
170 |
#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN | \ |
#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \ |
171 |
TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END) |
| TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END) |
172 |
|
|
173 |
/* discard newlines after these */ |
/* discard newlines after these */ |
174 |
#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM | \ |
#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \ |
175 |
TC_BINOP | TC_OPTERM) |
| TC_BINOP | TC_OPTERM) |
176 |
|
|
177 |
/* what can expression begin with */ |
/* what can expression begin with */ |
178 |
#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP) |
#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP) |
179 |
/* what can group begin with */ |
/* what can group begin with */ |
180 |
#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART) |
#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART) |
181 |
|
|
182 |
/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */ |
/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */ |
183 |
/* operator is inserted between them */ |
/* operator is inserted between them */ |
184 |
#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM | \ |
#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \ |
185 |
TC_STRING | TC_NUMBER | TC_UOPPOST) |
| TC_STRING | TC_NUMBER | TC_UOPPOST) |
186 |
#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) |
#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) |
187 |
|
|
188 |
#define OF_RES1 0x010000 |
#define OF_RES1 0x010000 |
189 |
#define OF_RES2 0x020000 |
#define OF_RES2 0x020000 |
190 |
#define OF_STR1 0x040000 |
#define OF_STR1 0x040000 |
191 |
#define OF_STR2 0x080000 |
#define OF_STR2 0x080000 |
192 |
#define OF_NUM1 0x100000 |
#define OF_NUM1 0x100000 |
193 |
#define OF_CHECKED 0x200000 |
#define OF_CHECKED 0x200000 |
194 |
|
|
195 |
/* combined operator flags */ |
/* combined operator flags */ |
196 |
#define xx 0 |
#define xx 0 |
204 |
#define SV (OF_RES1 | OF_STR1 | OF_RES2) |
#define SV (OF_RES1 | OF_STR1 | OF_RES2) |
205 |
#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2) |
#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2) |
206 |
|
|
207 |
#define OPCLSMASK 0xFF00 |
#define OPCLSMASK 0xFF00 |
208 |
#define OPNMASK 0x007F |
#define OPNMASK 0x007F |
209 |
|
|
210 |
/* operator priority is a highest byte (even: r->l, odd: l->r grouping) |
/* operator priority is a highest byte (even: r->l, odd: l->r grouping) |
211 |
* For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1, |
* For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1, |
212 |
* n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string |
* n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string |
213 |
*/ |
*/ |
214 |
#define P(x) (x << 24) |
#define P(x) (x << 24) |
215 |
#define PRIMASK 0x7F000000 |
#define PRIMASK 0x7F000000 |
216 |
#define PRIMASK2 0x7E000000 |
#define PRIMASK2 0x7E000000 |
217 |
|
|
218 |
/* Operation classes */ |
/* Operation classes */ |
219 |
|
|
221 |
#define RECUR_FROM_THIS 0x1000 |
#define RECUR_FROM_THIS 0x1000 |
222 |
|
|
223 |
enum { |
enum { |
224 |
OC_DELETE=0x0100, OC_EXEC=0x0200, OC_NEWSOURCE=0x0300, |
OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300, |
225 |
OC_PRINT=0x0400, OC_PRINTF=0x0500, OC_WALKINIT=0x0600, |
OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600, |
226 |
|
|
227 |
OC_BR=0x0700, OC_BREAK=0x0800, OC_CONTINUE=0x0900, |
OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900, |
228 |
OC_EXIT=0x0a00, OC_NEXT=0x0b00, OC_NEXTFILE=0x0c00, |
OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00, |
229 |
OC_TEST=0x0d00, OC_WALKNEXT=0x0e00, |
OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00, |
230 |
|
|
231 |
OC_BINARY=0x1000, OC_BUILTIN=0x1100, OC_COLON=0x1200, |
OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200, |
232 |
OC_COMMA=0x1300, OC_COMPARE=0x1400, OC_CONCAT=0x1500, |
OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500, |
233 |
OC_FBLTIN=0x1600, OC_FIELD=0x1700, OC_FNARG=0x1800, |
OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800, |
234 |
OC_FUNC=0x1900, OC_GETLINE=0x1a00, OC_IN=0x1b00, |
OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00, |
235 |
OC_LAND=0x1c00, OC_LOR=0x1d00, OC_MATCH=0x1e00, |
OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00, |
236 |
OC_MOVE=0x1f00, OC_PGETLINE=0x2000, OC_REGEXP=0x2100, |
OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100, |
237 |
OC_REPLACE=0x2200, OC_RETURN=0x2300, OC_SPRINTF=0x2400, |
OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400, |
238 |
OC_TERNARY=0x2500, OC_UNARY=0x2600, OC_VAR=0x2700, |
OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700, |
239 |
OC_DONE=0x2800, |
OC_DONE = 0x2800, |
240 |
|
|
241 |
ST_IF=0x3000, ST_DO=0x3100, ST_FOR=0x3200, |
ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200, |
242 |
ST_WHILE=0x3300 |
ST_WHILE = 0x3300 |
243 |
}; |
}; |
244 |
|
|
245 |
/* simple builtins */ |
/* simple builtins */ |
246 |
enum { |
enum { |
247 |
F_in=0, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr, |
F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr, |
248 |
F_ti, F_le, F_sy, F_ff, F_cl |
F_ti, F_le, F_sy, F_ff, F_cl |
249 |
}; |
}; |
250 |
|
|
251 |
/* builtins */ |
/* builtins */ |
252 |
enum { |
enum { |
253 |
B_a2=0, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up, |
B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up, |
254 |
B_ge, B_gs, B_su, |
B_ge, B_gs, B_su, |
255 |
B_an, B_co, B_ls, B_or, B_rs, B_xo, |
B_an, B_co, B_ls, B_or, B_rs, B_xo, |
256 |
}; |
}; |
257 |
|
|
258 |
/* tokens and their corresponding info values */ |
/* tokens and their corresponding info values */ |
259 |
|
|
260 |
#define NTC "\377" /* switch to next token class (tc<<1) */ |
#define NTC "\377" /* switch to next token class (tc<<1) */ |
261 |
#define NTCC '\377' |
#define NTCC '\377' |
262 |
|
|
263 |
#define OC_B OC_BUILTIN |
#define OC_B OC_BUILTIN |
264 |
|
|
265 |
static const char tokenlist[] = |
static const char tokenlist[] ALIGN1 = |
266 |
"\1(" NTC |
"\1(" NTC |
267 |
"\1)" NTC |
"\1)" NTC |
268 |
"\1/" NTC /* REGEXP */ |
"\1/" NTC /* REGEXP */ |
364 |
/* internal variable names and their initial values */ |
/* internal variable names and their initial values */ |
365 |
/* asterisk marks SPECIAL vars; $ is just no-named Field0 */ |
/* asterisk marks SPECIAL vars; $ is just no-named Field0 */ |
366 |
enum { |
enum { |
367 |
CONVFMT=0, OFMT, FS, OFS, |
CONVFMT, OFMT, FS, OFS, |
368 |
ORS, RS, RT, FILENAME, |
ORS, RS, RT, FILENAME, |
369 |
SUBSEP, ARGIND, ARGC, ARGV, |
SUBSEP, ARGIND, ARGC, ARGV, |
370 |
ERRNO, FNR, |
ERRNO, FNR, |
371 |
NR, NF, IGNORECASE, |
NR, NF, IGNORECASE, |
372 |
ENVIRON, F0, _intvarcount_ |
ENVIRON, F0, NUM_INTERNAL_VARS |
373 |
}; |
}; |
374 |
|
|
375 |
static const char vNames[] = |
static const char vNames[] ALIGN1 = |
376 |
"CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0" |
"CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0" |
377 |
"ORS\0" "RS\0*" "RT\0" "FILENAME\0" |
"ORS\0" "RS\0*" "RT\0" "FILENAME\0" |
378 |
"SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0" |
"SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0" |
380 |
"NR\0" "NF\0*" "IGNORECASE\0*" |
"NR\0" "NF\0*" "IGNORECASE\0*" |
381 |
"ENVIRON\0" "$\0*" "\0"; |
"ENVIRON\0" "$\0*" "\0"; |
382 |
|
|
383 |
static const char vValues[] = |
static const char vValues[] ALIGN1 = |
384 |
"%.6g\0" "%.6g\0" " \0" " \0" |
"%.6g\0" "%.6g\0" " \0" " \0" |
385 |
"\n\0" "\n\0" "\0" "\0" |
"\n\0" "\n\0" "\0" "\0" |
386 |
"\034\0" |
"\034\0" |
387 |
"\377"; |
"\377"; |
388 |
|
|
389 |
/* hash size may grow to these values */ |
/* hash size may grow to these values */ |
390 |
#define FIRST_PRIME 61; |
#define FIRST_PRIME 61 |
391 |
static const unsigned PRIMES[] = { 251, 1021, 4093, 16381, 65521 }; |
static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 }; |
392 |
enum { NPRIMES = sizeof(PRIMES) / sizeof(unsigned) }; |
|
393 |
|
|
394 |
/* globals */ |
/* Globals. Split in two parts so that first one is addressed |
395 |
|
* with (mostly short) negative offsets. |
396 |
extern char **environ; |
* NB: it's unsafe to put members of type "double" |
397 |
|
* into globals2 (gcc may fail to align them). |
398 |
static var * V[_intvarcount_]; |
*/ |
399 |
static chain beginseq, mainseq, endseq, *seq; |
struct globals { |
400 |
static int nextrec, nextfile; |
double t_double; |
401 |
static node *break_ptr, *continue_ptr; |
chain beginseq, mainseq, endseq; |
402 |
static rstream *iF; |
chain *seq; |
403 |
static xhash *vhash, *ahash, *fdhash, *fnhash; |
node *break_ptr, *continue_ptr; |
404 |
static char *programname; |
rstream *iF; |
405 |
static short lineno; |
xhash *vhash, *ahash, *fdhash, *fnhash; |
406 |
static int is_f0_split; |
const char *g_progname; |
407 |
static int nfields; |
int g_lineno; |
408 |
static var *Fields; |
int nfields; |
409 |
static tsplitter fsplitter, rsplitter; |
int maxfields; /* used in fsrealloc() only */ |
410 |
static nvblock *cb; |
var *Fields; |
411 |
static char *pos; |
nvblock *g_cb; |
412 |
static char *buf; |
char *g_pos; |
413 |
static int icase; |
char *g_buf; |
414 |
static int exiting; |
smallint icase; |
415 |
|
smallint exiting; |
416 |
|
smallint nextrec; |
417 |
|
smallint nextfile; |
418 |
|
smallint is_f0_split; |
419 |
|
}; |
420 |
|
struct globals2 { |
421 |
|
uint32_t t_info; /* often used */ |
422 |
|
uint32_t t_tclass; |
423 |
|
char *t_string; |
424 |
|
int t_lineno; |
425 |
|
int t_rollback; |
426 |
|
|
427 |
|
var *intvar[NUM_INTERNAL_VARS]; /* often used */ |
428 |
|
|
429 |
|
/* former statics from various functions */ |
430 |
|
char *split_f0__fstrings; |
431 |
|
|
432 |
|
uint32_t next_token__save_tclass; |
433 |
|
uint32_t next_token__save_info; |
434 |
|
uint32_t next_token__ltclass; |
435 |
|
smallint next_token__concat_inserted; |
436 |
|
|
437 |
|
smallint next_input_file__files_happen; |
438 |
|
rstream next_input_file__rsm; |
439 |
|
|
440 |
|
var *evaluate__fnargs; |
441 |
|
unsigned evaluate__seed; |
442 |
|
regex_t evaluate__sreg; |
443 |
|
|
444 |
|
var ptest__v; |
445 |
|
|
446 |
|
tsplitter exec_builtin__tspl; |
447 |
|
|
448 |
|
/* biggest and least used members go last */ |
449 |
|
tsplitter fsplitter, rsplitter; |
450 |
|
}; |
451 |
|
#define G1 (ptr_to_globals[-1]) |
452 |
|
#define G (*(struct globals2 *)ptr_to_globals) |
453 |
|
/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */ |
454 |
|
/*char G1size[sizeof(G1)]; - 0x74 */ |
455 |
|
/*char Gsize[sizeof(G)]; - 0x1c4 */ |
456 |
|
/* Trying to keep most of members accessible with short offsets: */ |
457 |
|
/*char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */ |
458 |
|
#define t_double (G1.t_double ) |
459 |
|
#define beginseq (G1.beginseq ) |
460 |
|
#define mainseq (G1.mainseq ) |
461 |
|
#define endseq (G1.endseq ) |
462 |
|
#define seq (G1.seq ) |
463 |
|
#define break_ptr (G1.break_ptr ) |
464 |
|
#define continue_ptr (G1.continue_ptr) |
465 |
|
#define iF (G1.iF ) |
466 |
|
#define vhash (G1.vhash ) |
467 |
|
#define ahash (G1.ahash ) |
468 |
|
#define fdhash (G1.fdhash ) |
469 |
|
#define fnhash (G1.fnhash ) |
470 |
|
#define g_progname (G1.g_progname ) |
471 |
|
#define g_lineno (G1.g_lineno ) |
472 |
|
#define nfields (G1.nfields ) |
473 |
|
#define maxfields (G1.maxfields ) |
474 |
|
#define Fields (G1.Fields ) |
475 |
|
#define g_cb (G1.g_cb ) |
476 |
|
#define g_pos (G1.g_pos ) |
477 |
|
#define g_buf (G1.g_buf ) |
478 |
|
#define icase (G1.icase ) |
479 |
|
#define exiting (G1.exiting ) |
480 |
|
#define nextrec (G1.nextrec ) |
481 |
|
#define nextfile (G1.nextfile ) |
482 |
|
#define is_f0_split (G1.is_f0_split ) |
483 |
|
#define t_info (G.t_info ) |
484 |
|
#define t_tclass (G.t_tclass ) |
485 |
|
#define t_string (G.t_string ) |
486 |
|
#define t_lineno (G.t_lineno ) |
487 |
|
#define t_rollback (G.t_rollback ) |
488 |
|
#define intvar (G.intvar ) |
489 |
|
#define fsplitter (G.fsplitter ) |
490 |
|
#define rsplitter (G.rsplitter ) |
491 |
|
#define INIT_G() do { \ |
492 |
|
SET_PTR_TO_GLOBALS(xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1)); \ |
493 |
|
G.next_token__ltclass = TC_OPTERM; \ |
494 |
|
G.evaluate__seed = 1; \ |
495 |
|
} while (0) |
496 |
|
|
|
static struct { |
|
|
uint32_t tclass; |
|
|
uint32_t info; |
|
|
char *string; |
|
|
double number; |
|
|
short lineno; |
|
|
int rollback; |
|
|
} t; |
|
497 |
|
|
498 |
/* function prototypes */ |
/* function prototypes */ |
499 |
static void handle_special(var *); |
static void handle_special(var *); |
502 |
static var *evaluate(node *, var *); |
static var *evaluate(node *, var *); |
503 |
static rstream *next_input_file(void); |
static rstream *next_input_file(void); |
504 |
static int fmt_num(char *, int, const char *, double, int); |
static int fmt_num(char *, int, const char *, double, int); |
505 |
static int awk_exit(int) ATTRIBUTE_NORETURN; |
static int awk_exit(int) NORETURN; |
506 |
|
|
507 |
/* ---- error handling ---- */ |
/* ---- error handling ---- */ |
508 |
|
|
509 |
static const char EMSG_INTERNAL_ERROR[] = "Internal error"; |
static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error"; |
510 |
static const char EMSG_UNEXP_EOS[] = "Unexpected end of string"; |
static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string"; |
511 |
static const char EMSG_UNEXP_TOKEN[] = "Unexpected token"; |
static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token"; |
512 |
static const char EMSG_DIV_BY_ZERO[] = "Division by zero"; |
static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero"; |
513 |
static const char EMSG_INV_FMT[] = "Invalid format specifier"; |
static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier"; |
514 |
static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin"; |
static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; |
515 |
static const char EMSG_NOT_ARRAY[] = "Not an array"; |
static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; |
516 |
static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error"; |
static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; |
517 |
static const char EMSG_UNDEF_FUNC[] = "Call to undefined function"; |
static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; |
518 |
#if !ENABLE_FEATURE_AWK_MATH |
#if !ENABLE_FEATURE_AWK_LIBM |
519 |
static const char EMSG_NO_MATH[] = "Math support is not compiled in"; |
static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; |
520 |
#endif |
#endif |
521 |
|
|
522 |
static void zero_out_var(var * vp) |
static void zero_out_var(var * vp) |
524 |
memset(vp, 0, sizeof(*vp)); |
memset(vp, 0, sizeof(*vp)); |
525 |
} |
} |
526 |
|
|
527 |
static void syntax_error(const char * const message) ATTRIBUTE_NORETURN; |
static void syntax_error(const char *const message) NORETURN; |
528 |
static void syntax_error(const char * const message) |
static void syntax_error(const char *const message) |
529 |
{ |
{ |
530 |
bb_error_msg_and_die("%s:%i: %s", programname, lineno, message); |
bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message); |
531 |
} |
} |
532 |
|
|
|
#define runtime_error(x) syntax_error(x) |
|
|
|
|
|
|
|
533 |
/* ---- hash stuff ---- */ |
/* ---- hash stuff ---- */ |
534 |
|
|
535 |
static unsigned hashidx(const char *name) |
static unsigned hashidx(const char *name) |
572 |
unsigned newsize, i, idx; |
unsigned newsize, i, idx; |
573 |
hash_item **newitems, *hi, *thi; |
hash_item **newitems, *hi, *thi; |
574 |
|
|
575 |
if (hash->nprime == NPRIMES) |
if (hash->nprime == ARRAY_SIZE(PRIMES)) |
576 |
return; |
return; |
577 |
|
|
578 |
newsize = PRIMES[hash->nprime++]; |
newsize = PRIMES[hash->nprime++]; |
579 |
newitems = xzalloc(newsize * sizeof(hash_item *)); |
newitems = xzalloc(newsize * sizeof(hash_item *)); |
580 |
|
|
581 |
for (i=0; i<hash->csize; i++) { |
for (i = 0; i < hash->csize; i++) { |
582 |
hi = hash->items[i]; |
hi = hash->items[i]; |
583 |
while (hi) { |
while (hi) { |
584 |
thi = hi; |
thi = hi; |
602 |
int l; |
int l; |
603 |
|
|
604 |
hi = hash_search(hash, name); |
hi = hash_search(hash, name); |
605 |
if (! hi) { |
if (!hi) { |
606 |
if (++hash->nel / hash->csize > 10) |
if (++hash->nel / hash->csize > 10) |
607 |
hash_rebuild(hash); |
hash_rebuild(hash); |
608 |
|
|
618 |
return &(hi->data); |
return &(hi->data); |
619 |
} |
} |
620 |
|
|
621 |
#define findvar(hash, name) ((var*) hash_find((hash) , (name))) |
#define findvar(hash, name) ((var*) hash_find((hash), (name))) |
622 |
#define newvar(name) ((var*) hash_find(vhash , (name))) |
#define newvar(name) ((var*) hash_find(vhash, (name))) |
623 |
#define newfile(name) ((rstream*)hash_find(fdhash ,(name))) |
#define newfile(name) ((rstream*)hash_find(fdhash, (name))) |
624 |
#define newfunc(name) ((func*) hash_find(fnhash , (name))) |
#define newfunc(name) ((func*) hash_find(fnhash, (name))) |
625 |
|
|
626 |
static void hash_remove(xhash *hash, const char *name) |
static void hash_remove(xhash *hash, const char *name) |
627 |
{ |
{ |
628 |
hash_item *hi, **phi; |
hash_item *hi, **phi; |
629 |
|
|
630 |
phi = &(hash->items[ hashidx(name) % hash->csize ]); |
phi = &(hash->items[hashidx(name) % hash->csize]); |
631 |
while (*phi) { |
while (*phi) { |
632 |
hi = *phi; |
hi = *phi; |
633 |
if (strcmp(hi->name, name) == 0) { |
if (strcmp(hi->name, name) == 0) { |
647 |
{ |
{ |
648 |
char *p = *s; |
char *p = *s; |
649 |
|
|
650 |
while (*p == ' ' || *p == '\t' || |
while (1) { |
651 |
(*p == '\\' && *(p+1) == '\n' && (++p, ++t.lineno))) { |
if (*p == '\\' && p[1] == '\n') { |
652 |
|
p++; |
653 |
|
t_lineno++; |
654 |
|
} else if (*p != ' ' && *p != '\t') { |
655 |
|
break; |
656 |
|
} |
657 |
p++; |
p++; |
658 |
} |
} |
659 |
*s = p; |
*s = p; |
679 |
return c; |
return c; |
680 |
} |
} |
681 |
|
|
682 |
static int ATTRIBUTE_ALWAYS_INLINE isalnum_(int c) |
static ALWAYS_INLINE int isalnum_(int c) |
683 |
{ |
{ |
684 |
return (isalnum(c) || c == '_'); |
return (isalnum(c) || c == '_'); |
685 |
} |
} |
686 |
|
|
687 |
static FILE *afopen(const char *path, const char *mode) |
static double my_strtod(char **pp) |
688 |
{ |
{ |
689 |
return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode); |
#if ENABLE_DESKTOP |
690 |
|
if ((*pp)[0] == '0' |
691 |
|
&& ((((*pp)[1] | 0x20) == 'x') || isdigit((*pp)[1])) |
692 |
|
) { |
693 |
|
return strtoull(*pp, pp, 0); |
694 |
|
} |
695 |
|
#endif |
696 |
|
return strtod(*pp, pp); |
697 |
} |
} |
698 |
|
|
699 |
/* -------- working with variables (set/get/copy/etc) -------- */ |
/* -------- working with variables (set/get/copy/etc) -------- */ |
705 |
while (a->type & VF_CHILD) |
while (a->type & VF_CHILD) |
706 |
a = a->x.parent; |
a = a->x.parent; |
707 |
|
|
708 |
if (! (a->type & VF_ARRAY)) { |
if (!(a->type & VF_ARRAY)) { |
709 |
a->type |= VF_ARRAY; |
a->type |= VF_ARRAY; |
710 |
a->x.array = hash_init(); |
a->x.array = hash_init(); |
711 |
} |
} |
717 |
unsigned i; |
unsigned i; |
718 |
hash_item *hi, *thi; |
hash_item *hi, *thi; |
719 |
|
|
720 |
for (i=0; i<array->csize; i++) { |
for (i = 0; i < array->csize; i++) { |
721 |
hi = array->items[i]; |
hi = array->items[i]; |
722 |
while (hi) { |
while (hi) { |
723 |
thi = hi; |
thi = hi; |
748 |
clrvar(v); |
clrvar(v); |
749 |
v->string = value; |
v->string = value; |
750 |
handle_special(v); |
handle_special(v); |
|
|
|
751 |
return v; |
return v; |
752 |
} |
} |
753 |
|
|
768 |
/* set array element to user string */ |
/* set array element to user string */ |
769 |
static void setari_u(var *a, int idx, const char *s) |
static void setari_u(var *a, int idx, const char *s) |
770 |
{ |
{ |
771 |
|
char sidx[sizeof(int)*3 + 1]; |
772 |
var *v; |
var *v; |
|
static char sidx[12]; |
|
773 |
|
|
774 |
sprintf(sidx, "%d", idx); |
sprintf(sidx, "%d", idx); |
775 |
v = findvar(iamarray(a), sidx); |
v = findvar(iamarray(a), sidx); |
786 |
return v; |
return v; |
787 |
} |
} |
788 |
|
|
789 |
static char *getvar_s(var *v) |
static const char *getvar_s(var *v) |
790 |
{ |
{ |
791 |
/* if v is numeric and has no cached string, convert it to string */ |
/* if v is numeric and has no cached string, convert it to string */ |
792 |
if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) { |
if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) { |
793 |
fmt_num(buf, MAXVARFMT, getvar_s(V[CONVFMT]), v->number, TRUE); |
fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE); |
794 |
v->string = xstrdup(buf); |
v->string = xstrdup(g_buf); |
795 |
v->type |= VF_CACHED; |
v->type |= VF_CACHED; |
796 |
} |
} |
797 |
return (v->string == NULL) ? "" : v->string; |
return (v->string == NULL) ? "" : v->string; |
805 |
v->number = 0; |
v->number = 0; |
806 |
s = v->string; |
s = v->string; |
807 |
if (s && *s) { |
if (s && *s) { |
808 |
v->number = strtod(s, &s); |
v->number = my_strtod(&s); |
809 |
if (v->type & VF_USER) { |
if (v->type & VF_USER) { |
810 |
skip_spaces(&s); |
skip_spaces(&s); |
811 |
if (*s != '\0') |
if (*s != '\0') |
819 |
return v->number; |
return v->number; |
820 |
} |
} |
821 |
|
|
822 |
|
/* Used for operands of bitwise ops */ |
823 |
|
static unsigned long getvar_i_int(var *v) |
824 |
|
{ |
825 |
|
double d = getvar_i(v); |
826 |
|
|
827 |
|
/* Casting doubles to longs is undefined for values outside |
828 |
|
* of target type range. Try to widen it as much as possible */ |
829 |
|
if (d >= 0) |
830 |
|
return (unsigned long)d; |
831 |
|
/* Why? Think about d == -4294967295.0 (assuming 32bit longs) */ |
832 |
|
return - (long) (unsigned long) (-d); |
833 |
|
} |
834 |
|
|
835 |
static var *copyvar(var *dest, const var *src) |
static var *copyvar(var *dest, const var *src) |
836 |
{ |
{ |
837 |
if (dest != src) { |
if (dest != src) { |
838 |
clrvar(dest); |
clrvar(dest); |
839 |
dest->type |= (src->type & ~VF_DONTTOUCH); |
dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR)); |
840 |
dest->number = src->number; |
dest->number = src->number; |
841 |
if (src->string) |
if (src->string) |
842 |
dest->string = xstrdup(src->string); |
dest->string = xstrdup(src->string); |
847 |
|
|
848 |
static var *incvar(var *v) |
static var *incvar(var *v) |
849 |
{ |
{ |
850 |
return setvar_i(v, getvar_i(v)+1.); |
return setvar_i(v, getvar_i(v) + 1.); |
851 |
} |
} |
852 |
|
|
853 |
/* return true if v is number or numeric string */ |
/* return true if v is number or numeric string */ |
862 |
{ |
{ |
863 |
if (is_numeric(v)) |
if (is_numeric(v)) |
864 |
return (v->number == 0) ? 0 : 1; |
return (v->number == 0) ? 0 : 1; |
865 |
else |
return (v->string && *(v->string)) ? 1 : 0; |
|
return (v->string && *(v->string)) ? 1 : 0; |
|
866 |
} |
} |
867 |
|
|
868 |
/* temporary variables allocator. Last allocated should be first freed */ |
/* temporary variables allocator. Last allocated should be first freed */ |
872 |
var *v, *r; |
var *v, *r; |
873 |
int size; |
int size; |
874 |
|
|
875 |
while (cb) { |
while (g_cb) { |
876 |
pb = cb; |
pb = g_cb; |
877 |
if ((cb->pos - cb->nv) + n <= cb->size) break; |
if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break; |
878 |
cb = cb->next; |
g_cb = g_cb->next; |
879 |
} |
} |
880 |
|
|
881 |
if (! cb) { |
if (!g_cb) { |
882 |
size = (n <= MINNVBLOCK) ? MINNVBLOCK : n; |
size = (n <= MINNVBLOCK) ? MINNVBLOCK : n; |
883 |
cb = xmalloc(sizeof(nvblock) + size * sizeof(var)); |
g_cb = xzalloc(sizeof(nvblock) + size * sizeof(var)); |
884 |
cb->size = size; |
g_cb->size = size; |
885 |
cb->pos = cb->nv; |
g_cb->pos = g_cb->nv; |
886 |
cb->prev = pb; |
g_cb->prev = pb; |
887 |
cb->next = NULL; |
/*g_cb->next = NULL; - xzalloc did it */ |
888 |
if (pb) pb->next = cb; |
if (pb) pb->next = g_cb; |
889 |
} |
} |
890 |
|
|
891 |
v = r = cb->pos; |
v = r = g_cb->pos; |
892 |
cb->pos += n; |
g_cb->pos += n; |
893 |
|
|
894 |
while (v < cb->pos) { |
while (v < g_cb->pos) { |
895 |
v->type = 0; |
v->type = 0; |
896 |
v->string = NULL; |
v->string = NULL; |
897 |
v++; |
v++; |
904 |
{ |
{ |
905 |
var *p; |
var *p; |
906 |
|
|
907 |
if (v < cb->nv || v >= cb->pos) |
if (v < g_cb->nv || v >= g_cb->pos) |
908 |
runtime_error(EMSG_INTERNAL_ERROR); |
syntax_error(EMSG_INTERNAL_ERROR); |
909 |
|
|
910 |
for (p=v; p<cb->pos; p++) { |
for (p = v; p < g_cb->pos; p++) { |
911 |
if ((p->type & (VF_ARRAY|VF_CHILD)) == VF_ARRAY) { |
if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) { |
912 |
clear_array(iamarray(p)); |
clear_array(iamarray(p)); |
913 |
free(p->x.array->items); |
free(p->x.array->items); |
914 |
free(p->x.array); |
free(p->x.array); |
919 |
clrvar(p); |
clrvar(p); |
920 |
} |
} |
921 |
|
|
922 |
cb->pos = v; |
g_cb->pos = v; |
923 |
while (cb->prev && cb->pos == cb->nv) { |
while (g_cb->prev && g_cb->pos == g_cb->nv) { |
924 |
cb = cb->prev; |
g_cb = g_cb->prev; |
925 |
} |
} |
926 |
} |
} |
927 |
|
|
928 |
/* ------- awk program text parsing ------- */ |
/* ------- awk program text parsing ------- */ |
929 |
|
|
930 |
/* Parse next token pointed by global pos, place results into global t. |
/* Parse next token pointed by global pos, place results into global ttt. |
931 |
* If token isn't expected, give away. Return token class |
* If token isn't expected, give away. Return token class |
932 |
*/ |
*/ |
933 |
static uint32_t next_token(uint32_t expected) |
static uint32_t next_token(uint32_t expected) |
934 |
{ |
{ |
935 |
static int concat_inserted; |
#define concat_inserted (G.next_token__concat_inserted) |
936 |
static uint32_t save_tclass, save_info; |
#define save_tclass (G.next_token__save_tclass) |
937 |
static uint32_t ltclass = TC_OPTERM; |
#define save_info (G.next_token__save_info) |
938 |
|
/* Initialized to TC_OPTERM: */ |
939 |
|
#define ltclass (G.next_token__ltclass) |
940 |
|
|
941 |
char *p, *pp, *s; |
char *p, *pp, *s; |
942 |
const char *tl; |
const char *tl; |
944 |
const uint32_t *ti; |
const uint32_t *ti; |
945 |
int l; |
int l; |
946 |
|
|
947 |
if (t.rollback) { |
if (t_rollback) { |
948 |
t.rollback = FALSE; |
t_rollback = FALSE; |
949 |
|
|
950 |
} else if (concat_inserted) { |
} else if (concat_inserted) { |
951 |
concat_inserted = FALSE; |
concat_inserted = FALSE; |
952 |
t.tclass = save_tclass; |
t_tclass = save_tclass; |
953 |
t.info = save_info; |
t_info = save_info; |
954 |
|
|
955 |
} else { |
} else { |
956 |
p = pos; |
p = g_pos; |
957 |
readnext: |
readnext: |
958 |
skip_spaces(&p); |
skip_spaces(&p); |
959 |
lineno = t.lineno; |
g_lineno = t_lineno; |
960 |
if (*p == '#') |
if (*p == '#') |
961 |
while (*p != '\n' && *p != '\0') p++; |
while (*p != '\n' && *p != '\0') |
962 |
|
p++; |
963 |
|
|
964 |
if (*p == '\n') |
if (*p == '\n') |
965 |
t.lineno++; |
t_lineno++; |
966 |
|
|
967 |
if (*p == '\0') { |
if (*p == '\0') { |
968 |
tc = TC_EOF; |
tc = TC_EOF; |
969 |
|
|
970 |
} else if (*p == '\"') { |
} else if (*p == '\"') { |
971 |
/* it's a string */ |
/* it's a string */ |
972 |
t.string = s = ++p; |
t_string = s = ++p; |
973 |
while (*p != '\"') { |
while (*p != '\"') { |
974 |
if (*p == '\0' || *p == '\n') |
if (*p == '\0' || *p == '\n') |
975 |
syntax_error(EMSG_UNEXP_EOS); |
syntax_error(EMSG_UNEXP_EOS); |
981 |
|
|
982 |
} else if ((expected & TC_REGEXP) && *p == '/') { |
} else if ((expected & TC_REGEXP) && *p == '/') { |
983 |
/* it's regexp */ |
/* it's regexp */ |
984 |
t.string = s = ++p; |
t_string = s = ++p; |
985 |
while (*p != '/') { |
while (*p != '/') { |
986 |
if (*p == '\0' || *p == '\n') |
if (*p == '\0' || *p == '\n') |
987 |
syntax_error(EMSG_UNEXP_EOS); |
syntax_error(EMSG_UNEXP_EOS); |
988 |
if ((*s++ = *p++) == '\\') { |
*s = *p++; |
989 |
|
if (*s++ == '\\') { |
990 |
pp = p; |
pp = p; |
991 |
*(s-1) = bb_process_escape_sequence((const char **)&p); |
*(s-1) = bb_process_escape_sequence((const char **)&p); |
992 |
if (*pp == '\\') *s++ = '\\'; |
if (*pp == '\\') |
993 |
if (p == pp) *s++ = *p++; |
*s++ = '\\'; |
994 |
|
if (p == pp) |
995 |
|
*s++ = *p++; |
996 |
} |
} |
997 |
} |
} |
998 |
p++; |
p++; |
1001 |
|
|
1002 |
} else if (*p == '.' || isdigit(*p)) { |
} else if (*p == '.' || isdigit(*p)) { |
1003 |
/* it's a number */ |
/* it's a number */ |
1004 |
t.number = strtod(p, &p); |
t_double = my_strtod(&p); |
1005 |
if (*p == '.') |
if (*p == '.') |
1006 |
syntax_error(EMSG_UNEXP_TOKEN); |
syntax_error(EMSG_UNEXP_TOKEN); |
1007 |
tc = TC_NUMBER; |
tc = TC_NUMBER; |
1021 |
* matches and it's not a longer word, |
* matches and it's not a longer word, |
1022 |
* then this is what we are looking for |
* then this is what we are looking for |
1023 |
*/ |
*/ |
1024 |
if ((tc & (expected | TC_WORD | TC_NEWLINE)) && |
if ((tc & (expected | TC_WORD | TC_NEWLINE)) |
1025 |
*tl == *p && strncmp(p, tl, l) == 0 && |
&& *tl == *p && strncmp(p, tl, l) == 0 |
1026 |
!((tc & TC_WORD) && isalnum_(*(p + l)))) { |
&& !((tc & TC_WORD) && isalnum_(p[l])) |
1027 |
t.info = *ti; |
) { |
1028 |
|
t_info = *ti; |
1029 |
p += l; |
p += l; |
1030 |
break; |
break; |
1031 |
} |
} |
1040 |
if (!isalnum_(*p)) |
if (!isalnum_(*p)) |
1041 |
syntax_error(EMSG_UNEXP_TOKEN); |
syntax_error(EMSG_UNEXP_TOKEN); |
1042 |
|
|
1043 |
t.string = --p; |
t_string = --p; |
1044 |
while (isalnum_(*(++p))) { |
while (isalnum_(*(++p))) { |
1045 |
*(p-1) = *p; |
*(p-1) = *p; |
1046 |
} |
} |
1047 |
*(p-1) = '\0'; |
*(p-1) = '\0'; |
1048 |
tc = TC_VARIABLE; |
tc = TC_VARIABLE; |
1049 |
/* also consume whitespace between functionname and bracket */ |
/* also consume whitespace between functionname and bracket */ |
1050 |
if (!(expected & TC_VARIABLE)) skip_spaces(&p); |
if (!(expected & TC_VARIABLE)) |
1051 |
|
skip_spaces(&p); |
1052 |
if (*p == '(') { |
if (*p == '(') { |
1053 |
tc = TC_FUNCTION; |
tc = TC_FUNCTION; |
1054 |
} else { |
} else { |
1059 |
} |
} |
1060 |
} |
} |
1061 |
} |
} |
1062 |
pos = p; |
g_pos = p; |
1063 |
|
|
1064 |
/* skipping newlines in some cases */ |
/* skipping newlines in some cases */ |
1065 |
if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE)) |
if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE)) |
1066 |
goto readnext; |
goto readnext; |
1067 |
|
|
1068 |
/* insert concatenation operator when needed */ |
/* insert concatenation operator when needed */ |
1069 |
if ((ltclass&TC_CONCAT1) && (tc&TC_CONCAT2) && (expected&TC_BINOP)) { |
if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) { |
1070 |
concat_inserted = TRUE; |
concat_inserted = TRUE; |
1071 |
save_tclass = tc; |
save_tclass = tc; |
1072 |
save_info = t.info; |
save_info = t_info; |
1073 |
tc = TC_BINOP; |
tc = TC_BINOP; |
1074 |
t.info = OC_CONCAT | SS | P(35); |
t_info = OC_CONCAT | SS | P(35); |
1075 |
} |
} |
1076 |
|
|
1077 |
t.tclass = tc; |
t_tclass = tc; |
1078 |
} |
} |
1079 |
ltclass = t.tclass; |
ltclass = t_tclass; |
1080 |
|
|
1081 |
/* Are we ready for this? */ |
/* Are we ready for this? */ |
1082 |
if (! (ltclass & expected)) |
if (!(ltclass & expected)) |
1083 |
syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ? |
syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ? |
1084 |
EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); |
EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); |
1085 |
|
|
1086 |
return ltclass; |
return ltclass; |
1087 |
|
#undef concat_inserted |
1088 |
|
#undef save_tclass |
1089 |
|
#undef save_info |
1090 |
|
#undef ltclass |
1091 |
} |
} |
1092 |
|
|
1093 |
static void rollback_token(void) { t.rollback = TRUE; } |
static void rollback_token(void) |
1094 |
|
{ |
1095 |
|
t_rollback = TRUE; |
1096 |
|
} |
1097 |
|
|
1098 |
static node *new_node(uint32_t info) |
static node *new_node(uint32_t info) |
1099 |
{ |
{ |
1101 |
|
|
1102 |
n = xzalloc(sizeof(node)); |
n = xzalloc(sizeof(node)); |
1103 |
n->info = info; |
n->info = info; |
1104 |
n->lineno = lineno; |
n->lineno = g_lineno; |
1105 |
return n; |
return n; |
1106 |
} |
} |
1107 |
|
|
1108 |
static node *mk_re_node(char *s, node *n, regex_t *re) |
static node *mk_re_node(const char *s, node *n, regex_t *re) |
1109 |
{ |
{ |
1110 |
n->info = OC_REGEXP; |
n->info = OC_REGEXP; |
1111 |
n->l.re = re; |
n->l.re = re; |
1112 |
n->r.ire = re + 1; |
n->r.ire = re + 1; |
1113 |
xregcomp(re, s, REG_EXTENDED); |
xregcomp(re, s, REG_EXTENDED); |
1114 |
xregcomp(re+1, s, REG_EXTENDED | REG_ICASE); |
xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE); |
1115 |
|
|
1116 |
return n; |
return n; |
1117 |
} |
} |
1136 |
sn.r.n = glptr = NULL; |
sn.r.n = glptr = NULL; |
1137 |
xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; |
xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; |
1138 |
|
|
1139 |
while (! ((tc = next_token(xtc)) & iexp)) { |
while (!((tc = next_token(xtc)) & iexp)) { |
1140 |
if (glptr && (t.info == (OC_COMPARE|VV|P(39)|2))) { |
if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { |
1141 |
/* input redirection (<) attached to glptr node */ |
/* input redirection (<) attached to glptr node */ |
1142 |
cn = glptr->l.n = new_node(OC_CONCAT|SS|P(37)); |
cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); |
1143 |
cn->a.n = glptr; |
cn->a.n = glptr; |
1144 |
xtc = TC_OPERAND | TC_UOPPRE; |
xtc = TC_OPERAND | TC_UOPPRE; |
1145 |
glptr = NULL; |
glptr = NULL; |
1148 |
/* for binary and postfix-unary operators, jump back over |
/* for binary and postfix-unary operators, jump back over |
1149 |
* previous operators with higher priority */ |
* previous operators with higher priority */ |
1150 |
vn = cn; |
vn = cn; |
1151 |
while ( ((t.info & PRIMASK) > (vn->a.n->info & PRIMASK2)) || |
while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) |
1152 |
((t.info == vn->info) && ((t.info & OPCLSMASK) == OC_COLON)) ) |
|| ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) ) |
1153 |
vn = vn->a.n; |
vn = vn->a.n; |
1154 |
if ((t.info & OPCLSMASK) == OC_TERNARY) |
if ((t_info & OPCLSMASK) == OC_TERNARY) |
1155 |
t.info += P(6); |
t_info += P(6); |
1156 |
cn = vn->a.n->r.n = new_node(t.info); |
cn = vn->a.n->r.n = new_node(t_info); |
1157 |
cn->a.n = vn->a.n; |
cn->a.n = vn->a.n; |
1158 |
if (tc & TC_BINOP) { |
if (tc & TC_BINOP) { |
1159 |
cn->l.n = vn; |
cn->l.n = vn; |
1160 |
xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; |
xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; |
1161 |
if ((t.info & OPCLSMASK) == OC_PGETLINE) { |
if ((t_info & OPCLSMASK) == OC_PGETLINE) { |
1162 |
/* it's a pipe */ |
/* it's a pipe */ |
1163 |
next_token(TC_GETLINE); |
next_token(TC_GETLINE); |
1164 |
/* give maximum priority to this pipe */ |
/* give maximum priority to this pipe */ |
1175 |
/* for operands and prefix-unary operators, attach them |
/* for operands and prefix-unary operators, attach them |
1176 |
* to last node */ |
* to last node */ |
1177 |
vn = cn; |
vn = cn; |
1178 |
cn = vn->r.n = new_node(t.info); |
cn = vn->r.n = new_node(t_info); |
1179 |
cn->a.n = vn; |
cn->a.n = vn; |
1180 |
xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; |
xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; |
1181 |
if (tc & (TC_OPERAND | TC_REGEXP)) { |
if (tc & (TC_OPERAND | TC_REGEXP)) { |
1186 |
case TC_VARIABLE: |
case TC_VARIABLE: |
1187 |
case TC_ARRAY: |
case TC_ARRAY: |
1188 |
cn->info = OC_VAR; |
cn->info = OC_VAR; |
1189 |
if ((v = hash_search(ahash, t.string)) != NULL) { |
v = hash_search(ahash, t_string); |
1190 |
|
if (v != NULL) { |
1191 |
cn->info = OC_FNARG; |
cn->info = OC_FNARG; |
1192 |
cn->l.i = v->x.aidx; |
cn->l.i = v->x.aidx; |
1193 |
} else { |
} else { |
1194 |
cn->l.v = newvar(t.string); |
cn->l.v = newvar(t_string); |
1195 |
} |
} |
1196 |
if (tc & TC_ARRAY) { |
if (tc & TC_ARRAY) { |
1197 |
cn->info |= xS; |
cn->info |= xS; |
1204 |
cn->info = OC_VAR; |
cn->info = OC_VAR; |
1205 |
v = cn->l.v = xzalloc(sizeof(var)); |
v = cn->l.v = xzalloc(sizeof(var)); |
1206 |
if (tc & TC_NUMBER) |
if (tc & TC_NUMBER) |
1207 |
setvar_i(v, t.number); |
setvar_i(v, t_double); |
1208 |
else |
else |
1209 |
setvar_s(v, t.string); |
setvar_s(v, t_string); |
1210 |
break; |
break; |
1211 |
|
|
1212 |
case TC_REGEXP: |
case TC_REGEXP: |
1213 |
mk_re_node(t.string, cn, xzalloc(sizeof(regex_t)*2)); |
mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2)); |
1214 |
break; |
break; |
1215 |
|
|
1216 |
case TC_FUNCTION: |
case TC_FUNCTION: |
1217 |
cn->info = OC_FUNC; |
cn->info = OC_FUNC; |
1218 |
cn->r.f = newfunc(t.string); |
cn->r.f = newfunc(t_string); |
1219 |
cn->l.n = condition(); |
cn->l.n = condition(); |
1220 |
break; |
break; |
1221 |
|
|
1244 |
{ |
{ |
1245 |
node *n; |
node *n; |
1246 |
|
|
1247 |
if (! seq->first) |
if (!seq->first) |
1248 |
seq->first = seq->last = new_node(0); |
seq->first = seq->last = new_node(0); |
1249 |
|
|
1250 |
if (seq->programname != programname) { |
if (seq->programname != g_progname) { |
1251 |
seq->programname = programname; |
seq->programname = g_progname; |
1252 |
n = chain_node(OC_NEWSOURCE); |
n = chain_node(OC_NEWSOURCE); |
1253 |
n->l.s = xstrdup(programname); |
n->l.s = xstrdup(g_progname); |
1254 |
} |
} |
1255 |
|
|
1256 |
n = seq->last; |
n = seq->last; |
1266 |
|
|
1267 |
n = chain_node(info); |
n = chain_node(info); |
1268 |
n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM); |
n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM); |
1269 |
if (t.tclass & TC_GRPTERM) |
if (t_tclass & TC_GRPTERM) |
1270 |
rollback_token(); |
rollback_token(); |
1271 |
} |
} |
1272 |
|
|
1305 |
|
|
1306 |
if (c & TC_GRPSTART) { |
if (c & TC_GRPSTART) { |
1307 |
while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { |
while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { |
1308 |
if (t.tclass & TC_NEWLINE) continue; |
if (t_tclass & TC_NEWLINE) continue; |
1309 |
rollback_token(); |
rollback_token(); |
1310 |
chain_group(); |
chain_group(); |
1311 |
} |
} |
1313 |
rollback_token(); |
rollback_token(); |
1314 |
chain_expr(OC_EXEC | Vx); |
chain_expr(OC_EXEC | Vx); |
1315 |
} else { /* TC_STATEMNT */ |
} else { /* TC_STATEMNT */ |
1316 |
switch (t.info & OPCLSMASK) { |
switch (t_info & OPCLSMASK) { |
1317 |
case ST_IF: |
case ST_IF: |
1318 |
n = chain_node(OC_BR | Vx); |
n = chain_node(OC_BR | Vx); |
1319 |
n->l.n = condition(); |
n->l.n = condition(); |
1320 |
|
chain_group(); |
1321 |
|
n2 = chain_node(OC_EXEC); |
1322 |
|
n->r.n = seq->last; |
1323 |
|
if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) { |
1324 |
chain_group(); |
chain_group(); |
1325 |
n2 = chain_node(OC_EXEC); |
n2->a.n = seq->last; |
1326 |
n->r.n = seq->last; |
} else { |
1327 |
if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE)==TC_ELSE) { |
rollback_token(); |
1328 |
chain_group(); |
} |
1329 |
n2->a.n = seq->last; |
break; |
|
} else { |
|
|
rollback_token(); |
|
|
} |
|
|
break; |
|
1330 |
|
|
1331 |
case ST_WHILE: |
case ST_WHILE: |
1332 |
n2 = condition(); |
n2 = condition(); |
1333 |
|
n = chain_loop(NULL); |
1334 |
|
n->l.n = n2; |
1335 |
|
break; |
1336 |
|
|
1337 |
|
case ST_DO: |
1338 |
|
n2 = chain_node(OC_EXEC); |
1339 |
|
n = chain_loop(NULL); |
1340 |
|
n2->a.n = n->a.n; |
1341 |
|
next_token(TC_WHILE); |
1342 |
|
n->l.n = condition(); |
1343 |
|
break; |
1344 |
|
|
1345 |
|
case ST_FOR: |
1346 |
|
next_token(TC_SEQSTART); |
1347 |
|
n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); |
1348 |
|
if (t_tclass & TC_SEQTERM) { /* for-in */ |
1349 |
|
if ((n2->info & OPCLSMASK) != OC_IN) |
1350 |
|
syntax_error(EMSG_UNEXP_TOKEN); |
1351 |
|
n = chain_node(OC_WALKINIT | VV); |
1352 |
|
n->l.n = n2->l.n; |
1353 |
|
n->r.n = n2->r.n; |
1354 |
n = chain_loop(NULL); |
n = chain_loop(NULL); |
1355 |
|
n->info = OC_WALKNEXT | Vx; |
1356 |
|
n->l.n = n2->l.n; |
1357 |
|
} else { /* for (;;) */ |
1358 |
|
n = chain_node(OC_EXEC | Vx); |
1359 |
n->l.n = n2; |
n->l.n = n2; |
1360 |
break; |
n2 = parse_expr(TC_SEMICOL); |
1361 |
|
n3 = parse_expr(TC_SEQTERM); |
1362 |
|
n = chain_loop(n3); |
1363 |
|
n->l.n = n2; |
1364 |
|
if (!n2) |
1365 |
|
n->info = OC_EXEC; |
1366 |
|
} |
1367 |
|
break; |
1368 |
|
|
1369 |
case ST_DO: |
case OC_PRINT: |
1370 |
n2 = chain_node(OC_EXEC); |
case OC_PRINTF: |
1371 |
n = chain_loop(NULL); |
n = chain_node(t_info); |
1372 |
n2->a.n = n->a.n; |
n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM); |
1373 |
next_token(TC_WHILE); |
if (t_tclass & TC_OUTRDR) { |
1374 |
n->l.n = condition(); |
n->info |= t_info; |
1375 |
break; |
n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM); |
1376 |
|
} |
1377 |
case ST_FOR: |
if (t_tclass & TC_GRPTERM) |
1378 |
next_token(TC_SEQSTART); |
rollback_token(); |
1379 |
n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); |
break; |
1380 |
if (t.tclass & TC_SEQTERM) { /* for-in */ |
|
1381 |
if ((n2->info & OPCLSMASK) != OC_IN) |
case OC_BREAK: |
1382 |
syntax_error(EMSG_UNEXP_TOKEN); |
n = chain_node(OC_EXEC); |
1383 |
n = chain_node(OC_WALKINIT | VV); |
n->a.n = break_ptr; |
1384 |
n->l.n = n2->l.n; |
break; |
|
n->r.n = n2->r.n; |
|
|
n = chain_loop(NULL); |
|
|
n->info = OC_WALKNEXT | Vx; |
|
|
n->l.n = n2->l.n; |
|
|
} else { /* for (;;) */ |
|
|
n = chain_node(OC_EXEC | Vx); |
|
|
n->l.n = n2; |
|
|
n2 = parse_expr(TC_SEMICOL); |
|
|
n3 = parse_expr(TC_SEQTERM); |
|
|
n = chain_loop(n3); |
|
|
n->l.n = n2; |
|
|
if (! n2) |
|
|
n->info = OC_EXEC; |
|
|
} |
|
|
break; |
|
1385 |
|
|
1386 |
case OC_PRINT: |
case OC_CONTINUE: |
1387 |
case OC_PRINTF: |
n = chain_node(OC_EXEC); |
1388 |
n = chain_node(t.info); |
n->a.n = continue_ptr; |
1389 |
n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM); |
break; |
1390 |
if (t.tclass & TC_OUTRDR) { |
|
1391 |
n->info |= t.info; |
/* delete, next, nextfile, return, exit */ |
1392 |
n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM); |
default: |
1393 |
} |
chain_expr(t_info); |
|
if (t.tclass & TC_GRPTERM) |
|
|
rollback_token(); |
|
|
break; |
|
|
|
|
|
case OC_BREAK: |
|
|
n = chain_node(OC_EXEC); |
|
|
n->a.n = break_ptr; |
|
|
break; |
|
|
|
|
|
case OC_CONTINUE: |
|
|
n = chain_node(OC_EXEC); |
|
|
n->a.n = continue_ptr; |
|
|
break; |
|
|
|
|
|
/* delete, next, nextfile, return, exit */ |
|
|
default: |
|
|
chain_expr(t.info); |
|
1394 |
} |
} |
1395 |
} |
} |
1396 |
} |
} |
1402 |
func *f; |
func *f; |
1403 |
var *v; |
var *v; |
1404 |
|
|
1405 |
pos = p; |
g_pos = p; |
1406 |
t.lineno = 1; |
t_lineno = 1; |
1407 |
while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | |
while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | |
1408 |
TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) { |
TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) { |
1409 |
|
|
1410 |
if (tclass & TC_OPTERM) |
if (tclass & TC_OPTERM) |
1411 |
continue; |
continue; |
1421 |
|
|
1422 |
} else if (tclass & TC_FUNCDECL) { |
} else if (tclass & TC_FUNCDECL) { |
1423 |
next_token(TC_FUNCTION); |
next_token(TC_FUNCTION); |
1424 |
pos++; |
g_pos++; |
1425 |
f = newfunc(t.string); |
f = newfunc(t_string); |
1426 |
f->body.first = NULL; |
f->body.first = NULL; |
1427 |
f->nargs = 0; |
f->nargs = 0; |
1428 |
while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { |
while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { |
1429 |
v = findvar(ahash, t.string); |
v = findvar(ahash, t_string); |
1430 |
v->x.aidx = (f->nargs)++; |
v->x.aidx = (f->nargs)++; |
1431 |
|
|
1432 |
if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) |
if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) |
1440 |
rollback_token(); |
rollback_token(); |
1441 |
cn = chain_node(OC_TEST); |
cn = chain_node(OC_TEST); |
1442 |
cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); |
cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); |
1443 |
if (t.tclass & TC_GRPSTART) { |
if (t_tclass & TC_GRPSTART) { |
1444 |
rollback_token(); |
rollback_token(); |
1445 |
chain_group(); |
chain_group(); |
1446 |
} else { |
} else { |
1458 |
|
|
1459 |
/* -------- program execution part -------- */ |
/* -------- program execution part -------- */ |
1460 |
|
|
1461 |
static node *mk_splitter(char *s, tsplitter *spl) |
static node *mk_splitter(const char *s, tsplitter *spl) |
1462 |
{ |
{ |
1463 |
regex_t *re, *ire; |
regex_t *re, *ire; |
1464 |
node *n; |
node *n; |
1468 |
n = &spl->n; |
n = &spl->n; |
1469 |
if ((n->info & OPCLSMASK) == OC_REGEXP) { |
if ((n->info & OPCLSMASK) == OC_REGEXP) { |
1470 |
regfree(re); |
regfree(re); |
1471 |
regfree(ire); |
regfree(ire); // TODO: nuke ire, use re+1? |
1472 |
} |
} |
1473 |
if (strlen(s) > 1) { |
if (strlen(s) > 1) { |
1474 |
mk_re_node(s, n, re); |
mk_re_node(s, n, re); |
1486 |
static regex_t *as_regex(node *op, regex_t *preg) |
static regex_t *as_regex(node *op, regex_t *preg) |
1487 |
{ |
{ |
1488 |
var *v; |
var *v; |
1489 |
char *s; |
const char *s; |
1490 |
|
|
1491 |
if ((op->info & OPCLSMASK) == OC_REGEXP) { |
if ((op->info & OPCLSMASK) == OC_REGEXP) { |
1492 |
return icase ? op->r.ire : op->l.re; |
return icase ? op->r.ire : op->l.re; |
|
} else { |
|
|
v = nvalloc(1); |
|
|
s = getvar_s(evaluate(op, v)); |
|
|
xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED); |
|
|
nvfree(v); |
|
|
return preg; |
|
1493 |
} |
} |
1494 |
|
v = nvalloc(1); |
1495 |
|
s = getvar_s(evaluate(op, v)); |
1496 |
|
xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED); |
1497 |
|
nvfree(v); |
1498 |
|
return preg; |
1499 |
} |
} |
1500 |
|
|
1501 |
/* gradually increasing buffer */ |
/* gradually increasing buffer */ |
1502 |
static void qrealloc(char **b, int n, int *size) |
static void qrealloc(char **b, int n, int *size) |
1503 |
{ |
{ |
1504 |
if (!*b || n >= *size) |
if (!*b || n >= *size) { |
1505 |
*b = xrealloc(*b, *size = n + (n>>1) + 80); |
*size = n + (n>>1) + 80; |
1506 |
|
*b = xrealloc(*b, *size); |
1507 |
|
} |
1508 |
} |
} |
1509 |
|
|
1510 |
/* resize field storage space */ |
/* resize field storage space */ |
1511 |
static void fsrealloc(int size) |
static void fsrealloc(int size) |
1512 |
{ |
{ |
|
static int maxfields; /* = 0;*/ |
|
1513 |
int i; |
int i; |
1514 |
|
|
1515 |
if (size >= maxfields) { |
if (size >= maxfields) { |
1530 |
nfields = size; |
nfields = size; |
1531 |
} |
} |
1532 |
|
|
1533 |
static int awk_split(char *s, node *spl, char **slist) |
static int awk_split(const char *s, node *spl, char **slist) |
1534 |
{ |
{ |
1535 |
int l, n = 0; |
int l, n = 0; |
1536 |
char c[4]; |
char c[4]; |
1537 |
char *s1; |
char *s1; |
1538 |
regmatch_t pmatch[2]; |
regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... |
1539 |
|
|
1540 |
/* in worst case, each char would be a separate field */ |
/* in worst case, each char would be a separate field */ |
1541 |
*slist = s1 = xstrndup(s, strlen(s) * 2 + 3); |
*slist = s1 = xzalloc(strlen(s) * 2 + 3); |
1542 |
|
strcpy(s1, s); |
1543 |
|
|
1544 |
c[0] = c[1] = (char)spl->info; |
c[0] = c[1] = (char)spl->info; |
1545 |
c[2] = c[3] = '\0'; |
c[2] = c[3] = '\0'; |
1546 |
if (*getvar_s(V[RS]) == '\0') c[2] = '\n'; |
if (*getvar_s(intvar[RS]) == '\0') |
1547 |
|
c[2] = '\n'; |
1548 |
|
|
1549 |
if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */ |
if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */ |
1550 |
while (*s) { |
if (!*s) |
1551 |
l = strcspn(s, c+2); |
return n; /* "": zero fields */ |
1552 |
if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0 && |
n++; /* at least one field will be there */ |
1553 |
pmatch[0].rm_so <= l) { |
do { |
1554 |
|
l = strcspn(s, c+2); /* len till next NUL or \n */ |
1555 |
|
if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0 |
1556 |
|
&& pmatch[0].rm_so <= l |
1557 |
|
) { |
1558 |
l = pmatch[0].rm_so; |
l = pmatch[0].rm_so; |
1559 |
if (pmatch[0].rm_eo == 0) { l++; pmatch[0].rm_eo++; } |
if (pmatch[0].rm_eo == 0) { |
1560 |
|
l++; |
1561 |
|
pmatch[0].rm_eo++; |
1562 |
|
} |
1563 |
|
n++; /* we saw yet another delimiter */ |
1564 |
} else { |
} else { |
1565 |
pmatch[0].rm_eo = l; |
pmatch[0].rm_eo = l; |
1566 |
if (s[l]) pmatch[0].rm_eo++; |
if (s[l]) pmatch[0].rm_eo++; |
1567 |
} |
} |
|
|
|
1568 |
memcpy(s1, s, l); |
memcpy(s1, s, l); |
1569 |
s1[l] = '\0'; |
s1[l] = '\0'; |
1570 |
nextword(&s1); |
nextword(&s1); |
1571 |
s += pmatch[0].rm_eo; |
s += pmatch[0].rm_eo; |
1572 |
n++; |
} while (*s); |
1573 |
} |
return n; |
1574 |
} else if (c[0] == '\0') { /* null split */ |
} |
1575 |
|
if (c[0] == '\0') { /* null split */ |
1576 |
while (*s) { |
while (*s) { |
1577 |
*s1++ = *s++; |
*s1++ = *s++; |
1578 |
*s1++ = '\0'; |
*s1++ = '\0'; |
1579 |
n++; |
n++; |
1580 |
} |
} |
1581 |
} else if (c[0] != ' ') { /* single-character split */ |
return n; |
1582 |
|
} |
1583 |
|
if (c[0] != ' ') { /* single-character split */ |
1584 |
if (icase) { |
if (icase) { |
1585 |
c[0] = toupper(c[0]); |
c[0] = toupper(c[0]); |
1586 |
c[1] = tolower(c[1]); |
c[1] = tolower(c[1]); |
1590 |
*s1++ = '\0'; |
*s1++ = '\0'; |
1591 |
n++; |
n++; |
1592 |
} |
} |
1593 |
} else { /* space split */ |
return n; |
1594 |
while (*s) { |
} |
1595 |
s = skip_whitespace(s); |
/* space split */ |
1596 |
if (!*s) break; |
while (*s) { |
1597 |
n++; |
s = skip_whitespace(s); |
1598 |
while (*s && !isspace(*s)) |
if (!*s) break; |
1599 |
*s1++ = *s++; |
n++; |
1600 |
*s1++ = '\0'; |
while (*s && !isspace(*s)) |
1601 |
} |
*s1++ = *s++; |
1602 |
|
*s1++ = '\0'; |
1603 |
} |
} |
1604 |
return n; |
return n; |
1605 |
} |
} |
1606 |
|
|
1607 |
static void split_f0(void) |
static void split_f0(void) |
1608 |
{ |
{ |
1609 |
static char *fstrings = NULL; |
/* static char *fstrings; */ |
1610 |
|
#define fstrings (G.split_f0__fstrings) |
1611 |
|
|
1612 |
int i, n; |
int i, n; |
1613 |
char *s; |
char *s; |
1614 |
|
|
1618 |
is_f0_split = TRUE; |
is_f0_split = TRUE; |
1619 |
free(fstrings); |
free(fstrings); |
1620 |
fsrealloc(0); |
fsrealloc(0); |
1621 |
n = awk_split(getvar_s(V[F0]), &fsplitter.n, &fstrings); |
n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings); |
1622 |
fsrealloc(n); |
fsrealloc(n); |
1623 |
s = fstrings; |
s = fstrings; |
1624 |
for (i = 0; i < n; i++) { |
for (i = 0; i < n; i++) { |
1627 |
} |
} |
1628 |
|
|
1629 |
/* set NF manually to avoid side effects */ |
/* set NF manually to avoid side effects */ |
1630 |
clrvar(V[NF]); |
clrvar(intvar[NF]); |
1631 |
V[NF]->type = VF_NUMBER | VF_SPECIAL; |
intvar[NF]->type = VF_NUMBER | VF_SPECIAL; |
1632 |
V[NF]->number = nfields; |
intvar[NF]->number = nfields; |
1633 |
|
#undef fstrings |
1634 |
} |
} |
1635 |
|
|
1636 |
/* perform additional actions when some internal variables changed */ |
/* perform additional actions when some internal variables changed */ |
1637 |
static void handle_special(var *v) |
static void handle_special(var *v) |
1638 |
{ |
{ |
1639 |
int n; |
int n; |
1640 |
char *b, *sep, *s; |
char *b; |
1641 |
|
const char *sep, *s; |
1642 |
int sl, l, len, i, bsize; |
int sl, l, len, i, bsize; |
1643 |
|
|
1644 |
if (!(v->type & VF_SPECIAL)) |
if (!(v->type & VF_SPECIAL)) |
1645 |
return; |
return; |
1646 |
|
|
1647 |
if (v == V[NF]) { |
if (v == intvar[NF]) { |
1648 |
n = (int)getvar_i(v); |
n = (int)getvar_i(v); |
1649 |
fsrealloc(n); |
fsrealloc(n); |
1650 |
|
|
1651 |
/* recalculate $0 */ |
/* recalculate $0 */ |
1652 |
sep = getvar_s(V[OFS]); |
sep = getvar_s(intvar[OFS]); |
1653 |
sl = strlen(sep); |
sl = strlen(sep); |
1654 |
b = NULL; |
b = NULL; |
1655 |
len = 0; |
len = 0; |
1656 |
for (i=0; i<n; i++) { |
for (i = 0; i < n; i++) { |
1657 |
s = getvar_s(&Fields[i]); |
s = getvar_s(&Fields[i]); |
1658 |
l = strlen(s); |
l = strlen(s); |
1659 |
if (b) { |
if (b) { |
1666 |
} |
} |
1667 |
if (b) |
if (b) |
1668 |
b[len] = '\0'; |
b[len] = '\0'; |
1669 |
setvar_p(V[F0], b); |
setvar_p(intvar[F0], b); |
1670 |
is_f0_split = TRUE; |
is_f0_split = TRUE; |
1671 |
|
|
1672 |
} else if (v == V[F0]) { |
} else if (v == intvar[F0]) { |
1673 |
is_f0_split = FALSE; |
is_f0_split = FALSE; |
1674 |
|
|
1675 |
} else if (v == V[FS]) { |
} else if (v == intvar[FS]) { |
1676 |
mk_splitter(getvar_s(v), &fsplitter); |
mk_splitter(getvar_s(v), &fsplitter); |
1677 |
|
|
1678 |
} else if (v == V[RS]) { |
} else if (v == intvar[RS]) { |
1679 |
mk_splitter(getvar_s(v), &rsplitter); |
mk_splitter(getvar_s(v), &rsplitter); |
1680 |
|
|
1681 |
} else if (v == V[IGNORECASE]) { |
} else if (v == intvar[IGNORECASE]) { |
1682 |
icase = istrue(v); |
icase = istrue(v); |
1683 |
|
|
1684 |
} else { /* $n */ |
} else { /* $n */ |
1685 |
n = getvar_i(V[NF]); |
n = getvar_i(intvar[NF]); |
1686 |
setvar_i(V[NF], n > v-Fields ? n : v-Fields+1); |
setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1); |
1687 |
/* right here v is invalid. Just to note... */ |
/* right here v is invalid. Just to note... */ |
1688 |
} |
} |
1689 |
} |
} |
1707 |
{ |
{ |
1708 |
char **w; |
char **w; |
1709 |
hash_item *hi; |
hash_item *hi; |
1710 |
int i; |
unsigned i; |
1711 |
|
|
1712 |
if (v->type & VF_WALK) |
if (v->type & VF_WALK) |
1713 |
free(v->x.walker); |
free(v->x.walker); |
1714 |
|
|
1715 |
v->type |= VF_WALK; |
v->type |= VF_WALK; |
1716 |
w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen); |
w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen); |
1717 |
*w = *(w+1) = (char *)(w + 2); |
w[0] = w[1] = (char *)(w + 2); |
1718 |
for (i=0; i<array->csize; i++) { |
for (i = 0; i < array->csize; i++) { |
1719 |
hi = array->items[i]; |
hi = array->items[i]; |
1720 |
while (hi) { |
while (hi) { |
1721 |
strcpy(*w, hi->name); |
strcpy(*w, hi->name); |
1730 |
char **w; |
char **w; |
1731 |
|
|
1732 |
w = v->x.walker; |
w = v->x.walker; |
1733 |
if (*(w+1) == *w) |
if (w[1] == w[0]) |
1734 |
return FALSE; |
return FALSE; |
1735 |
|
|
1736 |
setvar_s(v, nextword(w+1)); |
setvar_s(v, nextword(w+1)); |
1740 |
/* evaluate node, return 1 when result is true, 0 otherwise */ |
/* evaluate node, return 1 when result is true, 0 otherwise */ |
1741 |
static int ptest(node *pattern) |
static int ptest(node *pattern) |
1742 |
{ |
{ |
1743 |
static var v; /* static: to save stack space? */ |
/* ptest__v is "static": to save stack space? */ |
1744 |
|
return istrue(evaluate(pattern, &G.ptest__v)); |
|
return istrue(evaluate(pattern, &v)); |
|
1745 |
} |
} |
1746 |
|
|
1747 |
/* read next record from stream rsm into a variable v */ |
/* read next record from stream rsm into a variable v */ |
1764 |
c = (char) rsplitter.n.info; |
c = (char) rsplitter.n.info; |
1765 |
rp = 0; |
rp = 0; |
1766 |
|
|
1767 |
if (! m) qrealloc(&m, 256, &size); |
if (!m) qrealloc(&m, 256, &size); |
1768 |
do { |
do { |
1769 |
b = m + a; |
b = m + a; |
1770 |
so = eo = p; |
so = eo = p; |
1772 |
if (p > 0) { |
if (p > 0) { |
1773 |
if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) { |
if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) { |
1774 |
if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re, |
if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re, |
1775 |
b, 1, pmatch, 0) == 0) { |
b, 1, pmatch, 0) == 0) { |
1776 |
so = pmatch[0].rm_so; |
so = pmatch[0].rm_so; |
1777 |
eo = pmatch[0].rm_eo; |
eo = pmatch[0].rm_eo; |
1778 |
if (b[eo] != '\0') |
if (b[eo] != '\0') |
1780 |
} |
} |
1781 |
} else if (c != '\0') { |
} else if (c != '\0') { |
1782 |
s = strchr(b+pp, c); |
s = strchr(b+pp, c); |
1783 |
if (! s) s = memchr(b+pp, '\0', p - pp); |
if (!s) s = memchr(b+pp, '\0', p - pp); |
1784 |
if (s) { |
if (s) { |
1785 |
so = eo = s-b; |
so = eo = s-b; |
1786 |
eo++; |
eo++; |
1812 |
if (p < pp) { |
if (p < pp) { |
1813 |
p = 0; |
p = 0; |
1814 |
r = 0; |
r = 0; |
1815 |
setvar_i(V[ERRNO], errno); |
setvar_i(intvar[ERRNO], errno); |
1816 |
} |
} |
1817 |
b[p] = '\0'; |
b[p] = '\0'; |
1818 |
|
|
1826 |
v->type |= VF_USER; |
v->type |= VF_USER; |
1827 |
b[so] = c; |
b[so] = c; |
1828 |
c = b[eo]; b[eo] = '\0'; |
c = b[eo]; b[eo] = '\0'; |
1829 |
setvar_s(V[RT], b+so); |
setvar_s(intvar[RT], b+so); |
1830 |
b[eo] = c; |
b[eo] = c; |
1831 |
} |
} |
1832 |
|
|
1853 |
} else if (strchr("eEfgG", c)) { |
} else if (strchr("eEfgG", c)) { |
1854 |
r = snprintf(b, size, format, n); |
r = snprintf(b, size, format, n); |
1855 |
} else { |
} else { |
1856 |
runtime_error(EMSG_INV_FMT); |
syntax_error(EMSG_INV_FMT); |
1857 |
} |
} |
1858 |
} |
} |
1859 |
return r; |
return r; |
1864 |
static char *awk_printf(node *n) |
static char *awk_printf(node *n) |
1865 |
{ |
{ |
1866 |
char *b = NULL; |
char *b = NULL; |
1867 |
char *fmt, *s, *s1, *f; |
char *fmt, *s, *f; |
1868 |
|
const char *s1; |
1869 |
int i, j, incr, bsize; |
int i, j, incr, bsize; |
1870 |
char c, c1; |
char c, c1; |
1871 |
var *v, *arg; |
var *v, *arg; |
1878 |
s = f; |
s = f; |
1879 |
while (*f && (*f != '%' || *(++f) == '%')) |
while (*f && (*f != '%' || *(++f) == '%')) |
1880 |
f++; |
f++; |
1881 |
while (*f && !isalpha(*f)) |
while (*f && !isalpha(*f)) { |
1882 |
|
if (*f == '*') |
1883 |
|
syntax_error("%*x formats are not supported"); |
1884 |
f++; |
f++; |
1885 |
|
} |
1886 |
|
|
1887 |
incr = (f - s) + MAXVARFMT; |
incr = (f - s) + MAXVARFMT; |
1888 |
qrealloc(&b, incr + i, &bsize); |
qrealloc(&b, incr + i, &bsize); |
1896 |
if (c == 'c' || !c) { |
if (c == 'c' || !c) { |
1897 |
i += sprintf(b+i, s, is_numeric(arg) ? |
i += sprintf(b+i, s, is_numeric(arg) ? |
1898 |
(char)getvar_i(arg) : *getvar_s(arg)); |
(char)getvar_i(arg) : *getvar_s(arg)); |
|
|
|
1899 |
} else if (c == 's') { |
} else if (c == 's') { |
1900 |
s1 = getvar_s(arg); |
s1 = getvar_s(arg); |
1901 |
qrealloc(&b, incr+i+strlen(s1), &bsize); |
qrealloc(&b, incr+i+strlen(s1), &bsize); |
1902 |
i += sprintf(b+i, s, s1); |
i += sprintf(b+i, s, s1); |
|
|
|
1903 |
} else { |
} else { |
1904 |
i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE); |
i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE); |
1905 |
} |
} |
1922 |
* all matches. If src or dst is NULL, use $0. If ex=TRUE, enable |
* all matches. If src or dst is NULL, use $0. If ex=TRUE, enable |
1923 |
* subexpression matching (\1-\9) |
* subexpression matching (\1-\9) |
1924 |
*/ |
*/ |
1925 |
static int awk_sub(node *rn, char *repl, int nm, var *src, var *dest, int ex) |
static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex) |
1926 |
{ |
{ |
1927 |
char *ds = NULL; |
char *ds = NULL; |
1928 |
char *sp, *s; |
const char *s; |
1929 |
|
const char *sp; |
1930 |
int c, i, j, di, rl, so, eo, nbs, n, dssize; |
int c, i, j, di, rl, so, eo, nbs, n, dssize; |
1931 |
regmatch_t pmatch[10]; |
regmatch_t pmatch[10]; |
1932 |
regex_t sreg, *re; |
regex_t sreg, *re; |
1933 |
|
|
1934 |
re = as_regex(rn, &sreg); |
re = as_regex(rn, &sreg); |
1935 |
if (! src) src = V[F0]; |
if (!src) src = intvar[F0]; |
1936 |
if (! dest) dest = V[F0]; |
if (!dest) dest = intvar[F0]; |
1937 |
|
|
1938 |
i = di = 0; |
i = di = 0; |
1939 |
sp = getvar_s(src); |
sp = getvar_s(src); |
1940 |
rl = strlen(repl); |
rl = strlen(repl); |
1941 |
while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0:REG_NOTBOL) == 0) { |
while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) { |
1942 |
so = pmatch[0].rm_so; |
so = pmatch[0].rm_so; |
1943 |
eo = pmatch[0].rm_eo; |
eo = pmatch[0].rm_eo; |
1944 |
|
|
1978 |
sp += eo; |
sp += eo; |
1979 |
if (i == nm) break; |
if (i == nm) break; |
1980 |
if (eo == so) { |
if (eo == so) { |
1981 |
if (! (ds[di++] = *sp++)) break; |
ds[di] = *sp++; |
1982 |
|
if (!ds[di++]) break; |
1983 |
} |
} |
1984 |
} |
} |
1985 |
|
|
1992 |
|
|
1993 |
static var *exec_builtin(node *op, var *res) |
static var *exec_builtin(node *op, var *res) |
1994 |
{ |
{ |
1995 |
|
#define tspl (G.exec_builtin__tspl) |
1996 |
|
|
1997 |
int (*to_xxx)(int); |
int (*to_xxx)(int); |
1998 |
var *tv; |
var *tv; |
1999 |
node *an[4]; |
node *an[4]; |
2000 |
var *av[4]; |
var *av[4]; |
2001 |
char *as[4]; |
const char *as[4]; |
2002 |
regmatch_t pmatch[2]; |
regmatch_t pmatch[2]; |
2003 |
regex_t sreg, *re; |
regex_t sreg, *re; |
|
static tsplitter tspl; |
|
2004 |
node *spl; |
node *spl; |
2005 |
uint32_t isr, info; |
uint32_t isr, info; |
2006 |
int nargs; |
int nargs; |
2013 |
op = op->l.n; |
op = op->l.n; |
2014 |
|
|
2015 |
av[2] = av[3] = NULL; |
av[2] = av[3] = NULL; |
2016 |
for (i=0 ; i<4 && op ; i++) { |
for (i = 0; i < 4 && op; i++) { |
2017 |
an[i] = nextarg(&op); |
an[i] = nextarg(&op); |
2018 |
if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]); |
if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]); |
2019 |
if (isr & 0x08000000) as[i] = getvar_s(av[i]); |
if (isr & 0x08000000) as[i] = getvar_s(av[i]); |
2021 |
} |
} |
2022 |
|
|
2023 |
nargs = i; |
nargs = i; |
2024 |
if (nargs < (info >> 30)) |
if ((uint32_t)nargs < (info >> 30)) |
2025 |
runtime_error(EMSG_TOO_FEW_ARGS); |
syntax_error(EMSG_TOO_FEW_ARGS); |
2026 |
|
|
2027 |
switch (info & OPNMASK) { |
switch (info & OPNMASK) { |
2028 |
|
|
2029 |
case B_a2: |
case B_a2: |
2030 |
#if ENABLE_FEATURE_AWK_MATH |
#if ENABLE_FEATURE_AWK_LIBM |
2031 |
setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1]))); |
setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1]))); |
2032 |
#else |
#else |
2033 |
runtime_error(EMSG_NO_MATH); |
syntax_error(EMSG_NO_MATH); |
2034 |
#endif |
#endif |
2035 |
break; |
break; |
2036 |
|
|
2045 |
n = awk_split(as[0], spl, &s); |
n = awk_split(as[0], spl, &s); |
2046 |
s1 = s; |
s1 = s; |
2047 |
clear_array(iamarray(av[1])); |
clear_array(iamarray(av[1])); |
2048 |
for (i=1; i<=n; i++) |
for (i = 1; i <= n; i++) |
2049 |
setari_u(av[1], i, nextword(&s1)); |
setari_u(av[1], i, nextword(&s1)); |
2050 |
free(s); |
free(s); |
2051 |
setvar_i(res, n); |
setvar_i(res, n); |
2054 |
case B_ss: |
case B_ss: |
2055 |
l = strlen(as[0]); |
l = strlen(as[0]); |
2056 |
i = getvar_i(av[1]) - 1; |
i = getvar_i(av[1]) - 1; |
2057 |
if (i>l) i=l; if (i<0) i=0; |
if (i > l) i = l; |
2058 |
|
if (i < 0) i = 0; |
2059 |
n = (nargs > 2) ? getvar_i(av[2]) : l-i; |
n = (nargs > 2) ? getvar_i(av[2]) : l-i; |
2060 |
if (n<0) n=0; |
if (n < 0) n = 0; |
2061 |
s = xmalloc(n+1); |
s = xstrndup(as[0]+i, n); |
|
strncpy(s, as[0]+i, n); |
|
|
s[n] = '\0'; |
|
2062 |
setvar_p(res, s); |
setvar_p(res, s); |
2063 |
break; |
break; |
2064 |
|
|
2065 |
|
/* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5: |
2066 |
|
* awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */ |
2067 |
case B_an: |
case B_an: |
2068 |
setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1])); |
setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1])); |
2069 |
break; |
break; |
2070 |
|
|
2071 |
case B_co: |
case B_co: |
2072 |
setvar_i(res, ~(long)getvar_i(av[0])); |
setvar_i(res, ~getvar_i_int(av[0])); |
2073 |
break; |
break; |
2074 |
|
|
2075 |
case B_ls: |
case B_ls: |
2076 |
setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1])); |
setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1])); |
2077 |
break; |
break; |
2078 |
|
|
2079 |
case B_or: |
case B_or: |
2080 |
setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1])); |
setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1])); |
2081 |
break; |
break; |
2082 |
|
|
2083 |
case B_rs: |
case B_rs: |
2084 |
setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1]))); |
setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1])); |
2085 |
break; |
break; |
2086 |
|
|
2087 |
case B_xo: |
case B_xo: |
2088 |
setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1])); |
setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1])); |
2089 |
break; |
break; |
2090 |
|
|
2091 |
case B_lo: |
case B_lo: |
2108 |
ll = strlen(as[1]); |
ll = strlen(as[1]); |
2109 |
l = strlen(as[0]) - ll; |
l = strlen(as[0]) - ll; |
2110 |
if (ll > 0 && l >= 0) { |
if (ll > 0 && l >= 0) { |
2111 |
if (! icase) { |
if (!icase) { |
2112 |
s = strstr(as[0], as[1]); |
s = strstr(as[0], as[1]); |
2113 |
if (s) n = (s - as[0]) + 1; |
if (s) n = (s - as[0]) + 1; |
2114 |
} else { |
} else { |
2131 |
tt = getvar_i(av[1]); |
tt = getvar_i(av[1]); |
2132 |
else |
else |
2133 |
time(&tt); |
time(&tt); |
2134 |
s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"; |
//s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"; |
2135 |
i = strftime(buf, MAXVARFMT, s, localtime(&tt)); |
i = strftime(g_buf, MAXVARFMT, |
2136 |
buf[i] = '\0'; |
((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"), |
2137 |
setvar_s(res, buf); |
localtime(&tt)); |
2138 |
|
g_buf[i] = '\0'; |
2139 |
|
setvar_s(res, g_buf); |
2140 |
break; |
break; |
2141 |
|
|
2142 |
case B_ma: |
case B_ma: |
2170 |
|
|
2171 |
nvfree(tv); |
nvfree(tv); |
2172 |
return res; |
return res; |
2173 |
|
#undef tspl |
2174 |
} |
} |
2175 |
|
|
2176 |
/* |
/* |
2181 |
|
|
2182 |
static var *evaluate(node *op, var *res) |
static var *evaluate(node *op, var *res) |
2183 |
{ |
{ |
2184 |
/* This procedure is recursive so we should count every byte */ |
/* This procedure is recursive so we should count every byte */ |
2185 |
static var *fnargs = NULL; |
#define fnargs (G.evaluate__fnargs) |
2186 |
static unsigned seed = 1; |
/* seed is initialized to 1 */ |
2187 |
static regex_t sreg; |
#define seed (G.evaluate__seed) |
2188 |
|
#define sreg (G.evaluate__sreg) |
2189 |
|
|
2190 |
node *op1; |
node *op1; |
2191 |
var *v1; |
var *v1; |
2192 |
union { |
union { |
2193 |
var *v; |
var *v; |
2194 |
char *s; |
const char *s; |
2195 |
double d; |
double d; |
2196 |
int i; |
int i; |
2197 |
} L, R; |
} L, R; |
2198 |
uint32_t opinfo; |
uint32_t opinfo; |
2199 |
short opn; |
int opn; |
2200 |
union { |
union { |
2201 |
char *s; |
char *s; |
2202 |
rstream *rsm; |
rstream *rsm; |
2212 |
v1 = nvalloc(2); |
v1 = nvalloc(2); |
2213 |
|
|
2214 |
while (op) { |
while (op) { |
|
|
|
2215 |
opinfo = op->info; |
opinfo = op->info; |
2216 |
opn = (short)(opinfo & OPNMASK); |
opn = (opinfo & OPNMASK); |
2217 |
lineno = op->lineno; |
g_lineno = op->lineno; |
2218 |
|
|
2219 |
/* execute inevitable things */ |
/* execute inevitable things */ |
2220 |
op1 = op->l.n; |
op1 = op->l.n; |
2226 |
|
|
2227 |
switch (XC(opinfo & OPCLSMASK)) { |
switch (XC(opinfo & OPCLSMASK)) { |
2228 |
|
|
2229 |
/* -- iterative node type -- */ |
/* -- iterative node type -- */ |
2230 |
|
|
2231 |
/* test pattern */ |
/* test pattern */ |
2232 |
case XC( OC_TEST ): |
case XC( OC_TEST ): |
2233 |
if ((op1->info & OPCLSMASK) == OC_COMMA) { |
if ((op1->info & OPCLSMASK) == OC_COMMA) { |
2234 |
/* it's range pattern */ |
/* it's range pattern */ |
2246 |
} |
} |
2247 |
break; |
break; |
2248 |
|
|
2249 |
/* just evaluate an expression, also used as unconditional jump */ |
/* just evaluate an expression, also used as unconditional jump */ |
2250 |
case XC( OC_EXEC ): |
case XC( OC_EXEC ): |
2251 |
break; |
break; |
2252 |
|
|
2253 |
/* branch, used in if-else and various loops */ |
/* branch, used in if-else and various loops */ |
2254 |
case XC( OC_BR ): |
case XC( OC_BR ): |
2255 |
op = istrue(L.v) ? op->a.n : op->r.n; |
op = istrue(L.v) ? op->a.n : op->r.n; |
2256 |
break; |
break; |
2257 |
|
|
2258 |
/* initialize for-in loop */ |
/* initialize for-in loop */ |
2259 |
case XC( OC_WALKINIT ): |
case XC( OC_WALKINIT ): |
2260 |
hashwalk_init(L.v, iamarray(R.v)); |
hashwalk_init(L.v, iamarray(R.v)); |
2261 |
break; |
break; |
2262 |
|
|
2263 |
/* get next array item */ |
/* get next array item */ |
2264 |
case XC( OC_WALKNEXT ): |
case XC( OC_WALKNEXT ): |
2265 |
op = hashwalk_next(L.v) ? op->a.n : op->r.n; |
op = hashwalk_next(L.v) ? op->a.n : op->r.n; |
2266 |
break; |
break; |
2270 |
X.F = stdout; |
X.F = stdout; |
2271 |
if (op->r.n) { |
if (op->r.n) { |
2272 |
X.rsm = newfile(R.s); |
X.rsm = newfile(R.s); |
2273 |
if (! X.rsm->F) { |
if (!X.rsm->F) { |
2274 |
if (opn == '|') { |
if (opn == '|') { |
2275 |
if((X.rsm->F = popen(R.s, "w")) == NULL) |
X.rsm->F = popen(R.s, "w"); |
2276 |
|
if (X.rsm->F == NULL) |
2277 |
bb_perror_msg_and_die("popen"); |
bb_perror_msg_and_die("popen"); |
2278 |
X.rsm->is_pipe = 1; |
X.rsm->is_pipe = 1; |
2279 |
} else { |
} else { |
2284 |
} |
} |
2285 |
|
|
2286 |
if ((opinfo & OPCLSMASK) == OC_PRINT) { |
if ((opinfo & OPCLSMASK) == OC_PRINT) { |
2287 |
if (! op1) { |
if (!op1) { |
2288 |
fputs(getvar_s(V[F0]), X.F); |
fputs(getvar_s(intvar[F0]), X.F); |
2289 |
} else { |
} else { |
2290 |
while (op1) { |
while (op1) { |
2291 |
L.v = evaluate(nextarg(&op1), v1); |
L.v = evaluate(nextarg(&op1), v1); |
2292 |
if (L.v->type & VF_NUMBER) { |
if (L.v->type & VF_NUMBER) { |
2293 |
fmt_num(buf, MAXVARFMT, getvar_s(V[OFMT]), |
fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]), |
2294 |
getvar_i(L.v), TRUE); |
getvar_i(L.v), TRUE); |
2295 |
fputs(buf, X.F); |
fputs(g_buf, X.F); |
2296 |
} else { |
} else { |
2297 |
fputs(getvar_s(L.v), X.F); |
fputs(getvar_s(L.v), X.F); |
2298 |
} |
} |
2299 |
|
|
2300 |
if (op1) fputs(getvar_s(V[OFS]), X.F); |
if (op1) fputs(getvar_s(intvar[OFS]), X.F); |
2301 |
} |
} |
2302 |
} |
} |
2303 |
fputs(getvar_s(V[ORS]), X.F); |
fputs(getvar_s(intvar[ORS]), X.F); |
2304 |
|
|
2305 |
} else { /* OC_PRINTF */ |
} else { /* OC_PRINTF */ |
2306 |
L.s = awk_printf(op1); |
L.s = awk_printf(op1); |
2307 |
fputs(L.s, X.F); |
fputs(L.s, X.F); |
2308 |
free(L.s); |
free((char*)L.s); |
2309 |
} |
} |
2310 |
fflush(X.F); |
fflush(X.F); |
2311 |
break; |
break; |
2317 |
} else if (X.info == OC_FNARG) { |
} else if (X.info == OC_FNARG) { |
2318 |
R.v = &fnargs[op1->l.i]; |
R.v = &fnargs[op1->l.i]; |
2319 |
} else { |
} else { |
2320 |
runtime_error(EMSG_NOT_ARRAY); |
syntax_error(EMSG_NOT_ARRAY); |
2321 |
} |
} |
2322 |
|
|
2323 |
if (op1->r.n) { |
if (op1->r.n) { |
2330 |
break; |
break; |
2331 |
|
|
2332 |
case XC( OC_NEWSOURCE ): |
case XC( OC_NEWSOURCE ): |
2333 |
programname = op->l.s; |
g_progname = op->l.s; |
2334 |
break; |
break; |
2335 |
|
|
2336 |
case XC( OC_RETURN ): |
case XC( OC_RETURN ): |
2348 |
case XC( OC_EXIT ): |
case XC( OC_EXIT ): |
2349 |
awk_exit(L.d); |
awk_exit(L.d); |
2350 |
|
|
2351 |
/* -- recursive node type -- */ |
/* -- recursive node type -- */ |
2352 |
|
|
2353 |
case XC( OC_VAR ): |
case XC( OC_VAR ): |
2354 |
L.v = op->l.v; |
L.v = op->l.v; |
2355 |
if (L.v == V[NF]) |
if (L.v == intvar[NF]) |
2356 |
split_f0(); |
split_f0(); |
2357 |
goto v_cont; |
goto v_cont; |
2358 |
|
|
2368 |
|
|
2369 |
case XC( OC_REGEXP ): |
case XC( OC_REGEXP ): |
2370 |
op1 = op; |
op1 = op; |
2371 |
L.s = getvar_s(V[F0]); |
L.s = getvar_s(intvar[F0]); |
2372 |
goto re_cont; |
goto re_cont; |
2373 |
|
|
2374 |
case XC( OC_MATCH ): |
case XC( OC_MATCH ): |
2392 |
|
|
2393 |
case XC( OC_TERNARY ): |
case XC( OC_TERNARY ): |
2394 |
if ((op->r.n->info & OPCLSMASK) != OC_COLON) |
if ((op->r.n->info & OPCLSMASK) != OC_COLON) |
2395 |
runtime_error(EMSG_POSSIBLE_ERROR); |
syntax_error(EMSG_POSSIBLE_ERROR); |
2396 |
res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); |
res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); |
2397 |
break; |
break; |
2398 |
|
|
2399 |
case XC( OC_FUNC ): |
case XC( OC_FUNC ): |
2400 |
if (! op->r.f->body.first) |
if (!op->r.f->body.first) |
2401 |
runtime_error(EMSG_UNDEF_FUNC); |
syntax_error(EMSG_UNDEF_FUNC); |
2402 |
|
|
2403 |
X.v = R.v = nvalloc(op->r.f->nargs+1); |
X.v = R.v = nvalloc(op->r.f->nargs+1); |
2404 |
while (op1) { |
while (op1) { |
2413 |
R.v = fnargs; |
R.v = fnargs; |
2414 |
fnargs = X.v; |
fnargs = X.v; |
2415 |
|
|
2416 |
L.s = programname; |
L.s = g_progname; |
2417 |
res = evaluate(op->r.f->body.first, res); |
res = evaluate(op->r.f->body.first, res); |
2418 |
programname = L.s; |
g_progname = L.s; |
2419 |
|
|
2420 |
nvfree(fnargs); |
nvfree(fnargs); |
2421 |
fnargs = R.v; |
fnargs = R.v; |
2425 |
case XC( OC_PGETLINE ): |
case XC( OC_PGETLINE ): |
2426 |
if (op1) { |
if (op1) { |
2427 |
X.rsm = newfile(L.s); |
X.rsm = newfile(L.s); |
2428 |
if (! X.rsm->F) { |
if (!X.rsm->F) { |
2429 |
if ((opinfo & OPCLSMASK) == OC_PGETLINE) { |
if ((opinfo & OPCLSMASK) == OC_PGETLINE) { |
2430 |
X.rsm->F = popen(L.s, "r"); |
X.rsm->F = popen(L.s, "r"); |
2431 |
X.rsm->is_pipe = TRUE; |
X.rsm->is_pipe = TRUE; |
2432 |
} else { |
} else { |
2433 |
X.rsm->F = fopen(L.s, "r"); /* not xfopen! */ |
X.rsm->F = fopen_for_read(L.s); /* not xfopen! */ |
2434 |
} |
} |
2435 |
} |
} |
2436 |
} else { |
} else { |
2437 |
if (! iF) iF = next_input_file(); |
if (!iF) iF = next_input_file(); |
2438 |
X.rsm = iF; |
X.rsm = iF; |
2439 |
} |
} |
2440 |
|
|
2441 |
if (! X.rsm->F) { |
if (!X.rsm->F) { |
2442 |
setvar_i(V[ERRNO], errno); |
setvar_i(intvar[ERRNO], errno); |
2443 |
setvar_i(res, -1); |
setvar_i(res, -1); |
2444 |
break; |
break; |
2445 |
} |
} |
2446 |
|
|
2447 |
if (! op->r.n) |
if (!op->r.n) |
2448 |
R.v = V[F0]; |
R.v = intvar[F0]; |
2449 |
|
|
2450 |
L.i = awk_getline(X.rsm, R.v); |
L.i = awk_getline(X.rsm, R.v); |
2451 |
if (L.i > 0) { |
if (L.i > 0) { |
2452 |
if (! op1) { |
if (!op1) { |
2453 |
incvar(V[FNR]); |
incvar(intvar[FNR]); |
2454 |
incvar(V[NR]); |
incvar(intvar[NR]); |
2455 |
} |
} |
2456 |
} |
} |
2457 |
setvar_i(res, L.i); |
setvar_i(res, L.i); |
2458 |
break; |
break; |
2459 |
|
|
2460 |
/* simple builtins */ |
/* simple builtins */ |
2461 |
case XC( OC_FBLTIN ): |
case XC( OC_FBLTIN ): |
2462 |
switch (opn) { |
switch (opn) { |
2463 |
|
|
2468 |
case F_rn: |
case F_rn: |
2469 |
R.d = (double)rand() / (double)RAND_MAX; |
R.d = (double)rand() / (double)RAND_MAX; |
2470 |
break; |
break; |
2471 |
|
#if ENABLE_FEATURE_AWK_LIBM |
|
#if ENABLE_FEATURE_AWK_MATH |
|
2472 |
case F_co: |
case F_co: |
2473 |
R.d = cos(L.d); |
R.d = cos(L.d); |
2474 |
break; |
break; |
2494 |
case F_lg: |
case F_lg: |
2495 |
case F_si: |
case F_si: |
2496 |
case F_sq: |
case F_sq: |
2497 |
runtime_error(EMSG_NO_MATH); |
syntax_error(EMSG_NO_MATH); |
2498 |
break; |
break; |
2499 |
#endif |
#endif |
|
|
|
2500 |
case F_sr: |
case F_sr: |
2501 |
R.d = (double)seed; |
R.d = (double)seed; |
2502 |
seed = op1 ? (unsigned)L.d : (unsigned)time(NULL); |
seed = op1 ? (unsigned)L.d : (unsigned)time(NULL); |
2508 |
break; |
break; |
2509 |
|
|
2510 |
case F_le: |
case F_le: |
2511 |
if (! op1) |
if (!op1) |
2512 |
L.s = getvar_s(V[F0]); |
L.s = getvar_s(intvar[F0]); |
2513 |
R.d = strlen(L.s); |
R.d = strlen(L.s); |
2514 |
break; |
break; |
2515 |
|
|
2520 |
break; |
break; |
2521 |
|
|
2522 |
case F_ff: |
case F_ff: |
2523 |
if (! op1) |
if (!op1) |
2524 |
fflush(stdout); |
fflush(stdout); |
2525 |
else { |
else { |
2526 |
if (L.s && *L.s) { |
if (L.s && *L.s) { |
2540 |
hash_remove(fdhash, L.s); |
hash_remove(fdhash, L.s); |
2541 |
} |
} |
2542 |
if (R.i != 0) |
if (R.i != 0) |
2543 |
setvar_i(V[ERRNO], errno); |
setvar_i(intvar[ERRNO], errno); |
2544 |
R.d = (double)R.i; |
R.d = (double)R.i; |
2545 |
break; |
break; |
2546 |
} |
} |
2586 |
case XC( OC_FIELD ): |
case XC( OC_FIELD ): |
2587 |
R.i = (int)getvar_i(R.v); |
R.i = (int)getvar_i(R.v); |
2588 |
if (R.i == 0) { |
if (R.i == 0) { |
2589 |
res = V[F0]; |
res = intvar[F0]; |
2590 |
} else { |
} else { |
2591 |
split_f0(); |
split_f0(); |
2592 |
if (R.i > nfields) |
if (R.i > nfields) |
2593 |
fsrealloc(R.i); |
fsrealloc(R.i); |
2594 |
|
res = &Fields[R.i - 1]; |
|
res = &Fields[R.i-1]; |
|
2595 |
} |
} |
2596 |
break; |
break; |
2597 |
|
|
2598 |
/* concatenation (" ") and index joining (",") */ |
/* concatenation (" ") and index joining (",") */ |
2599 |
case XC( OC_CONCAT ): |
case XC( OC_CONCAT ): |
2600 |
case XC( OC_COMMA ): |
case XC( OC_COMMA ): |
2601 |
opn = strlen(L.s) + strlen(R.s) + 2; |
opn = strlen(L.s) + strlen(R.s) + 2; |
2602 |
X.s = xmalloc(opn); |
X.s = xmalloc(opn); |
2603 |
strcpy(X.s, L.s); |
strcpy(X.s, L.s); |
2604 |
if ((opinfo & OPCLSMASK) == OC_COMMA) { |
if ((opinfo & OPCLSMASK) == OC_COMMA) { |
2605 |
L.s = getvar_s(V[SUBSEP]); |
L.s = getvar_s(intvar[SUBSEP]); |
2606 |
X.s = xrealloc(X.s, opn + strlen(L.s)); |
X.s = xrealloc(X.s, opn + strlen(L.s)); |
2607 |
strcat(X.s, L.s); |
strcat(X.s, L.s); |
2608 |
} |
} |
2632 |
L.d *= R.d; |
L.d *= R.d; |
2633 |
break; |
break; |
2634 |
case '/': |
case '/': |
2635 |
if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO); |
if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO); |
2636 |
L.d /= R.d; |
L.d /= R.d; |
2637 |
break; |
break; |
2638 |
case '&': |
case '&': |
2639 |
#if ENABLE_FEATURE_AWK_MATH |
#if ENABLE_FEATURE_AWK_LIBM |
2640 |
L.d = pow(L.d, R.d); |
L.d = pow(L.d, R.d); |
2641 |
#else |
#else |
2642 |
runtime_error(EMSG_NO_MATH); |
syntax_error(EMSG_NO_MATH); |
2643 |
#endif |
#endif |
2644 |
break; |
break; |
2645 |
case '%': |
case '%': |
2646 |
if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO); |
if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO); |
2647 |
L.d -= (int)(L.d / R.d) * R.d; |
L.d -= (int)(L.d / R.d) * R.d; |
2648 |
break; |
break; |
2649 |
} |
} |
2650 |
res = setvar_i(((opinfo&OPCLSMASK) == OC_BINARY) ? res : X.v, L.d); |
res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d); |
2651 |
break; |
break; |
2652 |
|
|
2653 |
case XC( OC_COMPARE ): |
case XC( OC_COMPARE ): |
2673 |
break; |
break; |
2674 |
|
|
2675 |
default: |
default: |
2676 |
runtime_error(EMSG_POSSIBLE_ERROR); |
syntax_error(EMSG_POSSIBLE_ERROR); |
2677 |
} |
} |
2678 |
if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS) |
if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS) |
2679 |
op = op->a.n; |
op = op->a.n; |
2684 |
} |
} |
2685 |
nvfree(v1); |
nvfree(v1); |
2686 |
return res; |
return res; |
2687 |
|
#undef fnargs |
2688 |
|
#undef seed |
2689 |
|
#undef sreg |
2690 |
} |
} |
2691 |
|
|
2692 |
|
|
2745 |
/* switch to next input file */ |
/* switch to next input file */ |
2746 |
static rstream *next_input_file(void) |
static rstream *next_input_file(void) |
2747 |
{ |
{ |
2748 |
static rstream rsm; |
#define rsm (G.next_input_file__rsm) |
2749 |
|
#define files_happen (G.next_input_file__files_happen) |
2750 |
|
|
2751 |
FILE *F = NULL; |
FILE *F = NULL; |
2752 |
char *fname, *ind; |
const char *fname, *ind; |
|
static int files_happen = FALSE; |
|
2753 |
|
|
2754 |
if (rsm.F) fclose(rsm.F); |
if (rsm.F) fclose(rsm.F); |
2755 |
rsm.F = NULL; |
rsm.F = NULL; |
2756 |
rsm.pos = rsm.adv = 0; |
rsm.pos = rsm.adv = 0; |
2757 |
|
|
2758 |
do { |
do { |
2759 |
if (getvar_i(V[ARGIND])+1 >= getvar_i(V[ARGC])) { |
if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) { |
2760 |
if (files_happen) |
if (files_happen) |
2761 |
return NULL; |
return NULL; |
2762 |
fname = "-"; |
fname = "-"; |
2763 |
F = stdin; |
F = stdin; |
2764 |
} else { |
} else { |
2765 |
ind = getvar_s(incvar(V[ARGIND])); |
ind = getvar_s(incvar(intvar[ARGIND])); |
2766 |
fname = getvar_s(findvar(iamarray(V[ARGV]), ind)); |
fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind)); |
2767 |
if (fname && *fname && !is_assignment(fname)) |
if (fname && *fname && !is_assignment(fname)) |
2768 |
F = afopen(fname, "r"); |
F = xfopen_stdin(fname); |
2769 |
} |
} |
2770 |
} while (!F); |
} while (!F); |
2771 |
|
|
2772 |
files_happen = TRUE; |
files_happen = TRUE; |
2773 |
setvar_s(V[FILENAME], fname); |
setvar_s(intvar[FILENAME], fname); |
2774 |
rsm.F = F; |
rsm.F = F; |
2775 |
return &rsm; |
return &rsm; |
2776 |
|
#undef rsm |
2777 |
|
#undef files_happen |
2778 |
} |
} |
2779 |
|
|
2780 |
|
int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
2781 |
int awk_main(int argc, char **argv) |
int awk_main(int argc, char **argv) |
2782 |
{ |
{ |
2783 |
unsigned opt; |
unsigned opt; |
2784 |
char *opt_F, *opt_v, *opt_W; |
char *opt_F, *opt_W; |
2785 |
int i, j, flen; |
llist_t *list_v = NULL; |
2786 |
|
llist_t *list_f = NULL; |
2787 |
|
int i, j; |
2788 |
var *v; |
var *v; |
2789 |
var tv; |
var tv; |
2790 |
char **envp; |
char **envp; |
2791 |
char *vnames = (char *)vNames; /* cheat */ |
char *vnames = (char *)vNames; /* cheat */ |
2792 |
char *vvalues = (char *)vValues; |
char *vvalues = (char *)vValues; |
2793 |
|
|
2794 |
|
INIT_G(); |
2795 |
|
|
2796 |
/* Undo busybox.c, or else strtod may eat ','! This breaks parsing: |
/* Undo busybox.c, or else strtod may eat ','! This breaks parsing: |
2797 |
* $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */ |
* $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */ |
2798 |
if (ENABLE_LOCALE_SUPPORT) |
if (ENABLE_LOCALE_SUPPORT) |
2801 |
zero_out_var(&tv); |
zero_out_var(&tv); |
2802 |
|
|
2803 |
/* allocate global buffer */ |
/* allocate global buffer */ |
2804 |
buf = xmalloc(MAXVARFMT + 1); |
g_buf = xmalloc(MAXVARFMT + 1); |
2805 |
|
|
2806 |
vhash = hash_init(); |
vhash = hash_init(); |
2807 |
ahash = hash_init(); |
ahash = hash_init(); |
2810 |
|
|
2811 |
/* initialize variables */ |
/* initialize variables */ |
2812 |
for (i = 0; *vnames; i++) { |
for (i = 0; *vnames; i++) { |
2813 |
V[i] = v = newvar(nextword(&vnames)); |
intvar[i] = v = newvar(nextword(&vnames)); |
2814 |
if (*vvalues != '\377') |
if (*vvalues != '\377') |
2815 |
setvar_s(v, nextword(&vvalues)); |
setvar_s(v, nextword(&vvalues)); |
2816 |
else |
else |
2822 |
} |
} |
2823 |
} |
} |
2824 |
|
|
2825 |
handle_special(V[FS]); |
handle_special(intvar[FS]); |
2826 |
handle_special(V[RS]); |
handle_special(intvar[RS]); |
2827 |
|
|
2828 |
newfile("/dev/stdin")->F = stdin; |
newfile("/dev/stdin")->F = stdin; |
2829 |
newfile("/dev/stdout")->F = stdout; |
newfile("/dev/stdout")->F = stdout; |
2830 |
newfile("/dev/stderr")->F = stderr; |
newfile("/dev/stderr")->F = stderr; |
2831 |
|
|
2832 |
for (envp = environ; *envp; envp++) { |
/* Huh, people report that sometimes environ is NULL. Oh well. */ |
2833 |
char *s = xstrdup(*envp); |
if (environ) for (envp = environ; *envp; envp++) { |
2834 |
|
/* environ is writable, thus we don't strdup it needlessly */ |
2835 |
|
char *s = *envp; |
2836 |
char *s1 = strchr(s, '='); |
char *s1 = strchr(s, '='); |
2837 |
if (s1) { |
if (s1) { |
2838 |
*s1++ = '\0'; |
*s1 = '\0'; |
2839 |
setvar_u(findvar(iamarray(V[ENVIRON]), s), s1); |
/* Both findvar and setvar_u take const char* |
2840 |
|
* as 2nd arg -> environment is not trashed */ |
2841 |
|
setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1); |
2842 |
|
*s1 = '='; |
2843 |
} |
} |
|
free(s); |
|
2844 |
} |
} |
2845 |
|
opt_complementary = "v::f::"; /* -v and -f can occur multiple times */ |
2846 |
opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &programname, &opt_W); |
opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W); |
2847 |
argv += optind; |
argv += optind; |
2848 |
argc -= optind; |
argc -= optind; |
2849 |
if (opt & 0x1) setvar_s(V[FS], opt_F); // -F |
if (opt & 0x1) |
2850 |
if (opt & 0x2) if (!is_assignment(opt_v)) bb_show_usage(); // -v |
setvar_s(intvar[FS], opt_F); // -F |
2851 |
if (opt & 0x4) { // -f |
while (list_v) { /* -v */ |
2852 |
char *s = s; /* die, gcc, die */ |
if (!is_assignment(llist_pop(&list_v))) |
2853 |
FILE *from_file = afopen(programname, "r"); |
bb_show_usage(); |
2854 |
/* one byte is reserved for some trick in next_token */ |
} |
2855 |
if (fseek(from_file, 0, SEEK_END) == 0) { |
if (list_f) { /* -f */ |
2856 |
flen = ftell(from_file); |
do { |
2857 |
s = xmalloc(flen + 4); |
char *s = NULL; |
2858 |
fseek(from_file, 0, SEEK_SET); |
FILE *from_file; |
2859 |
i = 1 + fread(s + 1, 1, flen, from_file); |
|
2860 |
} else { |
g_progname = llist_pop(&list_f); |
2861 |
|
from_file = xfopen_stdin(g_progname); |
2862 |
|
/* one byte is reserved for some trick in next_token */ |
2863 |
for (i = j = 1; j > 0; i += j) { |
for (i = j = 1; j > 0; i += j) { |
2864 |
s = xrealloc(s, i + 4096); |
s = xrealloc(s, i + 4096); |
2865 |
j = fread(s + i, 1, 4094, from_file); |
j = fread(s + i, 1, 4094, from_file); |
2866 |
} |
} |
2867 |
} |
s[i] = '\0'; |
2868 |
s[i] = '\0'; |
fclose(from_file); |
2869 |
fclose(from_file); |
parse_program(s + 1); |
2870 |
parse_program(s + 1); |
free(s); |
2871 |
free(s); |
} while (list_f); |
2872 |
} else { // no -f: take program from 1st parameter |
} else { // no -f: take program from 1st parameter |
2873 |
if (!argc) |
if (!argc) |
2874 |
bb_show_usage(); |
bb_show_usage(); |
2875 |
programname = "cmd. line"; |
g_progname = "cmd. line"; |
2876 |
parse_program(*argv++); |
parse_program(*argv++); |
2877 |
argc--; |
argc--; |
2878 |
} |
} |
2880 |
bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W); |
bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W); |
2881 |
|
|
2882 |
/* fill in ARGV array */ |
/* fill in ARGV array */ |
2883 |
setvar_i(V[ARGC], argc + 1); |
setvar_i(intvar[ARGC], argc + 1); |
2884 |
setari_u(V[ARGV], 0, "awk"); |
setari_u(intvar[ARGV], 0, "awk"); |
2885 |
i = 0; |
i = 0; |
2886 |
while (*argv) |
while (*argv) |
2887 |
setari_u(V[ARGV], ++i, *argv++); |
setari_u(intvar[ARGV], ++i, *argv++); |
2888 |
|
|
2889 |
evaluate(beginseq.first, &tv); |
evaluate(beginseq.first, &tv); |
2890 |
if (!mainseq.first && !endseq.first) |
if (!mainseq.first && !endseq.first) |
2896 |
/* passing through input files */ |
/* passing through input files */ |
2897 |
while (iF) { |
while (iF) { |
2898 |
nextfile = FALSE; |
nextfile = FALSE; |
2899 |
setvar_i(V[FNR], 0); |
setvar_i(intvar[FNR], 0); |
2900 |
|
|
2901 |
while ((i = awk_getline(iF, V[F0])) > 0) { |
while ((i = awk_getline(iF, intvar[F0])) > 0) { |
2902 |
nextrec = FALSE; |
nextrec = FALSE; |
2903 |
incvar(V[NR]); |
incvar(intvar[NR]); |
2904 |
incvar(V[FNR]); |
incvar(intvar[FNR]); |
2905 |
evaluate(mainseq.first, &tv); |
evaluate(mainseq.first, &tv); |
2906 |
|
|
2907 |
if (nextfile) |
if (nextfile) |
2909 |
} |
} |
2910 |
|
|
2911 |
if (i < 0) |
if (i < 0) |
2912 |
runtime_error(strerror(errno)); |
syntax_error(strerror(errno)); |
2913 |
|
|
2914 |
iF = next_input_file(); |
iF = next_input_file(); |
2915 |
} |
} |