1/* 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 * 7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 8 */ 9 10#include "libbb.h" 11#include "xregex.h" 12#include <math.h> 13extern char **environ; 14 15/* This is a NOEXEC applet. Be very careful! */ 16 17 18#define MAXVARFMT 240 19#define MINNVBLOCK 64 20 21/* variable flags */ 22#define VF_NUMBER 0x0001 /* 1 = primary type is number */ 23#define VF_ARRAY 0x0002 /* 1 = it's an array */ 24 25#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */ 26#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */ 27#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */ 28#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */ 29#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */ 30#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */ 31#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */ 32 33/* these flags are static, don't change them when value is changed */ 34#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY) 35 36/* Variable */ 37typedef struct var_s { 38 unsigned type; /* flags */ 39 double number; 40 char *string; 41 union { 42 int aidx; /* func arg idx (for compilation stage) */ 43 struct xhash_s *array; /* array ptr */ 44 struct var_s *parent; /* for func args, ptr to actual parameter */ 45 char **walker; /* list of array elements (for..in) */ 46 } x; 47} var; 48 49/* Node chain (pattern-action chain, BEGIN, END, function bodies) */ 50typedef struct chain_s { 51 struct node_s *first; 52 struct node_s *last; 53 const char *programname; 54} chain; 55 56/* Function */ 57typedef struct func_s { 58 unsigned nargs; 59 struct chain_s body; 60} func; 61 62/* I/O stream */ 63typedef struct rstream_s { 64 FILE *F; 65 char *buffer; 66 int adv; 67 int size; 68 int pos; 69 smallint is_pipe; 70} rstream; 71 72typedef struct hash_item_s { 73 union { 74 struct var_s v; /* variable/array hash */ 75 struct rstream_s rs; /* redirect streams hash */ 76 struct func_s f; /* functions hash */ 77 } data; 78 struct hash_item_s *next; /* next in chain */ 79 char name[1]; /* really it's longer */ 80} hash_item; 81 82typedef struct xhash_s { 83 unsigned nel; /* num of elements */ 84 unsigned csize; /* current hash size */ 85 unsigned nprime; /* next hash size in PRIMES[] */ 86 unsigned glen; /* summary length of item names */ 87 struct hash_item_s **items; 88} xhash; 89 90/* Tree node */ 91typedef struct node_s { 92 uint32_t info; 93 unsigned lineno; 94 union { 95 struct node_s *n; 96 var *v; 97 int i; 98 char *s; 99 regex_t *re; 100 } l; 101 union { 102 struct node_s *n; 103 regex_t *ire; 104 func *f; 105 int argno; 106 } r; 107 union { 108 struct node_s *n; 109 } a; 110} node; 111 112/* Block of temporary variables */ 113typedef struct nvblock_s { 114 int size; 115 var *pos; 116 struct nvblock_s *prev; 117 struct nvblock_s *next; 118 var nv[0]; 119} nvblock; 120 121typedef struct tsplitter_s { 122 node n; 123 regex_t re[2]; 124} tsplitter; 125 126/* simple token classes */ 127/* Order and hex values are very important!!! See next_token() */ 128#define TC_SEQSTART 1 /* ( */ 129#define TC_SEQTERM (1 << 1) /* ) */ 130#define TC_REGEXP (1 << 2) /* /.../ */ 131#define TC_OUTRDR (1 << 3) /* | > >> */ 132#define TC_UOPPOST (1 << 4) /* unary postfix operator */ 133#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */ 134#define TC_BINOPX (1 << 6) /* two-opnd operator */ 135#define TC_IN (1 << 7) 136#define TC_COMMA (1 << 8) 137#define TC_PIPE (1 << 9) /* input redirection pipe */ 138#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */ 139#define TC_ARRTERM (1 << 11) /* ] */ 140#define TC_GRPSTART (1 << 12) /* { */ 141#define TC_GRPTERM (1 << 13) /* } */ 142#define TC_SEMICOL (1 << 14) 143#define TC_NEWLINE (1 << 15) 144#define TC_STATX (1 << 16) /* ctl statement (for, next...) */ 145#define TC_WHILE (1 << 17) 146#define TC_ELSE (1 << 18) 147#define TC_BUILTIN (1 << 19) 148#define TC_GETLINE (1 << 20) 149#define TC_FUNCDECL (1 << 21) /* `function' `func' */ 150#define TC_BEGIN (1 << 22) 151#define TC_END (1 << 23) 152#define TC_EOF (1 << 24) 153#define TC_VARIABLE (1 << 25) 154#define TC_ARRAY (1 << 26) 155#define TC_FUNCTION (1 << 27) 156#define TC_STRING (1 << 28) 157#define TC_NUMBER (1 << 29) 158 159#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) 160 161/* combined token classes */ 162#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) 163#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) 164#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \ 165 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER) 166 167#define TC_STATEMNT (TC_STATX | TC_WHILE) 168#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE) 169 170/* word tokens, cannot mean something else if not expected */ 171#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \ 172 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END) 173 174/* discard newlines after these */ 175#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \ 176 | TC_BINOP | TC_OPTERM) 177 178/* what can expression begin with */ 179#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP) 180/* what can group begin with */ 181#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART) 182 183/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */ 184/* operator is inserted between them */ 185#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \ 186 | TC_STRING | TC_NUMBER | TC_UOPPOST) 187#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) 188 189#define OF_RES1 0x010000 190#define OF_RES2 0x020000 191#define OF_STR1 0x040000 192#define OF_STR2 0x080000 193#define OF_NUM1 0x100000 194#define OF_CHECKED 0x200000 195 196/* combined operator flags */ 197#define xx 0 198#define xV OF_RES2 199#define xS (OF_RES2 | OF_STR2) 200#define Vx OF_RES1 201#define VV (OF_RES1 | OF_RES2) 202#define Nx (OF_RES1 | OF_NUM1) 203#define NV (OF_RES1 | OF_NUM1 | OF_RES2) 204#define Sx (OF_RES1 | OF_STR1) 205#define SV (OF_RES1 | OF_STR1 | OF_RES2) 206#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2) 207 208#define OPCLSMASK 0xFF00 209#define OPNMASK 0x007F 210 211/* operator priority is a highest byte (even: r->l, odd: l->r grouping) 212 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1, 213 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string 214 */ 215#define P(x) (x << 24) 216#define PRIMASK 0x7F000000 217#define PRIMASK2 0x7E000000 218 219/* Operation classes */ 220 221#define SHIFT_TIL_THIS 0x0600 222#define RECUR_FROM_THIS 0x1000 223 224enum { 225 OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300, 226 OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600, 227 228 OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900, 229 OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00, 230 OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00, 231 232 OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200, 233 OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500, 234 OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800, 235 OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00, 236 OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00, 237 OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100, 238 OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400, 239 OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700, 240 OC_DONE = 0x2800, 241 242 ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200, 243 ST_WHILE = 0x3300 244}; 245 246/* simple builtins */ 247enum { 248 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr, 249 F_ti, F_le, F_sy, F_ff, F_cl 250}; 251 252/* builtins */ 253enum { 254 B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up, 255 B_ge, B_gs, B_su, 256 B_an, B_co, B_ls, B_or, B_rs, B_xo, 257}; 258 259/* tokens and their corresponding info values */ 260 261#define NTC "\377" /* switch to next token class (tc<<1) */ 262#define NTCC '\377' 263 264#define OC_B OC_BUILTIN 265 266static const char tokenlist[] ALIGN1 = 267 "\1(" NTC 268 "\1)" NTC 269 "\1/" NTC /* REGEXP */ 270 "\2>>" "\1>" "\1|" NTC /* OUTRDR */ 271 "\2++" "\2--" NTC /* UOPPOST */ 272 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ 273 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ 274 "\2*=" "\2/=" "\2%=" "\2^=" 275 "\1+" "\1-" "\3**=" "\2**" 276 "\1/" "\1%" "\1^" "\1*" 277 "\2!=" "\2>=" "\2<=" "\1>" 278 "\1<" "\2!~" "\1~" "\2&&" 279 "\2||" "\1?" "\1:" NTC 280 "\2in" NTC 281 "\1," NTC 282 "\1|" NTC 283 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ 284 "\1]" NTC 285 "\1{" NTC 286 "\1}" NTC 287 "\1;" NTC 288 "\1\n" NTC 289 "\2if" "\2do" "\3for" "\5break" /* STATX */ 290 "\10continue" "\6delete" "\5print" 291 "\6printf" "\4next" "\10nextfile" 292 "\6return" "\4exit" NTC 293 "\5while" NTC 294 "\4else" NTC 295 296 "\3and" "\5compl" "\6lshift" "\2or" 297 "\6rshift" "\3xor" 298 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ 299 "\3cos" "\3exp" "\3int" "\3log" 300 "\4rand" "\3sin" "\4sqrt" "\5srand" 301 "\6gensub" "\4gsub" "\5index" "\6length" 302 "\5match" "\5split" "\7sprintf" "\3sub" 303 "\6substr" "\7systime" "\10strftime" 304 "\7tolower" "\7toupper" NTC 305 "\7getline" NTC 306 "\4func" "\10function" NTC 307 "\5BEGIN" NTC 308 "\3END" "\0" 309 ; 310 311static const uint32_t tokeninfo[] = { 312 0, 313 0, 314 OC_REGEXP, 315 xS|'a', xS|'w', xS|'|', 316 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', 317 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', 318 OC_FIELD|xV|P(5), 319 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), 320 OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', 321 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', 322 OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', 323 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', 324 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', 325 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', 326 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', 327 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, 328 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, 329 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', 330 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), 331 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', 332 OC_COLON|xx|P(67)|':', 333 OC_IN|SV|P(49), 334 OC_COMMA|SS|P(80), 335 OC_PGETLINE|SV|P(37), 336 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', 337 OC_UNARY|xV|P(19)|'!', 338 0, 339 0, 340 0, 341 0, 342 0, 343 ST_IF, ST_DO, ST_FOR, OC_BREAK, 344 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, 345 OC_PRINTF, OC_NEXT, OC_NEXTFILE, 346 OC_RETURN|Vx, OC_EXIT|Nx, 347 ST_WHILE, 348 0, 349 350 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83), 351 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83), 352 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83), 353 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg, 354 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr, 355 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le, 356 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6), 357 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), 358 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), 359 OC_GETLINE|SV|P(0), 360 0, 0, 361 0, 362 0 363}; 364 365/* internal variable names and their initial values */ 366/* asterisk marks SPECIAL vars; $ is just no-named Field0 */ 367enum { 368 CONVFMT, OFMT, FS, OFS, 369 ORS, RS, RT, FILENAME, 370 SUBSEP, ARGIND, ARGC, ARGV, 371 ERRNO, FNR, 372 NR, NF, IGNORECASE, 373 ENVIRON, F0, NUM_INTERNAL_VARS 374}; 375 376static const char vNames[] ALIGN1 = 377 "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0" 378 "ORS\0" "RS\0*" "RT\0" "FILENAME\0" 379 "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0" 380 "ERRNO\0" "FNR\0" 381 "NR\0" "NF\0*" "IGNORECASE\0*" 382 "ENVIRON\0" "$\0*" "\0"; 383 384static const char vValues[] ALIGN1 = 385 "%.6g\0" "%.6g\0" " \0" " \0" 386 "\n\0" "\n\0" "\0" "\0" 387 "\034\0" 388 "\377"; 389 390/* hash size may grow to these values */ 391#define FIRST_PRIME 61 392static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 }; 393 394 395/* Globals. Split in two parts so that first one is addressed 396 * with (mostly short) negative offsets */ 397struct globals { 398 chain beginseq, mainseq, endseq, *seq; 399 node *break_ptr, *continue_ptr; 400 rstream *iF; 401 xhash *vhash, *ahash, *fdhash, *fnhash; 402 const char *g_progname; 403 int g_lineno; 404 int nfields; 405 int maxfields; /* used in fsrealloc() only */ 406 var *Fields; 407 nvblock *g_cb; 408 char *g_pos; 409 char *g_buf; 410 smallint icase; 411 smallint exiting; 412 smallint nextrec; 413 smallint nextfile; 414 smallint is_f0_split; 415}; 416struct globals2 { 417 uint32_t t_info; /* often used */ 418 uint32_t t_tclass; 419 char *t_string; 420 int t_lineno; 421 int t_rollback; 422 423 var *intvar[NUM_INTERNAL_VARS]; /* often used */ 424 425 /* former statics from various functions */ 426 char *split_f0__fstrings; 427 428 uint32_t next_token__save_tclass; 429 uint32_t next_token__save_info; 430 uint32_t next_token__ltclass; 431 smallint next_token__concat_inserted; 432 433 smallint next_input_file__files_happen; 434 rstream next_input_file__rsm; 435 436 var *evaluate__fnargs; 437 unsigned evaluate__seed; 438 regex_t evaluate__sreg; 439 440 var ptest__v; 441 442 tsplitter exec_builtin__tspl; 443 444 /* biggest and least used members go last */ 445 double t_double; 446 tsplitter fsplitter, rsplitter; 447}; 448#define G1 (ptr_to_globals[-1]) 449#define G (*(struct globals2 *const)ptr_to_globals) 450/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */ 451/* char G1size[sizeof(G1)]; - 0x6c */ 452/* char Gsize[sizeof(G)]; - 0x1cc */ 453/* Trying to keep most of members accessible with short offsets: */ 454/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */ 455#define beginseq (G1.beginseq ) 456#define mainseq (G1.mainseq ) 457#define endseq (G1.endseq ) 458#define seq (G1.seq ) 459#define break_ptr (G1.break_ptr ) 460#define continue_ptr (G1.continue_ptr) 461#define iF (G1.iF ) 462#define vhash (G1.vhash ) 463#define ahash (G1.ahash ) 464#define fdhash (G1.fdhash ) 465#define fnhash (G1.fnhash ) 466#define g_progname (G1.g_progname ) 467#define g_lineno (G1.g_lineno ) 468#define nfields (G1.nfields ) 469#define maxfields (G1.maxfields ) 470#define Fields (G1.Fields ) 471#define g_cb (G1.g_cb ) 472#define g_pos (G1.g_pos ) 473#define g_buf (G1.g_buf ) 474#define icase (G1.icase ) 475#define exiting (G1.exiting ) 476#define nextrec (G1.nextrec ) 477#define nextfile (G1.nextfile ) 478#define is_f0_split (G1.is_f0_split ) 479#define t_info (G.t_info ) 480#define t_tclass (G.t_tclass ) 481#define t_string (G.t_string ) 482#define t_double (G.t_double ) 483#define t_lineno (G.t_lineno ) 484#define t_rollback (G.t_rollback ) 485#define intvar (G.intvar ) 486#define fsplitter (G.fsplitter ) 487#define rsplitter (G.rsplitter ) 488#define INIT_G() do { \ 489 PTR_TO_GLOBALS = xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1); \ 490 G.next_token__ltclass = TC_OPTERM; \ 491 G.evaluate__seed = 1; \ 492} while (0) 493 494 495/* function prototypes */ 496static void handle_special(var *); 497static node *parse_expr(uint32_t); 498static void chain_group(void); 499static var *evaluate(node *, var *); 500static rstream *next_input_file(void); 501static int fmt_num(char *, int, const char *, double, int); 502static int awk_exit(int) ATTRIBUTE_NORETURN; 503 504/* ---- error handling ---- */ 505 506static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error"; 507static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string"; 508static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token"; 509static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero"; 510static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier"; 511static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; 512static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; 513static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; 514static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; 515#if !ENABLE_FEATURE_AWK_MATH 516static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; 517#endif 518 519static void zero_out_var(var * vp) 520{ 521 memset(vp, 0, sizeof(*vp)); 522} 523 524static void syntax_error(const char *const message) ATTRIBUTE_NORETURN; 525static void syntax_error(const char *const message) 526{ 527 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message); 528} 529 530/* ---- hash stuff ---- */ 531 532static unsigned hashidx(const char *name) 533{ 534 unsigned idx = 0; 535 536 while (*name) idx = *name++ + (idx << 6) - idx; 537 return idx; 538} 539 540/* create new hash */ 541static xhash *hash_init(void) 542{ 543 xhash *newhash; 544 545 newhash = xzalloc(sizeof(xhash)); 546 newhash->csize = FIRST_PRIME; 547 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *)); 548 549 return newhash; 550} 551 552/* find item in hash, return ptr to data, NULL if not found */ 553static void *hash_search(xhash *hash, const char *name) 554{ 555 hash_item *hi; 556 557 hi = hash->items [ hashidx(name) % hash->csize ]; 558 while (hi) { 559 if (strcmp(hi->name, name) == 0) 560 return &(hi->data); 561 hi = hi->next; 562 } 563 return NULL; 564} 565 566/* grow hash if it becomes too big */ 567static void hash_rebuild(xhash *hash) 568{ 569 unsigned newsize, i, idx; 570 hash_item **newitems, *hi, *thi; 571 572 if (hash->nprime == ARRAY_SIZE(PRIMES)) 573 return; 574 575 newsize = PRIMES[hash->nprime++]; 576 newitems = xzalloc(newsize * sizeof(hash_item *)); 577 578 for (i = 0; i < hash->csize; i++) { 579 hi = hash->items[i]; 580 while (hi) { 581 thi = hi; 582 hi = thi->next; 583 idx = hashidx(thi->name) % newsize; 584 thi->next = newitems[idx]; 585 newitems[idx] = thi; 586 } 587 } 588 589 free(hash->items); 590 hash->csize = newsize; 591 hash->items = newitems; 592} 593 594/* find item in hash, add it if necessary. Return ptr to data */ 595static void *hash_find(xhash *hash, const char *name) 596{ 597 hash_item *hi; 598 unsigned idx; 599 int l; 600 601 hi = hash_search(hash, name); 602 if (!hi) { 603 if (++hash->nel / hash->csize > 10) 604 hash_rebuild(hash); 605 606 l = strlen(name) + 1; 607 hi = xzalloc(sizeof(hash_item) + l); 608 memcpy(hi->name, name, l); 609 610 idx = hashidx(name) % hash->csize; 611 hi->next = hash->items[idx]; 612 hash->items[idx] = hi; 613 hash->glen += l; 614 } 615 return &(hi->data); 616} 617 618#define findvar(hash, name) ((var*) hash_find((hash), (name))) 619#define newvar(name) ((var*) hash_find(vhash, (name))) 620#define newfile(name) ((rstream*)hash_find(fdhash, (name))) 621#define newfunc(name) ((func*) hash_find(fnhash, (name))) 622 623static void hash_remove(xhash *hash, const char *name) 624{ 625 hash_item *hi, **phi; 626 627 phi = &(hash->items[hashidx(name) % hash->csize]); 628 while (*phi) { 629 hi = *phi; 630 if (strcmp(hi->name, name) == 0) { 631 hash->glen -= (strlen(name) + 1); 632 hash->nel--; 633 *phi = hi->next; 634 free(hi); 635 break; 636 } 637 phi = &(hi->next); 638 } 639} 640 641/* ------ some useful functions ------ */ 642 643static void skip_spaces(char **s) 644{ 645 char *p = *s; 646 647 while (1) { 648 if (*p == '\\' && p[1] == '\n') { 649 p++; 650 t_lineno++; 651 } else if (*p != ' ' && *p != '\t') { 652 break; 653 } 654 p++; 655 } 656 *s = p; 657} 658 659static char *nextword(char **s) 660{ 661 char *p = *s; 662 663 while (*(*s)++) /* */; 664 665 return p; 666} 667 668static char nextchar(char **s) 669{ 670 char c, *pps; 671 672 c = *((*s)++); 673 pps = *s; 674 if (c == '\\') c = bb_process_escape_sequence((const char**)s); 675 if (c == '\\' && *s == pps) c = *((*s)++); 676 return c; 677} 678 679static int ALWAYS_INLINE isalnum_(int c) 680{ 681 return (isalnum(c) || c == '_'); 682} 683 684static FILE *afopen(const char *path, const char *mode) 685{ 686 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode); 687} 688 689/* -------- working with variables (set/get/copy/etc) -------- */ 690 691static xhash *iamarray(var *v) 692{ 693 var *a = v; 694 695 while (a->type & VF_CHILD) 696 a = a->x.parent; 697 698 if (!(a->type & VF_ARRAY)) { 699 a->type |= VF_ARRAY; 700 a->x.array = hash_init(); 701 } 702 return a->x.array; 703} 704 705static void clear_array(xhash *array) 706{ 707 unsigned i; 708 hash_item *hi, *thi; 709 710 for (i = 0; i < array->csize; i++) { 711 hi = array->items[i]; 712 while (hi) { 713 thi = hi; 714 hi = hi->next; 715 free(thi->data.v.string); 716 free(thi); 717 } 718 array->items[i] = NULL; 719 } 720 array->glen = array->nel = 0; 721} 722 723/* clear a variable */ 724static var *clrvar(var *v) 725{ 726 if (!(v->type & VF_FSTR)) 727 free(v->string); 728 729 v->type &= VF_DONTTOUCH; 730 v->type |= VF_DIRTY; 731 v->string = NULL; 732 return v; 733} 734 735/* assign string value to variable */ 736static var *setvar_p(var *v, char *value) 737{ 738 clrvar(v); 739 v->string = value; 740 handle_special(v); 741 return v; 742} 743 744/* same as setvar_p but make a copy of string */ 745static var *setvar_s(var *v, const char *value) 746{ 747 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL); 748} 749 750/* same as setvar_s but set USER flag */ 751static var *setvar_u(var *v, const char *value) 752{ 753 setvar_s(v, value); 754 v->type |= VF_USER; 755 return v; 756} 757 758/* set array element to user string */ 759static void setari_u(var *a, int idx, const char *s) 760{ 761 char sidx[sizeof(int)*3 + 1]; 762 var *v; 763 764 sprintf(sidx, "%d", idx); 765 v = findvar(iamarray(a), sidx); 766 setvar_u(v, s); 767} 768 769/* assign numeric value to variable */ 770static var *setvar_i(var *v, double value) 771{ 772 clrvar(v); 773 v->type |= VF_NUMBER; 774 v->number = value; 775 handle_special(v); 776 return v; 777} 778 779static const char *getvar_s(var *v) 780{ 781 /* if v is numeric and has no cached string, convert it to string */ 782 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) { 783 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE); 784 v->string = xstrdup(g_buf); 785 v->type |= VF_CACHED; 786 } 787 return (v->string == NULL) ? "" : v->string; 788} 789 790static double getvar_i(var *v) 791{ 792 char *s; 793 794 if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) { 795 v->number = 0; 796 s = v->string; 797 if (s && *s) { 798 v->number = strtod(s, &s); 799 if (v->type & VF_USER) { 800 skip_spaces(&s); 801 if (*s != '\0') 802 v->type &= ~VF_USER; 803 } 804 } else { 805 v->type &= ~VF_USER; 806 } 807 v->type |= VF_CACHED; 808 } 809 return v->number; 810} 811 812static var *copyvar(var *dest, const var *src) 813{ 814 if (dest != src) { 815 clrvar(dest); 816 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR)); 817 dest->number = src->number; 818 if (src->string) 819 dest->string = xstrdup(src->string); 820 } 821 handle_special(dest); 822 return dest; 823} 824 825static var *incvar(var *v) 826{ 827 return setvar_i(v, getvar_i(v) + 1.); 828} 829 830/* return true if v is number or numeric string */ 831static int is_numeric(var *v) 832{ 833 getvar_i(v); 834 return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY)); 835} 836 837/* return 1 when value of v corresponds to true, 0 otherwise */ 838static int istrue(var *v) 839{ 840 if (is_numeric(v)) 841 return (v->number == 0) ? 0 : 1; 842 return (v->string && *(v->string)) ? 1 : 0; 843} 844 845/* temporary variables allocator. Last allocated should be first freed */ 846static var *nvalloc(int n) 847{ 848 nvblock *pb = NULL; 849 var *v, *r; 850 int size; 851 852 while (g_cb) { 853 pb = g_cb; 854 if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break; 855 g_cb = g_cb->next; 856 } 857 858 if (!g_cb) { 859 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n; 860 g_cb = xmalloc(sizeof(nvblock) + size * sizeof(var)); 861 g_cb->size = size; 862 g_cb->pos = g_cb->nv; 863 g_cb->prev = pb; 864 g_cb->next = NULL; 865 if (pb) pb->next = g_cb; 866 } 867 868 v = r = g_cb->pos; 869 g_cb->pos += n; 870 871 while (v < g_cb->pos) { 872 v->type = 0; 873 v->string = NULL; 874 v++; 875 } 876 877 return r; 878} 879 880static void nvfree(var *v) 881{ 882 var *p; 883 884 if (v < g_cb->nv || v >= g_cb->pos) 885 syntax_error(EMSG_INTERNAL_ERROR); 886 887 for (p = v; p < g_cb->pos; p++) { 888 if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) { 889 clear_array(iamarray(p)); 890 free(p->x.array->items); 891 free(p->x.array); 892 } 893 if (p->type & VF_WALK) 894 free(p->x.walker); 895 896 clrvar(p); 897 } 898 899 g_cb->pos = v; 900 while (g_cb->prev && g_cb->pos == g_cb->nv) { 901 g_cb = g_cb->prev; 902 } 903} 904 905/* ------- awk program text parsing ------- */ 906 907/* Parse next token pointed by global pos, place results into global ttt. 908 * If token isn't expected, give away. Return token class 909 */ 910static uint32_t next_token(uint32_t expected) 911{ 912#define concat_inserted (G.next_token__concat_inserted) 913#define save_tclass (G.next_token__save_tclass) 914#define save_info (G.next_token__save_info) 915/* Initialized to TC_OPTERM: */ 916#define ltclass (G.next_token__ltclass) 917 918 char *p, *pp, *s; 919 const char *tl; 920 uint32_t tc; 921 const uint32_t *ti; 922 int l; 923 924 if (t_rollback) { 925 t_rollback = FALSE; 926 927 } else if (concat_inserted) { 928 concat_inserted = FALSE; 929 t_tclass = save_tclass; 930 t_info = save_info; 931 932 } else { 933 p = g_pos; 934 readnext: 935 skip_spaces(&p); 936 g_lineno = t_lineno; 937 if (*p == '#') 938 while (*p != '\n' && *p != '\0') 939 p++; 940 941 if (*p == '\n') 942 t_lineno++; 943 944 if (*p == '\0') { 945 tc = TC_EOF; 946 947 } else if (*p == '\"') { 948 /* it's a string */ 949 t_string = s = ++p; 950 while (*p != '\"') { 951 if (*p == '\0' || *p == '\n') 952 syntax_error(EMSG_UNEXP_EOS); 953 *(s++) = nextchar(&p); 954 } 955 p++; 956 *s = '\0'; 957 tc = TC_STRING; 958 959 } else if ((expected & TC_REGEXP) && *p == '/') { 960 /* it's regexp */ 961 t_string = s = ++p; 962 while (*p != '/') { 963 if (*p == '\0' || *p == '\n') 964 syntax_error(EMSG_UNEXP_EOS); 965 *s = *p++; 966 if (*s++ == '\\') { 967 pp = p; 968 *(s-1) = bb_process_escape_sequence((const char **)&p); 969 if (*pp == '\\') 970 *s++ = '\\'; 971 if (p == pp) 972 *s++ = *p++; 973 } 974 } 975 p++; 976 *s = '\0'; 977 tc = TC_REGEXP; 978 979 } else if (*p == '.' || isdigit(*p)) { 980 /* it's a number */ 981 t_double = strtod(p, &p); 982 if (*p == '.') 983 syntax_error(EMSG_UNEXP_TOKEN); 984 tc = TC_NUMBER; 985 986 } else { 987 /* search for something known */ 988 tl = tokenlist; 989 tc = 0x00000001; 990 ti = tokeninfo; 991 while (*tl) { 992 l = *(tl++); 993 if (l == NTCC) { 994 tc <<= 1; 995 continue; 996 } 997 /* if token class is expected, token 998 * matches and it's not a longer word, 999 * then this is what we are looking for 1000 */ 1001 if ((tc & (expected | TC_WORD | TC_NEWLINE)) 1002 && *tl == *p && strncmp(p, tl, l) == 0 1003 && !((tc & TC_WORD) && isalnum_(p[l])) 1004 ) { 1005 t_info = *ti; 1006 p += l; 1007 break; 1008 } 1009 ti++; 1010 tl += l; 1011 } 1012 1013 if (!*tl) { 1014 /* it's a name (var/array/function), 1015 * otherwise it's something wrong 1016 */ 1017 if (!isalnum_(*p)) 1018 syntax_error(EMSG_UNEXP_TOKEN); 1019 1020 t_string = --p; 1021 while (isalnum_(*(++p))) { 1022 *(p-1) = *p; 1023 } 1024 *(p-1) = '\0'; 1025 tc = TC_VARIABLE; 1026 /* also consume whitespace between functionname and bracket */ 1027 if (!(expected & TC_VARIABLE)) 1028 skip_spaces(&p); 1029 if (*p == '(') { 1030 tc = TC_FUNCTION; 1031 } else { 1032 if (*p == '[') { 1033 p++; 1034 tc = TC_ARRAY; 1035 } 1036 } 1037 } 1038 } 1039 g_pos = p; 1040 1041 /* skipping newlines in some cases */ 1042 if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE)) 1043 goto readnext; 1044 1045 /* insert concatenation operator when needed */ 1046 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) { 1047 concat_inserted = TRUE; 1048 save_tclass = tc; 1049 save_info = t_info; 1050 tc = TC_BINOP; 1051 t_info = OC_CONCAT | SS | P(35); 1052 } 1053 1054 t_tclass = tc; 1055 } 1056 ltclass = t_tclass; 1057 1058 /* Are we ready for this? */ 1059 if (!(ltclass & expected)) 1060 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ? 1061 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); 1062 1063 return ltclass; 1064#undef concat_inserted 1065#undef save_tclass 1066#undef save_info 1067#undef ltclass 1068} 1069 1070static void rollback_token(void) 1071{ 1072 t_rollback = TRUE; 1073} 1074 1075static node *new_node(uint32_t info) 1076{ 1077 node *n; 1078 1079 n = xzalloc(sizeof(node)); 1080 n->info = info; 1081 n->lineno = g_lineno; 1082 return n; 1083} 1084 1085static node *mk_re_node(const char *s, node *n, regex_t *re) 1086{ 1087 n->info = OC_REGEXP; 1088 n->l.re = re; 1089 n->r.ire = re + 1; 1090 xregcomp(re, s, REG_EXTENDED); 1091 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE); 1092 1093 return n; 1094} 1095 1096static node *condition(void) 1097{ 1098 next_token(TC_SEQSTART); 1099 return parse_expr(TC_SEQTERM); 1100} 1101 1102/* parse expression terminated by given argument, return ptr 1103 * to built subtree. Terminator is eaten by parse_expr */ 1104static node *parse_expr(uint32_t iexp) 1105{ 1106 node sn; 1107 node *cn = &sn; 1108 node *vn, *glptr; 1109 uint32_t tc, xtc; 1110 var *v; 1111 1112 sn.info = PRIMASK; 1113 sn.r.n = glptr = NULL; 1114 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; 1115 1116 while (!((tc = next_token(xtc)) & iexp)) { 1117 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { 1118 /* input redirection (<) attached to glptr node */ 1119 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); 1120 cn->a.n = glptr; 1121 xtc = TC_OPERAND | TC_UOPPRE; 1122 glptr = NULL; 1123 1124 } else if (tc & (TC_BINOP | TC_UOPPOST)) { 1125 /* for binary and postfix-unary operators, jump back over 1126 * previous operators with higher priority */ 1127 vn = cn; 1128 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) 1129 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) ) 1130 vn = vn->a.n; 1131 if ((t_info & OPCLSMASK) == OC_TERNARY) 1132 t_info += P(6); 1133 cn = vn->a.n->r.n = new_node(t_info); 1134 cn->a.n = vn->a.n; 1135 if (tc & TC_BINOP) { 1136 cn->l.n = vn; 1137 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; 1138 if ((t_info & OPCLSMASK) == OC_PGETLINE) { 1139 /* it's a pipe */ 1140 next_token(TC_GETLINE); 1141 /* give maximum priority to this pipe */ 1142 cn->info &= ~PRIMASK; 1143 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; 1144 } 1145 } else { 1146 cn->r.n = vn; 1147 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; 1148 } 1149 vn->a.n = cn; 1150 1151 } else { 1152 /* for operands and prefix-unary operators, attach them 1153 * to last node */ 1154 vn = cn; 1155 cn = vn->r.n = new_node(t_info); 1156 cn->a.n = vn; 1157 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; 1158 if (tc & (TC_OPERAND | TC_REGEXP)) { 1159 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp; 1160 /* one should be very careful with switch on tclass - 1161 * only simple tclasses should be used! */ 1162 switch (tc) { 1163 case TC_VARIABLE: 1164 case TC_ARRAY: 1165 cn->info = OC_VAR; 1166 v = hash_search(ahash, t_string); 1167 if (v != NULL) { 1168 cn->info = OC_FNARG; 1169 cn->l.i = v->x.aidx; 1170 } else { 1171 cn->l.v = newvar(t_string); 1172 } 1173 if (tc & TC_ARRAY) { 1174 cn->info |= xS; 1175 cn->r.n = parse_expr(TC_ARRTERM); 1176 } 1177 break; 1178 1179 case TC_NUMBER: 1180 case TC_STRING: 1181 cn->info = OC_VAR; 1182 v = cn->l.v = xzalloc(sizeof(var)); 1183 if (tc & TC_NUMBER) 1184 setvar_i(v, t_double); 1185 else 1186 setvar_s(v, t_string); 1187 break; 1188 1189 case TC_REGEXP: 1190 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2)); 1191 break; 1192 1193 case TC_FUNCTION: 1194 cn->info = OC_FUNC; 1195 cn->r.f = newfunc(t_string); 1196 cn->l.n = condition(); 1197 break; 1198 1199 case TC_SEQSTART: 1200 cn = vn->r.n = parse_expr(TC_SEQTERM); 1201 cn->a.n = vn; 1202 break; 1203 1204 case TC_GETLINE: 1205 glptr = cn; 1206 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; 1207 break; 1208 1209 case TC_BUILTIN: 1210 cn->l.n = condition(); 1211 break; 1212 } 1213 } 1214 } 1215 } 1216 return sn.r.n; 1217} 1218 1219/* add node to chain. Return ptr to alloc'd node */ 1220static node *chain_node(uint32_t info) 1221{ 1222 node *n; 1223 1224 if (!seq->first) 1225 seq->first = seq->last = new_node(0); 1226 1227 if (seq->programname != g_progname) { 1228 seq->programname = g_progname; 1229 n = chain_node(OC_NEWSOURCE); 1230 n->l.s = xstrdup(g_progname); 1231 } 1232 1233 n = seq->last; 1234 n->info = info; 1235 seq->last = n->a.n = new_node(OC_DONE); 1236 1237 return n; 1238} 1239 1240static void chain_expr(uint32_t info) 1241{ 1242 node *n; 1243 1244 n = chain_node(info); 1245 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM); 1246 if (t_tclass & TC_GRPTERM) 1247 rollback_token(); 1248} 1249 1250static node *chain_loop(node *nn) 1251{ 1252 node *n, *n2, *save_brk, *save_cont; 1253 1254 save_brk = break_ptr; 1255 save_cont = continue_ptr; 1256 1257 n = chain_node(OC_BR | Vx); 1258 continue_ptr = new_node(OC_EXEC); 1259 break_ptr = new_node(OC_EXEC); 1260 chain_group(); 1261 n2 = chain_node(OC_EXEC | Vx); 1262 n2->l.n = nn; 1263 n2->a.n = n; 1264 continue_ptr->a.n = n2; 1265 break_ptr->a.n = n->r.n = seq->last; 1266 1267 continue_ptr = save_cont; 1268 break_ptr = save_brk; 1269 1270 return n; 1271} 1272 1273/* parse group and attach it to chain */ 1274static void chain_group(void) 1275{ 1276 uint32_t c; 1277 node *n, *n2, *n3; 1278 1279 do { 1280 c = next_token(TC_GRPSEQ); 1281 } while (c & TC_NEWLINE); 1282 1283 if (c & TC_GRPSTART) { 1284 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { 1285 if (t_tclass & TC_NEWLINE) continue; 1286 rollback_token(); 1287 chain_group(); 1288 } 1289 } else if (c & (TC_OPSEQ | TC_OPTERM)) { 1290 rollback_token(); 1291 chain_expr(OC_EXEC | Vx); 1292 } else { /* TC_STATEMNT */ 1293 switch (t_info & OPCLSMASK) { 1294 case ST_IF: 1295 n = chain_node(OC_BR | Vx); 1296 n->l.n = condition(); 1297 chain_group(); 1298 n2 = chain_node(OC_EXEC); 1299 n->r.n = seq->last; 1300 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) { 1301 chain_group(); 1302 n2->a.n = seq->last; 1303 } else { 1304 rollback_token(); 1305 } 1306 break; 1307 1308 case ST_WHILE: 1309 n2 = condition(); 1310 n = chain_loop(NULL); 1311 n->l.n = n2; 1312 break; 1313 1314 case ST_DO: 1315 n2 = chain_node(OC_EXEC); 1316 n = chain_loop(NULL); 1317 n2->a.n = n->a.n; 1318 next_token(TC_WHILE); 1319 n->l.n = condition(); 1320 break; 1321 1322 case ST_FOR: 1323 next_token(TC_SEQSTART); 1324 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); 1325 if (t_tclass & TC_SEQTERM) { /* for-in */ 1326 if ((n2->info & OPCLSMASK) != OC_IN) 1327 syntax_error(EMSG_UNEXP_TOKEN); 1328 n = chain_node(OC_WALKINIT | VV); 1329 n->l.n = n2->l.n; 1330 n->r.n = n2->r.n; 1331 n = chain_loop(NULL); 1332 n->info = OC_WALKNEXT | Vx; 1333 n->l.n = n2->l.n; 1334 } else { /* for (;;) */ 1335 n = chain_node(OC_EXEC | Vx); 1336 n->l.n = n2; 1337 n2 = parse_expr(TC_SEMICOL); 1338 n3 = parse_expr(TC_SEQTERM); 1339 n = chain_loop(n3); 1340 n->l.n = n2; 1341 if (!n2) 1342 n->info = OC_EXEC; 1343 } 1344 break; 1345 1346 case OC_PRINT: 1347 case OC_PRINTF: 1348 n = chain_node(t_info); 1349 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM); 1350 if (t_tclass & TC_OUTRDR) { 1351 n->info |= t_info; 1352 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM); 1353 } 1354 if (t_tclass & TC_GRPTERM) 1355 rollback_token(); 1356 break; 1357 1358 case OC_BREAK: 1359 n = chain_node(OC_EXEC); 1360 n->a.n = break_ptr; 1361 break; 1362 1363 case OC_CONTINUE: 1364 n = chain_node(OC_EXEC); 1365 n->a.n = continue_ptr; 1366 break; 1367 1368 /* delete, next, nextfile, return, exit */ 1369 default: 1370 chain_expr(t_info); 1371 } 1372 } 1373} 1374 1375static void parse_program(char *p) 1376{ 1377 uint32_t tclass; 1378 node *cn; 1379 func *f; 1380 var *v; 1381 1382 g_pos = p; 1383 t_lineno = 1; 1384 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | 1385 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) { 1386 1387 if (tclass & TC_OPTERM) 1388 continue; 1389 1390 seq = &mainseq; 1391 if (tclass & TC_BEGIN) { 1392 seq = &beginseq; 1393 chain_group(); 1394 1395 } else if (tclass & TC_END) { 1396 seq = &endseq; 1397 chain_group(); 1398 1399 } else if (tclass & TC_FUNCDECL) { 1400 next_token(TC_FUNCTION); 1401 g_pos++; 1402 f = newfunc(t_string); 1403 f->body.first = NULL; 1404 f->nargs = 0; 1405 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { 1406 v = findvar(ahash, t_string); 1407 v->x.aidx = (f->nargs)++; 1408 1409 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) 1410 break; 1411 } 1412 seq = &(f->body); 1413 chain_group(); 1414 clear_array(ahash); 1415 1416 } else if (tclass & TC_OPSEQ) { 1417 rollback_token(); 1418 cn = chain_node(OC_TEST); 1419 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); 1420 if (t_tclass & TC_GRPSTART) { 1421 rollback_token(); 1422 chain_group(); 1423 } else { 1424 chain_node(OC_PRINT); 1425 } 1426 cn->r.n = mainseq.last; 1427 1428 } else /* if (tclass & TC_GRPSTART) */ { 1429 rollback_token(); 1430 chain_group(); 1431 } 1432 } 1433} 1434 1435 1436/* -------- program execution part -------- */ 1437 1438static node *mk_splitter(const char *s, tsplitter *spl) 1439{ 1440 regex_t *re, *ire; 1441 node *n; 1442 1443 re = &spl->re[0]; 1444 ire = &spl->re[1]; 1445 n = &spl->n; 1446 if ((n->info & OPCLSMASK) == OC_REGEXP) { 1447 regfree(re); 1448 regfree(ire); // TODO: nuke ire, use re+1? 1449 } 1450 if (strlen(s) > 1) { 1451 mk_re_node(s, n, re); 1452 } else { 1453 n->info = (uint32_t) *s; 1454 } 1455 1456 return n; 1457} 1458 1459/* use node as a regular expression. Supplied with node ptr and regex_t 1460 * storage space. Return ptr to regex (if result points to preg, it should 1461 * be later regfree'd manually 1462 */ 1463static regex_t *as_regex(node *op, regex_t *preg) 1464{ 1465 var *v; 1466 const char *s; 1467 1468 if ((op->info & OPCLSMASK) == OC_REGEXP) { 1469 return icase ? op->r.ire : op->l.re; 1470 } 1471 v = nvalloc(1); 1472 s = getvar_s(evaluate(op, v)); 1473 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED); 1474 nvfree(v); 1475 return preg; 1476} 1477 1478/* gradually increasing buffer */ 1479static void qrealloc(char **b, int n, int *size) 1480{ 1481 if (!*b || n >= *size) 1482 *b = xrealloc(*b, *size = n + (n>>1) + 80); 1483} 1484 1485/* resize field storage space */ 1486static void fsrealloc(int size) 1487{ 1488 int i; 1489 1490 if (size >= maxfields) { 1491 i = maxfields; 1492 maxfields = size + 16; 1493 Fields = xrealloc(Fields, maxfields * sizeof(var)); 1494 for (; i < maxfields; i++) { 1495 Fields[i].type = VF_SPECIAL; 1496 Fields[i].string = NULL; 1497 } 1498 } 1499 1500 if (size < nfields) { 1501 for (i = size; i < nfields; i++) { 1502 clrvar(Fields + i); 1503 } 1504 } 1505 nfields = size; 1506} 1507 1508static int awk_split(const char *s, node *spl, char **slist) 1509{ 1510 int l, n = 0; 1511 char c[4]; 1512 char *s1; 1513 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... 1514 1515 /* in worst case, each char would be a separate field */ 1516 *slist = s1 = xzalloc(strlen(s) * 2 + 3); 1517 strcpy(s1, s); 1518 1519 c[0] = c[1] = (char)spl->info; 1520 c[2] = c[3] = '\0'; 1521 if (*getvar_s(intvar[RS]) == '\0') 1522 c[2] = '\n'; 1523 1524 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */ 1525 if (!*s) 1526 return n; /* "": zero fields */ 1527 n++; /* at least one field will be there */ 1528 do { 1529 l = strcspn(s, c+2); /* len till next NUL or \n */ 1530 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0 1531 && pmatch[0].rm_so <= l 1532 ) { 1533 l = pmatch[0].rm_so; 1534 if (pmatch[0].rm_eo == 0) { 1535 l++; 1536 pmatch[0].rm_eo++; 1537 } 1538 n++; /* we saw yet another delimiter */ 1539 } else { 1540 pmatch[0].rm_eo = l; 1541 if (s[l]) pmatch[0].rm_eo++; 1542 } 1543 memcpy(s1, s, l); 1544 s1[l] = '\0'; 1545 nextword(&s1); 1546 s += pmatch[0].rm_eo; 1547 } while (*s); 1548 return n; 1549 } 1550 if (c[0] == '\0') { /* null split */ 1551 while (*s) { 1552 *s1++ = *s++; 1553 *s1++ = '\0'; 1554 n++; 1555 } 1556 return n; 1557 } 1558 if (c[0] != ' ') { /* single-character split */ 1559 if (icase) { 1560 c[0] = toupper(c[0]); 1561 c[1] = tolower(c[1]); 1562 } 1563 if (*s1) n++; 1564 while ((s1 = strpbrk(s1, c))) { 1565 *s1++ = '\0'; 1566 n++; 1567 } 1568 return n; 1569 } 1570 /* space split */ 1571 while (*s) { 1572 s = skip_whitespace(s); 1573 if (!*s) break; 1574 n++; 1575 while (*s && !isspace(*s)) 1576 *s1++ = *s++; 1577 *s1++ = '\0'; 1578 } 1579 return n; 1580} 1581 1582static void split_f0(void) 1583{ 1584/* static char *fstrings; */ 1585#define fstrings (G.split_f0__fstrings) 1586 1587 int i, n; 1588 char *s; 1589 1590 if (is_f0_split) 1591 return; 1592 1593 is_f0_split = TRUE; 1594 free(fstrings); 1595 fsrealloc(0); 1596 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings); 1597 fsrealloc(n); 1598 s = fstrings; 1599 for (i = 0; i < n; i++) { 1600 Fields[i].string = nextword(&s); 1601 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY); 1602 } 1603 1604 /* set NF manually to avoid side effects */ 1605 clrvar(intvar[NF]); 1606 intvar[NF]->type = VF_NUMBER | VF_SPECIAL; 1607 intvar[NF]->number = nfields; 1608#undef fstrings 1609} 1610 1611/* perform additional actions when some internal variables changed */ 1612static void handle_special(var *v) 1613{ 1614 int n; 1615 char *b; 1616 const char *sep, *s; 1617 int sl, l, len, i, bsize; 1618 1619 if (!(v->type & VF_SPECIAL)) 1620 return; 1621 1622 if (v == intvar[NF]) { 1623 n = (int)getvar_i(v); 1624 fsrealloc(n); 1625 1626 /* recalculate $0 */ 1627 sep = getvar_s(intvar[OFS]); 1628 sl = strlen(sep); 1629 b = NULL; 1630 len = 0; 1631 for (i = 0; i < n; i++) { 1632 s = getvar_s(&Fields[i]); 1633 l = strlen(s); 1634 if (b) { 1635 memcpy(b+len, sep, sl); 1636 len += sl; 1637 } 1638 qrealloc(&b, len+l+sl, &bsize); 1639 memcpy(b+len, s, l); 1640 len += l; 1641 } 1642 if (b) 1643 b[len] = '\0'; 1644 setvar_p(intvar[F0], b); 1645 is_f0_split = TRUE; 1646 1647 } else if (v == intvar[F0]) { 1648 is_f0_split = FALSE; 1649 1650 } else if (v == intvar[FS]) { 1651 mk_splitter(getvar_s(v), &fsplitter); 1652 1653 } else if (v == intvar[RS]) { 1654 mk_splitter(getvar_s(v), &rsplitter); 1655 1656 } else if (v == intvar[IGNORECASE]) { 1657 icase = istrue(v); 1658 1659 } else { /* $n */ 1660 n = getvar_i(intvar[NF]); 1661 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1); 1662 /* right here v is invalid. Just to note... */ 1663 } 1664} 1665 1666/* step through func/builtin/etc arguments */ 1667static node *nextarg(node **pn) 1668{ 1669 node *n; 1670 1671 n = *pn; 1672 if (n && (n->info & OPCLSMASK) == OC_COMMA) { 1673 *pn = n->r.n; 1674 n = n->l.n; 1675 } else { 1676 *pn = NULL; 1677 } 1678 return n; 1679} 1680 1681static void hashwalk_init(var *v, xhash *array) 1682{ 1683 char **w; 1684 hash_item *hi; 1685 int i; 1686 1687 if (v->type & VF_WALK) 1688 free(v->x.walker); 1689 1690 v->type |= VF_WALK; 1691 w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen); 1692 w[0] = w[1] = (char *)(w + 2); 1693 for (i = 0; i < array->csize; i++) { 1694 hi = array->items[i]; 1695 while (hi) { 1696 strcpy(*w, hi->name); 1697 nextword(w); 1698 hi = hi->next; 1699 } 1700 } 1701} 1702 1703static int hashwalk_next(var *v) 1704{ 1705 char **w; 1706 1707 w = v->x.walker; 1708 if (w[1] == w[0]) 1709 return FALSE; 1710 1711 setvar_s(v, nextword(w+1)); 1712 return TRUE; 1713} 1714 1715/* evaluate node, return 1 when result is true, 0 otherwise */ 1716static int ptest(node *pattern) 1717{ 1718 /* ptest__v is "static": to save stack space? */ 1719 return istrue(evaluate(pattern, &G.ptest__v)); 1720} 1721 1722/* read next record from stream rsm into a variable v */ 1723static int awk_getline(rstream *rsm, var *v) 1724{ 1725 char *b; 1726 regmatch_t pmatch[2]; 1727 int a, p, pp=0, size; 1728 int fd, so, eo, r, rp; 1729 char c, *m, *s; 1730 1731 /* we're using our own buffer since we need access to accumulating 1732 * characters 1733 */ 1734 fd = fileno(rsm->F); 1735 m = rsm->buffer; 1736 a = rsm->adv; 1737 p = rsm->pos; 1738 size = rsm->size; 1739 c = (char) rsplitter.n.info; 1740 rp = 0; 1741 1742 if (!m) qrealloc(&m, 256, &size); 1743 do { 1744 b = m + a; 1745 so = eo = p; 1746 r = 1; 1747 if (p > 0) { 1748 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) { 1749 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re, 1750 b, 1, pmatch, 0) == 0) { 1751 so = pmatch[0].rm_so; 1752 eo = pmatch[0].rm_eo; 1753 if (b[eo] != '\0') 1754 break; 1755 } 1756 } else if (c != '\0') { 1757 s = strchr(b+pp, c); 1758 if (!s) s = memchr(b+pp, '\0', p - pp); 1759 if (s) { 1760 so = eo = s-b; 1761 eo++; 1762 break; 1763 } 1764 } else { 1765 while (b[rp] == '\n') 1766 rp++; 1767 s = strstr(b+rp, "\n\n"); 1768 if (s) { 1769 so = eo = s-b; 1770 while (b[eo] == '\n') eo++; 1771 if (b[eo] != '\0') 1772 break; 1773 } 1774 } 1775 } 1776 1777 if (a > 0) { 1778 memmove(m, (const void *)(m+a), p+1); 1779 b = m; 1780 a = 0; 1781 } 1782 1783 qrealloc(&m, a+p+128, &size); 1784 b = m + a; 1785 pp = p; 1786 p += safe_read(fd, b+p, size-p-1); 1787 if (p < pp) { 1788 p = 0; 1789 r = 0; 1790 setvar_i(intvar[ERRNO], errno); 1791 } 1792 b[p] = '\0'; 1793 1794 } while (p > pp); 1795 1796 if (p == 0) { 1797 r--; 1798 } else { 1799 c = b[so]; b[so] = '\0'; 1800 setvar_s(v, b+rp); 1801 v->type |= VF_USER; 1802 b[so] = c; 1803 c = b[eo]; b[eo] = '\0'; 1804 setvar_s(intvar[RT], b+so); 1805 b[eo] = c; 1806 } 1807 1808 rsm->buffer = m; 1809 rsm->adv = a + eo; 1810 rsm->pos = p - eo; 1811 rsm->size = size; 1812 1813 return r; 1814} 1815 1816static int fmt_num(char *b, int size, const char *format, double n, int int_as_int) 1817{ 1818 int r = 0; 1819 char c; 1820 const char *s = format; 1821 1822 if (int_as_int && n == (int)n) { 1823 r = snprintf(b, size, "%d", (int)n); 1824 } else { 1825 do { c = *s; } while (c && *++s); 1826 if (strchr("diouxX", c)) { 1827 r = snprintf(b, size, format, (int)n); 1828 } else if (strchr("eEfgG", c)) { 1829 r = snprintf(b, size, format, n); 1830 } else { 1831 syntax_error(EMSG_INV_FMT); 1832 } 1833 } 1834 return r; 1835} 1836 1837 1838/* formatted output into an allocated buffer, return ptr to buffer */ 1839static char *awk_printf(node *n) 1840{ 1841 char *b = NULL; 1842 char *fmt, *s, *f; 1843 const char *s1; 1844 int i, j, incr, bsize; 1845 char c, c1; 1846 var *v, *arg; 1847 1848 v = nvalloc(1); 1849 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v))); 1850 1851 i = 0; 1852 while (*f) { 1853 s = f; 1854 while (*f && (*f != '%' || *(++f) == '%')) 1855 f++; 1856 while (*f && !isalpha(*f)) { 1857 if (*f == '*') 1858 syntax_error("%*x formats are not supported"); 1859 f++; 1860 } 1861 1862 incr = (f - s) + MAXVARFMT; 1863 qrealloc(&b, incr + i, &bsize); 1864 c = *f; 1865 if (c != '\0') f++; 1866 c1 = *f; 1867 *f = '\0'; 1868 arg = evaluate(nextarg(&n), v); 1869 1870 j = i; 1871 if (c == 'c' || !c) { 1872 i += sprintf(b+i, s, is_numeric(arg) ? 1873 (char)getvar_i(arg) : *getvar_s(arg)); 1874 } else if (c == 's') { 1875 s1 = getvar_s(arg); 1876 qrealloc(&b, incr+i+strlen(s1), &bsize); 1877 i += sprintf(b+i, s, s1); 1878 } else { 1879 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE); 1880 } 1881 *f = c1; 1882 1883 /* if there was an error while sprintf, return value is negative */ 1884 if (i < j) i = j; 1885 } 1886 1887 b = xrealloc(b, i + 1); 1888 free(fmt); 1889 nvfree(v); 1890 b[i] = '\0'; 1891 return b; 1892} 1893 1894/* common substitution routine 1895 * replace (nm) substring of (src) that match (n) with (repl), store 1896 * result into (dest), return number of substitutions. If nm=0, replace 1897 * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable 1898 * subexpression matching (\1-\9) 1899 */ 1900static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex) 1901{ 1902 char *ds = NULL; 1903 const char *s; 1904 const char *sp; 1905 int c, i, j, di, rl, so, eo, nbs, n, dssize; 1906 regmatch_t pmatch[10]; 1907 regex_t sreg, *re; 1908 1909 re = as_regex(rn, &sreg); 1910 if (!src) src = intvar[F0]; 1911 if (!dest) dest = intvar[F0]; 1912 1913 i = di = 0; 1914 sp = getvar_s(src); 1915 rl = strlen(repl); 1916 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) { 1917 so = pmatch[0].rm_so; 1918 eo = pmatch[0].rm_eo; 1919 1920 qrealloc(&ds, di + eo + rl, &dssize); 1921 memcpy(ds + di, sp, eo); 1922 di += eo; 1923 if (++i >= nm) { 1924 /* replace */ 1925 di -= (eo - so); 1926 nbs = 0; 1927 for (s = repl; *s; s++) { 1928 ds[di++] = c = *s; 1929 if (c == '\\') { 1930 nbs++; 1931 continue; 1932 } 1933 if (c == '&' || (ex && c >= '0' && c <= '9')) { 1934 di -= ((nbs + 3) >> 1); 1935 j = 0; 1936 if (c != '&') { 1937 j = c - '0'; 1938 nbs++; 1939 } 1940 if (nbs % 2) { 1941 ds[di++] = c; 1942 } else { 1943 n = pmatch[j].rm_eo - pmatch[j].rm_so; 1944 qrealloc(&ds, di + rl + n, &dssize); 1945 memcpy(ds + di, sp + pmatch[j].rm_so, n); 1946 di += n; 1947 } 1948 } 1949 nbs = 0; 1950 } 1951 } 1952 1953 sp += eo; 1954 if (i == nm) break; 1955 if (eo == so) { 1956 ds[di] = *sp++; 1957 if (!ds[di++]) break; 1958 } 1959 } 1960 1961 qrealloc(&ds, di + strlen(sp), &dssize); 1962 strcpy(ds + di, sp); 1963 setvar_p(dest, ds); 1964 if (re == &sreg) regfree(re); 1965 return i; 1966} 1967 1968static var *exec_builtin(node *op, var *res) 1969{ 1970#define tspl (G.exec_builtin__tspl) 1971 1972 int (*to_xxx)(int); 1973 var *tv; 1974 node *an[4]; 1975 var *av[4]; 1976 const char *as[4]; 1977 regmatch_t pmatch[2]; 1978 regex_t sreg, *re; 1979 node *spl; 1980 uint32_t isr, info; 1981 int nargs; 1982 time_t tt; 1983 char *s, *s1; 1984 int i, l, ll, n; 1985 1986 tv = nvalloc(4); 1987 isr = info = op->info; 1988 op = op->l.n; 1989 1990 av[2] = av[3] = NULL; 1991 for (i = 0; i < 4 && op; i++) { 1992 an[i] = nextarg(&op); 1993 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]); 1994 if (isr & 0x08000000) as[i] = getvar_s(av[i]); 1995 isr >>= 1; 1996 } 1997 1998 nargs = i; 1999 if (nargs < (info >> 30)) 2000 syntax_error(EMSG_TOO_FEW_ARGS); 2001 2002 switch (info & OPNMASK) { 2003 2004 case B_a2: 2005#if ENABLE_FEATURE_AWK_MATH 2006 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1]))); 2007#else 2008 syntax_error(EMSG_NO_MATH); 2009#endif 2010 break; 2011 2012 case B_sp: 2013 if (nargs > 2) { 2014 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ? 2015 an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl); 2016 } else { 2017 spl = &fsplitter.n; 2018 } 2019 2020 n = awk_split(as[0], spl, &s); 2021 s1 = s; 2022 clear_array(iamarray(av[1])); 2023 for (i=1; i<=n; i++) 2024 setari_u(av[1], i, nextword(&s1)); 2025 free(s); 2026 setvar_i(res, n); 2027 break; 2028 2029 case B_ss: 2030 l = strlen(as[0]); 2031 i = getvar_i(av[1]) - 1; 2032 if (i > l) i = l; 2033 if (i < 0) i = 0; 2034 n = (nargs > 2) ? getvar_i(av[2]) : l-i; 2035 if (n < 0) n = 0; 2036 s = xmalloc(n+1); 2037 strncpy(s, as[0]+i, n); 2038 s[n] = '\0'; 2039 setvar_p(res, s); 2040 break; 2041 2042 case B_an: 2043 setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1])); 2044 break; 2045 2046 case B_co: 2047 setvar_i(res, ~(long)getvar_i(av[0])); 2048 break; 2049 2050 case B_ls: 2051 setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1])); 2052 break; 2053 2054 case B_or: 2055 setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1])); 2056 break; 2057 2058 case B_rs: 2059 setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1]))); 2060 break; 2061 2062 case B_xo: 2063 setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1])); 2064 break; 2065 2066 case B_lo: 2067 to_xxx = tolower; 2068 goto lo_cont; 2069 2070 case B_up: 2071 to_xxx = toupper; 2072 lo_cont: 2073 s1 = s = xstrdup(as[0]); 2074 while (*s1) { 2075 *s1 = (*to_xxx)(*s1); 2076 s1++; 2077 } 2078 setvar_p(res, s); 2079 break; 2080 2081 case B_ix: 2082 n = 0; 2083 ll = strlen(as[1]); 2084 l = strlen(as[0]) - ll; 2085 if (ll > 0 && l >= 0) { 2086 if (!icase) { 2087 s = strstr(as[0], as[1]); 2088 if (s) n = (s - as[0]) + 1; 2089 } else { 2090 /* this piece of code is terribly slow and 2091 * really should be rewritten 2092 */ 2093 for (i=0; i<=l; i++) { 2094 if (strncasecmp(as[0]+i, as[1], ll) == 0) { 2095 n = i+1; 2096 break; 2097 } 2098 } 2099 } 2100 } 2101 setvar_i(res, n); 2102 break; 2103 2104 case B_ti: 2105 if (nargs > 1) 2106 tt = getvar_i(av[1]); 2107 else 2108 time(&tt); 2109 //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"; 2110 i = strftime(g_buf, MAXVARFMT, 2111 ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"), 2112 localtime(&tt)); 2113 g_buf[i] = '\0'; 2114 setvar_s(res, g_buf); 2115 break; 2116 2117 case B_ma: 2118 re = as_regex(an[1], &sreg); 2119 n = regexec(re, as[0], 1, pmatch, 0); 2120 if (n == 0) { 2121 pmatch[0].rm_so++; 2122 pmatch[0].rm_eo++; 2123 } else { 2124 pmatch[0].rm_so = 0; 2125 pmatch[0].rm_eo = -1; 2126 } 2127 setvar_i(newvar("RSTART"), pmatch[0].rm_so); 2128 setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so); 2129 setvar_i(res, pmatch[0].rm_so); 2130 if (re == &sreg) regfree(re); 2131 break; 2132 2133 case B_ge: 2134 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE); 2135 break; 2136 2137 case B_gs: 2138 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE)); 2139 break; 2140 2141 case B_su: 2142 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE)); 2143 break; 2144 } 2145 2146 nvfree(tv); 2147 return res; 2148#undef tspl 2149} 2150 2151/* 2152 * Evaluate node - the heart of the program. Supplied with subtree 2153 * and place where to store result. returns ptr to result. 2154 */ 2155#define XC(n) ((n) >> 8) 2156 2157static var *evaluate(node *op, var *res) 2158{ 2159/* This procedure is recursive so we should count every byte */ 2160#define fnargs (G.evaluate__fnargs) 2161/* seed is initialized to 1 */ 2162#define seed (G.evaluate__seed) 2163#define sreg (G.evaluate__sreg) 2164 2165 node *op1; 2166 var *v1; 2167 union { 2168 var *v; 2169 const char *s; 2170 double d; 2171 int i; 2172 } L, R; 2173 uint32_t opinfo; 2174 int opn; 2175 union { 2176 char *s; 2177 rstream *rsm; 2178 FILE *F; 2179 var *v; 2180 regex_t *re; 2181 uint32_t info; 2182 } X; 2183 2184 if (!op) 2185 return setvar_s(res, NULL); 2186 2187 v1 = nvalloc(2); 2188 2189 while (op) { 2190 opinfo = op->info; 2191 opn = (opinfo & OPNMASK); 2192 g_lineno = op->lineno; 2193 2194 /* execute inevitable things */ 2195 op1 = op->l.n; 2196 if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1); 2197 if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1); 2198 if (opinfo & OF_STR1) L.s = getvar_s(L.v); 2199 if (opinfo & OF_STR2) R.s = getvar_s(R.v); 2200 if (opinfo & OF_NUM1) L.d = getvar_i(L.v); 2201 2202 switch (XC(opinfo & OPCLSMASK)) { 2203 2204 /* -- iterative node type -- */ 2205 2206 /* test pattern */ 2207 case XC( OC_TEST ): 2208 if ((op1->info & OPCLSMASK) == OC_COMMA) { 2209 /* it's range pattern */ 2210 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) { 2211 op->info |= OF_CHECKED; 2212 if (ptest(op1->r.n)) 2213 op->info &= ~OF_CHECKED; 2214 2215 op = op->a.n; 2216 } else { 2217 op = op->r.n; 2218 } 2219 } else { 2220 op = (ptest(op1)) ? op->a.n : op->r.n; 2221 } 2222 break; 2223 2224 /* just evaluate an expression, also used as unconditional jump */ 2225 case XC( OC_EXEC ): 2226 break; 2227 2228 /* branch, used in if-else and various loops */ 2229 case XC( OC_BR ): 2230 op = istrue(L.v) ? op->a.n : op->r.n; 2231 break; 2232 2233 /* initialize for-in loop */ 2234 case XC( OC_WALKINIT ): 2235 hashwalk_init(L.v, iamarray(R.v)); 2236 break; 2237 2238 /* get next array item */ 2239 case XC( OC_WALKNEXT ): 2240 op = hashwalk_next(L.v) ? op->a.n : op->r.n; 2241 break; 2242 2243 case XC( OC_PRINT ): 2244 case XC( OC_PRINTF ): 2245 X.F = stdout; 2246 if (op->r.n) { 2247 X.rsm = newfile(R.s); 2248 if (!X.rsm->F) { 2249 if (opn == '|') { 2250 X.rsm->F = popen(R.s, "w"); 2251 if (X.rsm->F == NULL) 2252 bb_perror_msg_and_die("popen"); 2253 X.rsm->is_pipe = 1; 2254 } else { 2255 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a"); 2256 } 2257 } 2258 X.F = X.rsm->F; 2259 } 2260 2261 if ((opinfo & OPCLSMASK) == OC_PRINT) { 2262 if (!op1) { 2263 fputs(getvar_s(intvar[F0]), X.F); 2264 } else { 2265 while (op1) { 2266 L.v = evaluate(nextarg(&op1), v1); 2267 if (L.v->type & VF_NUMBER) { 2268 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]), 2269 getvar_i(L.v), TRUE); 2270 fputs(g_buf, X.F); 2271 } else { 2272 fputs(getvar_s(L.v), X.F); 2273 } 2274 2275 if (op1) fputs(getvar_s(intvar[OFS]), X.F); 2276 } 2277 } 2278 fputs(getvar_s(intvar[ORS]), X.F); 2279 2280 } else { /* OC_PRINTF */ 2281 L.s = awk_printf(op1); 2282 fputs(L.s, X.F); 2283 free((char*)L.s); 2284 } 2285 fflush(X.F); 2286 break; 2287 2288 case XC( OC_DELETE ): 2289 X.info = op1->info & OPCLSMASK; 2290 if (X.info == OC_VAR) { 2291 R.v = op1->l.v; 2292 } else if (X.info == OC_FNARG) { 2293 R.v = &fnargs[op1->l.i]; 2294 } else { 2295 syntax_error(EMSG_NOT_ARRAY); 2296 } 2297 2298 if (op1->r.n) { 2299 clrvar(L.v); 2300 L.s = getvar_s(evaluate(op1->r.n, v1)); 2301 hash_remove(iamarray(R.v), L.s); 2302 } else { 2303 clear_array(iamarray(R.v)); 2304 } 2305 break; 2306 2307 case XC( OC_NEWSOURCE ): 2308 g_progname = op->l.s; 2309 break; 2310 2311 case XC( OC_RETURN ): 2312 copyvar(res, L.v); 2313 break; 2314 2315 case XC( OC_NEXTFILE ): 2316 nextfile = TRUE; 2317 case XC( OC_NEXT ): 2318 nextrec = TRUE; 2319 case XC( OC_DONE ): 2320 clrvar(res); 2321 break; 2322 2323 case XC( OC_EXIT ): 2324 awk_exit(L.d); 2325 2326 /* -- recursive node type -- */ 2327 2328 case XC( OC_VAR ): 2329 L.v = op->l.v; 2330 if (L.v == intvar[NF]) 2331 split_f0(); 2332 goto v_cont; 2333 2334 case XC( OC_FNARG ): 2335 L.v = &fnargs[op->l.i]; 2336 v_cont: 2337 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v; 2338 break; 2339 2340 case XC( OC_IN ): 2341 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0); 2342 break; 2343 2344 case XC( OC_REGEXP ): 2345 op1 = op; 2346 L.s = getvar_s(intvar[F0]); 2347 goto re_cont; 2348 2349 case XC( OC_MATCH ): 2350 op1 = op->r.n; 2351 re_cont: 2352 X.re = as_regex(op1, &sreg); 2353 R.i = regexec(X.re, L.s, 0, NULL, 0); 2354 if (X.re == &sreg) regfree(X.re); 2355 setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0)); 2356 break; 2357 2358 case XC( OC_MOVE ): 2359 /* if source is a temporary string, jusk relink it to dest */ 2360 if (R.v == v1+1 && R.v->string) { 2361 res = setvar_p(L.v, R.v->string); 2362 R.v->string = NULL; 2363 } else { 2364 res = copyvar(L.v, R.v); 2365 } 2366 break; 2367 2368 case XC( OC_TERNARY ): 2369 if ((op->r.n->info & OPCLSMASK) != OC_COLON) 2370 syntax_error(EMSG_POSSIBLE_ERROR); 2371 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); 2372 break; 2373 2374 case XC( OC_FUNC ): 2375 if (!op->r.f->body.first) 2376 syntax_error(EMSG_UNDEF_FUNC); 2377 2378 X.v = R.v = nvalloc(op->r.f->nargs+1); 2379 while (op1) { 2380 L.v = evaluate(nextarg(&op1), v1); 2381 copyvar(R.v, L.v); 2382 R.v->type |= VF_CHILD; 2383 R.v->x.parent = L.v; 2384 if (++R.v - X.v >= op->r.f->nargs) 2385 break; 2386 } 2387 2388 R.v = fnargs; 2389 fnargs = X.v; 2390 2391 L.s = g_progname; 2392 res = evaluate(op->r.f->body.first, res); 2393 g_progname = L.s; 2394 2395 nvfree(fnargs); 2396 fnargs = R.v; 2397 break; 2398 2399 case XC( OC_GETLINE ): 2400 case XC( OC_PGETLINE ): 2401 if (op1) { 2402 X.rsm = newfile(L.s); 2403 if (!X.rsm->F) { 2404 if ((opinfo & OPCLSMASK) == OC_PGETLINE) { 2405 X.rsm->F = popen(L.s, "r"); 2406 X.rsm->is_pipe = TRUE; 2407 } else { 2408 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */ 2409 } 2410 } 2411 } else { 2412 if (!iF) iF = next_input_file(); 2413 X.rsm = iF; 2414 } 2415 2416 if (!X.rsm->F) { 2417 setvar_i(intvar[ERRNO], errno); 2418 setvar_i(res, -1); 2419 break; 2420 } 2421 2422 if (!op->r.n) 2423 R.v = intvar[F0]; 2424 2425 L.i = awk_getline(X.rsm, R.v); 2426 if (L.i > 0) { 2427 if (!op1) { 2428 incvar(intvar[FNR]); 2429 incvar(intvar[NR]); 2430 } 2431 } 2432 setvar_i(res, L.i); 2433 break; 2434 2435 /* simple builtins */ 2436 case XC( OC_FBLTIN ): 2437 switch (opn) { 2438 2439 case F_in: 2440 R.d = (int)L.d; 2441 break; 2442 2443 case F_rn: 2444 R.d = (double)rand() / (double)RAND_MAX; 2445 break; 2446#if ENABLE_FEATURE_AWK_MATH 2447 case F_co: 2448 R.d = cos(L.d); 2449 break; 2450 2451 case F_ex: 2452 R.d = exp(L.d); 2453 break; 2454 2455 case F_lg: 2456 R.d = log(L.d); 2457 break; 2458 2459 case F_si: 2460 R.d = sin(L.d); 2461 break; 2462 2463 case F_sq: 2464 R.d = sqrt(L.d); 2465 break; 2466#else 2467 case F_co: 2468 case F_ex: 2469 case F_lg: 2470 case F_si: 2471 case F_sq: 2472 syntax_error(EMSG_NO_MATH); 2473 break; 2474#endif 2475 case F_sr: 2476 R.d = (double)seed; 2477 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL); 2478 srand(seed); 2479 break; 2480 2481 case F_ti: 2482 R.d = time(NULL); 2483 break; 2484 2485 case F_le: 2486 if (!op1) 2487 L.s = getvar_s(intvar[F0]); 2488 R.d = strlen(L.s); 2489 break; 2490 2491 case F_sy: 2492 fflush(NULL); 2493 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s) 2494 ? (system(L.s) >> 8) : 0; 2495 break; 2496 2497 case F_ff: 2498 if (!op1) 2499 fflush(stdout); 2500 else { 2501 if (L.s && *L.s) { 2502 X.rsm = newfile(L.s); 2503 fflush(X.rsm->F); 2504 } else { 2505 fflush(NULL); 2506 } 2507 } 2508 break; 2509 2510 case F_cl: 2511 X.rsm = (rstream *)hash_search(fdhash, L.s); 2512 if (X.rsm) { 2513 R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F); 2514 free(X.rsm->buffer); 2515 hash_remove(fdhash, L.s); 2516 } 2517 if (R.i != 0) 2518 setvar_i(intvar[ERRNO], errno); 2519 R.d = (double)R.i; 2520 break; 2521 } 2522 setvar_i(res, R.d); 2523 break; 2524 2525 case XC( OC_BUILTIN ): 2526 res = exec_builtin(op, res); 2527 break; 2528 2529 case XC( OC_SPRINTF ): 2530 setvar_p(res, awk_printf(op1)); 2531 break; 2532 2533 case XC( OC_UNARY ): 2534 X.v = R.v; 2535 L.d = R.d = getvar_i(R.v); 2536 switch (opn) { 2537 case 'P': 2538 L.d = ++R.d; 2539 goto r_op_change; 2540 case 'p': 2541 R.d++; 2542 goto r_op_change; 2543 case 'M': 2544 L.d = --R.d; 2545 goto r_op_change; 2546 case 'm': 2547 R.d--; 2548 goto r_op_change; 2549 case '!': 2550 L.d = istrue(X.v) ? 0 : 1; 2551 break; 2552 case '-': 2553 L.d = -R.d; 2554 break; 2555 r_op_change: 2556 setvar_i(X.v, R.d); 2557 } 2558 setvar_i(res, L.d); 2559 break; 2560 2561 case XC( OC_FIELD ): 2562 R.i = (int)getvar_i(R.v); 2563 if (R.i == 0) { 2564 res = intvar[F0]; 2565 } else { 2566 split_f0(); 2567 if (R.i > nfields) 2568 fsrealloc(R.i); 2569 res = &Fields[R.i - 1]; 2570 } 2571 break; 2572 2573 /* concatenation (" ") and index joining (",") */ 2574 case XC( OC_CONCAT ): 2575 case XC( OC_COMMA ): 2576 opn = strlen(L.s) + strlen(R.s) + 2; 2577 X.s = xmalloc(opn); 2578 strcpy(X.s, L.s); 2579 if ((opinfo & OPCLSMASK) == OC_COMMA) { 2580 L.s = getvar_s(intvar[SUBSEP]); 2581 X.s = xrealloc(X.s, opn + strlen(L.s)); 2582 strcat(X.s, L.s); 2583 } 2584 strcat(X.s, R.s); 2585 setvar_p(res, X.s); 2586 break; 2587 2588 case XC( OC_LAND ): 2589 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0); 2590 break; 2591 2592 case XC( OC_LOR ): 2593 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n)); 2594 break; 2595 2596 case XC( OC_BINARY ): 2597 case XC( OC_REPLACE ): 2598 R.d = getvar_i(R.v); 2599 switch (opn) { 2600 case '+': 2601 L.d += R.d; 2602 break; 2603 case '-': 2604 L.d -= R.d; 2605 break; 2606 case '*': 2607 L.d *= R.d; 2608 break; 2609 case '/': 2610 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO); 2611 L.d /= R.d; 2612 break; 2613 case '&': 2614#if ENABLE_FEATURE_AWK_MATH 2615 L.d = pow(L.d, R.d); 2616#else 2617 syntax_error(EMSG_NO_MATH); 2618#endif 2619 break; 2620 case '%': 2621 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO); 2622 L.d -= (int)(L.d / R.d) * R.d; 2623 break; 2624 } 2625 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d); 2626 break; 2627 2628 case XC( OC_COMPARE ): 2629 if (is_numeric(L.v) && is_numeric(R.v)) { 2630 L.d = getvar_i(L.v) - getvar_i(R.v); 2631 } else { 2632 L.s = getvar_s(L.v); 2633 R.s = getvar_s(R.v); 2634 L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s); 2635 } 2636 switch (opn & 0xfe) { 2637 case 0: 2638 R.i = (L.d > 0); 2639 break; 2640 case 2: 2641 R.i = (L.d >= 0); 2642 break; 2643 case 4: 2644 R.i = (L.d == 0); 2645 break; 2646 } 2647 setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0); 2648 break; 2649 2650 default: 2651 syntax_error(EMSG_POSSIBLE_ERROR); 2652 } 2653 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS) 2654 op = op->a.n; 2655 if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS) 2656 break; 2657 if (nextrec) 2658 break; 2659 } 2660 nvfree(v1); 2661 return res; 2662#undef fnargs 2663#undef seed 2664#undef sreg 2665} 2666 2667 2668/* -------- main & co. -------- */ 2669 2670static int awk_exit(int r) 2671{ 2672 var tv; 2673 unsigned i; 2674 hash_item *hi; 2675 2676 zero_out_var(&tv); 2677 2678 if (!exiting) { 2679 exiting = TRUE; 2680 nextrec = FALSE; 2681 evaluate(endseq.first, &tv); 2682 } 2683 2684 /* waiting for children */ 2685 for (i = 0; i < fdhash->csize; i++) { 2686 hi = fdhash->items[i]; 2687 while (hi) { 2688 if (hi->data.rs.F && hi->data.rs.is_pipe) 2689 pclose(hi->data.rs.F); 2690 hi = hi->next; 2691 } 2692 } 2693 2694 exit(r); 2695} 2696 2697/* if expr looks like "var=value", perform assignment and return 1, 2698 * otherwise return 0 */ 2699static int is_assignment(const char *expr) 2700{ 2701 char *exprc, *s, *s0, *s1; 2702 2703 exprc = xstrdup(expr); 2704 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) { 2705 free(exprc); 2706 return FALSE; 2707 } 2708 2709 *(s++) = '\0'; 2710 s0 = s1 = s; 2711 while (*s) 2712 *(s1++) = nextchar(&s); 2713 2714 *s1 = '\0'; 2715 setvar_u(newvar(exprc), s0); 2716 free(exprc); 2717 return TRUE; 2718} 2719 2720/* switch to next input file */ 2721static rstream *next_input_file(void) 2722{ 2723#define rsm (G.next_input_file__rsm) 2724#define files_happen (G.next_input_file__files_happen) 2725 2726 FILE *F = NULL; 2727 const char *fname, *ind; 2728 2729 if (rsm.F) fclose(rsm.F); 2730 rsm.F = NULL; 2731 rsm.pos = rsm.adv = 0; 2732 2733 do { 2734 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) { 2735 if (files_happen) 2736 return NULL; 2737 fname = "-"; 2738 F = stdin; 2739 } else { 2740 ind = getvar_s(incvar(intvar[ARGIND])); 2741 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind)); 2742 if (fname && *fname && !is_assignment(fname)) 2743 F = afopen(fname, "r"); 2744 } 2745 } while (!F); 2746 2747 files_happen = TRUE; 2748 setvar_s(intvar[FILENAME], fname); 2749 rsm.F = F; 2750 return &rsm; 2751#undef rsm 2752#undef files_happen 2753} 2754 2755int awk_main(int argc, char **argv); 2756int awk_main(int argc, char **argv) 2757{ 2758 unsigned opt; 2759 char *opt_F, *opt_W; 2760 llist_t *opt_v = NULL; 2761 int i, j, flen; 2762 var *v; 2763 var tv; 2764 char **envp; 2765 char *vnames = (char *)vNames; /* cheat */ 2766 char *vvalues = (char *)vValues; 2767 2768 INIT_G(); 2769 2770 /* Undo busybox.c, or else strtod may eat ','! This breaks parsing: 2771 * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */ 2772 if (ENABLE_LOCALE_SUPPORT) 2773 setlocale(LC_NUMERIC, "C"); 2774 2775 zero_out_var(&tv); 2776 2777 /* allocate global buffer */ 2778 g_buf = xmalloc(MAXVARFMT + 1); 2779 2780 vhash = hash_init(); 2781 ahash = hash_init(); 2782 fdhash = hash_init(); 2783 fnhash = hash_init(); 2784 2785 /* initialize variables */ 2786 for (i = 0; *vnames; i++) { 2787 intvar[i] = v = newvar(nextword(&vnames)); 2788 if (*vvalues != '\377') 2789 setvar_s(v, nextword(&vvalues)); 2790 else 2791 setvar_i(v, 0); 2792 2793 if (*vnames == '*') { 2794 v->type |= VF_SPECIAL; 2795 vnames++; 2796 } 2797 } 2798 2799 handle_special(intvar[FS]); 2800 handle_special(intvar[RS]); 2801 2802 newfile("/dev/stdin")->F = stdin; 2803 newfile("/dev/stdout")->F = stdout; 2804 newfile("/dev/stderr")->F = stderr; 2805 2806 /* Huh, people report that sometimes environ is NULL. Oh well. */ 2807 if (environ) for (envp = environ; *envp; envp++) { 2808 /* environ is writable, thus we don't strdup it needlessly */ 2809 char *s = *envp; 2810 char *s1 = strchr(s, '='); 2811 if (s1) { 2812 *s1 = '\0'; 2813 /* Both findvar and setvar_u take const char* 2814 * as 2nd arg -> environment is not trashed */ 2815 setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1); 2816 *s1 = '='; 2817 } 2818 } 2819 opt_complementary = "v::"; 2820 opt = getopt32(argv, "F:v:f:W:", &opt_F, &opt_v, &g_progname, &opt_W); 2821 argv += optind; 2822 argc -= optind; 2823 if (opt & 0x1) 2824 setvar_s(intvar[FS], opt_F); // -F 2825 while (opt_v) { /* -v */ 2826 if (!is_assignment(llist_pop(&opt_v))) 2827 bb_show_usage(); 2828 } 2829 if (opt & 0x4) { // -f 2830 char *s = s; /* die, gcc, die */ 2831 FILE *from_file = afopen(g_progname, "r"); 2832 /* one byte is reserved for some trick in next_token */ 2833 if (fseek(from_file, 0, SEEK_END) == 0) { 2834 flen = ftell(from_file); 2835 s = xmalloc(flen + 4); 2836 fseek(from_file, 0, SEEK_SET); 2837 i = 1 + fread(s + 1, 1, flen, from_file); 2838 } else { 2839 for (i = j = 1; j > 0; i += j) { 2840 s = xrealloc(s, i + 4096); 2841 j = fread(s + i, 1, 4094, from_file); 2842 } 2843 } 2844 s[i] = '\0'; 2845 fclose(from_file); 2846 parse_program(s + 1); 2847 free(s); 2848 } else { // no -f: take program from 1st parameter 2849 if (!argc) 2850 bb_show_usage(); 2851 g_progname = "cmd. line"; 2852 parse_program(*argv++); 2853 argc--; 2854 } 2855 if (opt & 0x8) // -W 2856 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W); 2857 2858 /* fill in ARGV array */ 2859 setvar_i(intvar[ARGC], argc + 1); 2860 setari_u(intvar[ARGV], 0, "awk"); 2861 i = 0; 2862 while (*argv) 2863 setari_u(intvar[ARGV], ++i, *argv++); 2864 2865 evaluate(beginseq.first, &tv); 2866 if (!mainseq.first && !endseq.first) 2867 awk_exit(EXIT_SUCCESS); 2868 2869 /* input file could already be opened in BEGIN block */ 2870 if (!iF) iF = next_input_file(); 2871 2872 /* passing through input files */ 2873 while (iF) { 2874 nextfile = FALSE; 2875 setvar_i(intvar[FNR], 0); 2876 2877 while ((i = awk_getline(iF, intvar[F0])) > 0) { 2878 nextrec = FALSE; 2879 incvar(intvar[NR]); 2880 incvar(intvar[FNR]); 2881 evaluate(mainseq.first, &tv); 2882 2883 if (nextfile) 2884 break; 2885 } 2886 2887 if (i < 0) 2888 syntax_error(strerror(errno)); 2889 2890 iF = next_input_file(); 2891 } 2892 2893 awk_exit(EXIT_SUCCESS); 2894 /*return 0;*/ 2895} 2896