Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/editors/awk.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/editors/awk.c
r821 r1770 8 8 */ 9 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <unistd.h> 13 #include <errno.h> 14 #include <string.h> 15 #include <strings.h> 16 #include <time.h> 10 #include "libbb.h" 11 #include "xregex.h" 17 12 #include <math.h> 18 #include <ctype.h> 19 #include <getopt.h> 20 21 #include "xregex.h" 22 #include "busybox.h" 23 24 25 #define MAXVARFMT 240 26 #define MINNVBLOCK 64 13 extern char **environ; 14 15 /* This is a NOEXEC applet. Be very careful! */ 16 17 18 #define MAXVARFMT 240 19 #define MINNVBLOCK 64 27 20 28 21 /* variable flags */ 29 #define VF_NUMBER 30 #define VF_ARRAY 31 32 #define VF_CACHED 33 #define VF_USER 34 #define VF_SPECIAL 35 #define VF_WALK 36 #define VF_FSTR 0x1000 /* 1 =string points to fstring buffer */37 #define VF_CHILD 38 #define VF_DIRTY 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 */ 39 32 40 33 /* these flags are static, don't change them when value is changed */ 41 #define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)34 #define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY) 42 35 43 36 /* Variable */ 44 37 typedef struct var_s { 45 unsigned short type;/* flags */38 unsigned type; /* flags */ 46 39 double number; 47 40 char *string; 48 41 union { 49 int aidx; 50 struct xhash_s *array; 51 struct var_s *parent; 52 char **walker; 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) */ 53 46 } x; 54 47 } var; … … 58 51 struct node_s *first; 59 52 struct node_s *last; 60 c har *programname;53 const char *programname; 61 54 } chain; 62 55 63 56 /* Function */ 64 57 typedef struct func_s { 65 unsigned shortnargs;58 unsigned nargs; 66 59 struct chain_s body; 67 60 } func; … … 74 67 int size; 75 68 int pos; 76 unsigned short is_pipe;69 smallint is_pipe; 77 70 } rstream; 78 71 79 72 typedef struct hash_item_s { 80 73 union { 81 struct var_s v; 82 struct rstream_s rs; 83 struct func_s f; 74 struct var_s v; /* variable/array hash */ 75 struct rstream_s rs; /* redirect streams hash */ 76 struct func_s f; /* functions hash */ 84 77 } data; 85 struct hash_item_s *next; 86 char name[1]; 78 struct hash_item_s *next; /* next in chain */ 79 char name[1]; /* really it's longer */ 87 80 } hash_item; 88 81 89 82 typedef struct xhash_s { 90 unsigned int nel;/* num of elements */91 unsigned int csize;/* current hash size */92 unsigned int nprime;/* next hash size in PRIMES[] */93 unsigned int glen;/* summary length of item names */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 */ 94 87 struct hash_item_s **items; 95 88 } xhash; … … 98 91 typedef struct node_s { 99 92 uint32_t info; 100 unsigned shortlineno;93 unsigned lineno; 101 94 union { 102 95 struct node_s *n; … … 164 157 #define TC_NUMBER (1 << 29) 165 158 166 #define TC_UOPPRE 159 #define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) 167 160 168 161 /* combined token classes */ 169 #define TC_BINOP 170 #define TC_UNARYOP 171 #define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION |\172 173 174 #define TC_STATEMNT 175 #define TC_OPTERM 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) 176 169 177 170 /* word tokens, cannot mean something else if not expected */ 178 #define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN |\179 171 #define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \ 172 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END) 180 173 181 174 /* discard newlines after these */ 182 #define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM |\183 175 #define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \ 176 | TC_BINOP | TC_OPTERM) 184 177 185 178 /* what can expression begin with */ 186 #define TC_OPSEQ 179 #define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP) 187 180 /* what can group begin with */ 188 #define TC_GRPSEQ 181 #define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART) 189 182 190 183 /* if previous token class is CONCAT1 and next is CONCAT2, concatenation */ 191 184 /* operator is inserted between them */ 192 #define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM |\193 194 #define TC_CONCAT2 195 196 #define OF_RES1 197 #define OF_RES2 198 #define OF_STR1 199 #define OF_STR2 200 #define OF_NUM1 201 #define OF_CHECKED 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 202 195 203 196 /* combined operator flags */ … … 213 206 #define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2) 214 207 215 #define OPCLSMASK 216 #define OPNMASK 208 #define OPCLSMASK 0xFF00 209 #define OPNMASK 0x007F 217 210 218 211 /* operator priority is a highest byte (even: r->l, odd: l->r grouping) … … 220 213 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string 221 214 */ 222 #define P(x)(x << 24)223 #define PRIMASK0x7F000000224 #define PRIMASK20x7E000000215 #define P(x) (x << 24) 216 #define PRIMASK 0x7F000000 217 #define PRIMASK2 0x7E000000 225 218 226 219 /* Operation classes */ … … 230 223 231 224 enum { 232 OC_DELETE =0x0100, OC_EXEC=0x0200, OC_NEWSOURCE=0x0300,233 OC_PRINT =0x0400, OC_PRINTF=0x0500, OC_WALKINIT=0x0600,234 235 OC_BR =0x0700, OC_BREAK=0x0800, OC_CONTINUE=0x0900,236 OC_EXIT =0x0a00, OC_NEXT=0x0b00, OC_NEXTFILE=0x0c00,237 OC_TEST =0x0d00, OC_WALKNEXT=0x0e00,238 239 OC_BINARY =0x1000, OC_BUILTIN=0x1100, OC_COLON=0x1200,240 OC_COMMA =0x1300, OC_COMPARE=0x1400, OC_CONCAT=0x1500,241 OC_FBLTIN =0x1600, OC_FIELD=0x1700, OC_FNARG=0x1800,242 OC_FUNC =0x1900, OC_GETLINE=0x1a00, OC_IN=0x1b00,243 OC_LAND =0x1c00, OC_LOR=0x1d00, OC_MATCH=0x1e00,244 OC_MOVE =0x1f00, OC_PGETLINE=0x2000, OC_REGEXP=0x2100,245 OC_REPLACE =0x2200, OC_RETURN=0x2300, OC_SPRINTF=0x2400,246 OC_TERNARY =0x2500, OC_UNARY=0x2600, OC_VAR=0x2700,247 OC_DONE =0x2800,248 249 ST_IF =0x3000, ST_DO=0x3100, ST_FOR=0x3200,250 ST_WHILE =0x3300225 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 251 244 }; 252 245 253 246 /* simple builtins */ 254 247 enum { 255 F_in =0, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,248 F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr, 256 249 F_ti, F_le, F_sy, F_ff, F_cl 257 250 }; … … 259 252 /* builtins */ 260 253 enum { 261 B_a2=0, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up, 262 B_ge, B_gs, B_su 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, 263 257 }; 264 258 265 259 /* tokens and their corresponding info values */ 266 260 267 #define NTC "\377"/* switch to next token class (tc<<1) */268 #define NTCC 261 #define NTC "\377" /* switch to next token class (tc<<1) */ 262 #define NTCC '\377' 269 263 270 264 #define OC_B OC_BUILTIN 271 265 272 static char * const tokenlist = 273 "\1(" NTC 274 "\1)" NTC 275 "\1/" NTC /* REGEXP */ 276 "\2>>" "\1>" "\1|" NTC /* OUTRDR */ 277 "\2++" "\2--" NTC /* UOPPOST */ 278 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ 279 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ 280 "\2*=" "\2/=" "\2%=" "\2^=" 281 "\1+" "\1-" "\3**=" "\2**" 282 "\1/" "\1%" "\1^" "\1*" 283 "\2!=" "\2>=" "\2<=" "\1>" 284 "\1<" "\2!~" "\1~" "\2&&" 285 "\2||" "\1?" "\1:" NTC 286 "\2in" NTC 287 "\1," NTC 288 "\1|" NTC 289 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ 290 "\1]" NTC 291 "\1{" NTC 292 "\1}" NTC 293 "\1;" NTC 294 "\1\n" NTC 295 "\2if" "\2do" "\3for" "\5break" /* STATX */ 296 "\10continue" "\6delete" "\5print" 297 "\6printf" "\4next" "\10nextfile" 298 "\6return" "\4exit" NTC 299 "\5while" NTC 300 "\4else" NTC 301 302 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ 303 "\3cos" "\3exp" "\3int" "\3log" 304 "\4rand" "\3sin" "\4sqrt" "\5srand" 305 "\6gensub" "\4gsub" "\5index" "\6length" 306 "\5match" "\5split" "\7sprintf" "\3sub" 307 "\6substr" "\7systime" "\10strftime" 308 "\7tolower" "\7toupper" NTC 309 "\7getline" NTC 310 "\4func" "\10function" NTC 311 "\5BEGIN" NTC 312 "\3END" "\0" 266 static 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" 313 309 ; 314 310 315 311 static const uint32_t tokeninfo[] = { 316 317 312 0, 318 313 0, 319 314 OC_REGEXP, 320 xS|'a', xS|'w',xS|'|',321 OC_UNARY|xV|P(9)|'p', 322 OC_UNARY|xV|P(9)|'P', 323 324 OC_COMPARE|VV|P(39)|5, 325 OC_REPLACE|NV|P(74)|'+',OC_REPLACE|NV|P(74)|'-',326 OC_REPLACE|NV|P(74)|'*', 327 OC_REPLACE|NV|P(74)|'%',OC_REPLACE|NV|P(74)|'&',328 OC_BINARY|NV|P(29)|'+', 329 OC_REPLACE|NV|P(74)|'&',OC_BINARY|NV|P(15)|'&',330 OC_BINARY|NV|P(25)|'/', 331 OC_BINARY|NV|P(15)|'&',OC_BINARY|NV|P(25)|'*',332 OC_COMPARE|VV|P(39)|4, 333 OC_COMPARE|VV|P(39)|0,OC_COMPARE|VV|P(39)|1,334 OC_COMPARE|VV|P(39)|2, 335 OC_MATCH|Sx|P(45)|'~',OC_LAND|Vx|P(55),336 OC_LOR|Vx|P(59), 337 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)|':', 338 333 OC_IN|SV|P(49), 339 334 OC_COMMA|SS|P(80), 340 335 OC_PGETLINE|SV|P(37), 341 OC_UNARY|xV|P(19)|'+', 342 336 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', 337 OC_UNARY|xV|P(19)|'!', 343 338 0, 344 339 0, … … 346 341 0, 347 342 0, 348 ST_IF, ST_DO, ST_FOR,OC_BREAK,349 OC_CONTINUE, OC_DELETE|Vx,OC_PRINT,350 OC_PRINTF, OC_NEXT,OC_NEXTFILE,351 OC_RETURN|Vx, 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, 352 347 ST_WHILE, 353 348 0, 354 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), 355 352 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83), 356 353 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg, … … 369 366 /* asterisk marks SPECIAL vars; $ is just no-named Field0 */ 370 367 enum { 371 CONVFMT =0, OFMT, FS,OFS,372 ORS, RS, RT,FILENAME,373 SUBSEP, ARGIND, ARGC,ARGV,374 ERRNO, 375 NR, NF,IGNORECASE,376 ENVIRON, F0, _intvarcount_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 377 374 }; 378 375 379 static c har * vNames=380 "CONVFMT\0" "OFMT\0" "FS\0*""OFS\0"381 "ORS\0" "RS\0*" "RT\0""FILENAME\0"382 "SUBSEP\0" "ARGIND\0" "ARGC\0""ARGV\0"383 "ERRNO\0" 384 "NR\0" "NF\0*""IGNORECASE\0*"385 "ENVIRON\0" "$\0*""\0";386 387 static c har * vValues=388 "%.6g\0" "%.6g\0" " \0"" \0"389 "\n\0" "\n\0" "\0""\0"376 static 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 384 static const char vValues[] ALIGN1 = 385 "%.6g\0" "%.6g\0" " \0" " \0" 386 "\n\0" "\n\0" "\0" "\0" 390 387 "\034\0" 391 388 "\377"; 392 389 393 390 /* hash size may grow to these values */ 394 #define FIRST_PRIME 61; 395 static const unsigned int PRIMES[] = { 251, 1021, 4093, 16381, 65521 }; 396 enum { NPRIMES = sizeof(PRIMES) / sizeof(unsigned int) }; 397 398 /* globals */ 399 400 extern char **environ; 401 402 static var * V[_intvarcount_]; 403 static chain beginseq, mainseq, endseq, *seq; 404 static int nextrec, nextfile; 405 static node *break_ptr, *continue_ptr; 406 static rstream *iF; 407 static xhash *vhash, *ahash, *fdhash, *fnhash; 408 static char *programname; 409 static short lineno; 410 static int is_f0_split; 411 static int nfields; 412 static var *Fields; 413 static tsplitter fsplitter, rsplitter; 414 static nvblock *cb; 415 static char *pos; 416 static char *buf; 417 static int icase; 418 static int exiting; 419 420 static struct { 421 uint32_t tclass; 422 uint32_t info; 423 char *string; 424 double number; 425 short lineno; 426 int rollback; 427 } t; 391 #define FIRST_PRIME 61 392 static 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 */ 397 struct 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 }; 416 struct 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 428 494 429 495 /* function prototypes */ … … 438 504 /* ---- error handling ---- */ 439 505 440 static const char EMSG_INTERNAL_ERROR[] = "Internal error";441 static const char EMSG_UNEXP_EOS[] = "Unexpected end of string";442 static const char EMSG_UNEXP_TOKEN[] = "Unexpected token";443 static const char EMSG_DIV_BY_ZERO[] = "Division by zero";444 static const char EMSG_INV_FMT[] = "Invalid format specifier";445 static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin";446 static const char EMSG_NOT_ARRAY[] = "Not an array";447 static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error";448 static const char EMSG_UNDEF_FUNC[] = "Call to undefined function";449 #if ndef CONFIG_FEATURE_AWK_MATH450 static const char EMSG_NO_MATH[] = "Math support is not compiled in";506 static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error"; 507 static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string"; 508 static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token"; 509 static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero"; 510 static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier"; 511 static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; 512 static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; 513 static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; 514 static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; 515 #if !ENABLE_FEATURE_AWK_MATH 516 static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; 451 517 #endif 452 518 453 static void syntax_error(const char * const message) ATTRIBUTE_NORETURN; 454 static void syntax_error(const char * const message) 455 { 456 bb_error_msg_and_die("%s:%i: %s", programname, lineno, message); 457 } 458 459 #define runtime_error(x) syntax_error(x) 460 519 static void zero_out_var(var * vp) 520 { 521 memset(vp, 0, sizeof(*vp)); 522 } 523 524 static void syntax_error(const char *const message) ATTRIBUTE_NORETURN; 525 static void syntax_error(const char *const message) 526 { 527 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message); 528 } 461 529 462 530 /* ---- hash stuff ---- */ 463 531 464 static unsigned inthashidx(const char *name)465 { 466 register unsigned int idx=0;467 468 while (*name) 532 static unsigned hashidx(const char *name) 533 { 534 unsigned idx = 0; 535 536 while (*name) idx = *name++ + (idx << 6) - idx; 469 537 return idx; 470 538 } … … 475 543 xhash *newhash; 476 544 477 newhash = (xhash *)xzalloc(sizeof(xhash));545 newhash = xzalloc(sizeof(xhash)); 478 546 newhash->csize = FIRST_PRIME; 479 newhash->items = (hash_item **)xzalloc(newhash->csize * sizeof(hash_item *));547 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *)); 480 548 481 549 return newhash; … … 499 567 static void hash_rebuild(xhash *hash) 500 568 { 501 unsigned intnewsize, i, idx;569 unsigned newsize, i, idx; 502 570 hash_item **newitems, *hi, *thi; 503 571 504 if (hash->nprime == NPRIMES)572 if (hash->nprime == ARRAY_SIZE(PRIMES)) 505 573 return; 506 574 507 575 newsize = PRIMES[hash->nprime++]; 508 newitems = (hash_item **)xzalloc(newsize * sizeof(hash_item *));509 510 for (i =0; i<hash->csize; i++) {576 newitems = xzalloc(newsize * sizeof(hash_item *)); 577 578 for (i = 0; i < hash->csize; i++) { 511 579 hi = hash->items[i]; 512 580 while (hi) { … … 528 596 { 529 597 hash_item *hi; 530 unsigned i nt idx;598 unsigned idx; 531 599 int l; 532 600 533 601 hi = hash_search(hash, name); 534 if (! 602 if (!hi) { 535 603 if (++hash->nel / hash->csize > 10) 536 604 hash_rebuild(hash); … … 548 616 } 549 617 550 #define findvar(hash, name) ( var *) hash_find ( (hash) , (name))551 #define newvar(name) (var *) hash_find ( vhash , (name))552 #define newfile(name) (rstream *) hash_find ( fdhash , (name))553 #define newfunc(name) (func *) hash_find ( fnhash , (name))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))) 554 622 555 623 static void hash_remove(xhash *hash, const char *name) … … 557 625 hash_item *hi, **phi; 558 626 559 phi = &(hash->items[ hashidx(name) % hash->csize]);627 phi = &(hash->items[hashidx(name) % hash->csize]); 560 628 while (*phi) { 561 629 hi = *phi; … … 575 643 static void skip_spaces(char **s) 576 644 { 577 register char *p = *s; 578 579 while(*p == ' ' || *p == '\t' || 580 (*p == '\\' && *(p+1) == '\n' && (++p, ++t.lineno))) { 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 } 581 654 p++; 582 655 } … … 586 659 static char *nextword(char **s) 587 660 { 588 registerchar *p = *s;589 590 while (*(*s)++) ;661 char *p = *s; 662 663 while (*(*s)++) /* */; 591 664 592 665 return p; … … 595 668 static char nextchar(char **s) 596 669 { 597 registerchar c, *pps;670 char c, *pps; 598 671 599 672 c = *((*s)++); … … 604 677 } 605 678 606 static in line intisalnum_(int c)679 static int ALWAYS_INLINE isalnum_(int c) 607 680 { 608 681 return (isalnum(c) || c == '_'); … … 611 684 static FILE *afopen(const char *path, const char *mode) 612 685 { 613 return (*path == '-' && *(path+1) == '\0') ? stdin : bb_xfopen(path, mode);686 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode); 614 687 } 615 688 … … 623 696 a = a->x.parent; 624 697 625 if (! 698 if (!(a->type & VF_ARRAY)) { 626 699 a->type |= VF_ARRAY; 627 700 a->x.array = hash_init(); … … 632 705 static void clear_array(xhash *array) 633 706 { 634 unsigned i nt i;707 unsigned i; 635 708 hash_item *hi, *thi; 636 709 637 for (i =0; i<array->csize; i++) {710 for (i = 0; i < array->csize; i++) { 638 711 hi = array->items[i]; 639 712 while (hi) { … … 666 739 v->string = value; 667 740 handle_special(v); 668 669 741 return v; 670 742 } … … 673 745 static var *setvar_s(var *v, const char *value) 674 746 { 675 return setvar_p(v, (value && *value) ? bb_xstrdup(value) : NULL);747 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL); 676 748 } 677 749 … … 687 759 static void setari_u(var *a, int idx, const char *s) 688 760 { 689 register var *v;690 static char sidx[12];761 char sidx[sizeof(int)*3 + 1]; 762 var *v; 691 763 692 764 sprintf(sidx, "%d", idx); … … 705 777 } 706 778 707 static c har *getvar_s(var *v)779 static const char *getvar_s(var *v) 708 780 { 709 781 /* if v is numeric and has no cached string, convert it to string */ 710 782 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) { 711 fmt_num( buf, MAXVARFMT, getvar_s(V[CONVFMT]), v->number, TRUE);712 v->string = bb_xstrdup(buf);783 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE); 784 v->string = xstrdup(g_buf); 713 785 v->type |= VF_CACHED; 714 786 } … … 742 814 if (dest != src) { 743 815 clrvar(dest); 744 dest->type |= (src->type & ~ VF_DONTTOUCH);816 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR)); 745 817 dest->number = src->number; 746 818 if (src->string) 747 dest->string = bb_xstrdup(src->string);819 dest->string = xstrdup(src->string); 748 820 } 749 821 handle_special(dest); … … 753 825 static var *incvar(var *v) 754 826 { 755 return setvar_i(v, getvar_i(v) +1.);827 return setvar_i(v, getvar_i(v) + 1.); 756 828 } 757 829 … … 768 840 if (is_numeric(v)) 769 841 return (v->number == 0) ? 0 : 1; 770 else 771 return (v->string && *(v->string)) ? 1 : 0; 842 return (v->string && *(v->string)) ? 1 : 0; 772 843 } 773 844 … … 779 850 int size; 780 851 781 while ( cb) {782 pb = cb;783 if (( cb->pos - cb->nv) + n <=cb->size) break;784 cb =cb->next;785 } 786 787 if (! 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) { 788 859 size = (n <= MINNVBLOCK) ? MINNVBLOCK : n; 789 cb = (nvblock *)xmalloc(sizeof(nvblock) + size * sizeof(var));790 cb->size = size;791 cb->pos =cb->nv;792 cb->prev = pb;793 cb->next = NULL;794 if (pb) pb->next = cb;795 } 796 797 v = r = cb->pos;798 cb->pos += n;799 800 while (v < cb->pos) {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) { 801 872 v->type = 0; 802 873 v->string = NULL; … … 811 882 var *p; 812 883 813 if (v < cb->nv || v >=cb->pos)814 runtime_error(EMSG_INTERNAL_ERROR);815 816 for (p =v; p<cb->pos; p++) {817 if ((p->type & (VF_ARRAY |VF_CHILD)) == VF_ARRAY) {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) { 818 889 clear_array(iamarray(p)); 819 890 free(p->x.array->items); … … 826 897 } 827 898 828 cb->pos = v;829 while ( cb->prev && cb->pos ==cb->nv) {830 cb =cb->prev;899 g_cb->pos = v; 900 while (g_cb->prev && g_cb->pos == g_cb->nv) { 901 g_cb = g_cb->prev; 831 902 } 832 903 } … … 834 905 /* ------- awk program text parsing ------- */ 835 906 836 /* Parse next token pointed by global pos, place results into global t .907 /* Parse next token pointed by global pos, place results into global ttt. 837 908 * If token isn't expected, give away. Return token class 838 909 */ 839 910 static uint32_t next_token(uint32_t expected) 840 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 841 918 char *p, *pp, *s; 842 c har *tl;919 const char *tl; 843 920 uint32_t tc; 844 921 const uint32_t *ti; 845 922 int l; 846 static int concat_inserted; 847 static uint32_t save_tclass, save_info; 848 static uint32_t ltclass = TC_OPTERM; 849 850 if (t.rollback) { 851 852 t.rollback = FALSE; 923 924 if (t_rollback) { 925 t_rollback = FALSE; 853 926 854 927 } else if (concat_inserted) { 855 856 928 concat_inserted = FALSE; 857 t .tclass = save_tclass;858 t .info = save_info;929 t_tclass = save_tclass; 930 t_info = save_info; 859 931 860 932 } else { 861 862 p = pos; 863 864 readnext: 933 p = g_pos; 934 readnext: 865 935 skip_spaces(&p); 866 lineno = t.lineno;936 g_lineno = t_lineno; 867 937 if (*p == '#') 868 while (*p != '\n' && *p != '\0') p++; 938 while (*p != '\n' && *p != '\0') 939 p++; 869 940 870 941 if (*p == '\n') 871 t .lineno++;942 t_lineno++; 872 943 873 944 if (*p == '\0') { … … 876 947 } else if (*p == '\"') { 877 948 /* it's a string */ 878 t .string = s = ++p;949 t_string = s = ++p; 879 950 while (*p != '\"') { 880 951 if (*p == '\0' || *p == '\n') … … 888 959 } else if ((expected & TC_REGEXP) && *p == '/') { 889 960 /* it's regexp */ 890 t .string = s = ++p;961 t_string = s = ++p; 891 962 while (*p != '/') { 892 963 if (*p == '\0' || *p == '\n') 893 964 syntax_error(EMSG_UNEXP_EOS); 894 if ((*s++ = *p++) == '\\') { 965 *s = *p++; 966 if (*s++ == '\\') { 895 967 pp = p; 896 968 *(s-1) = bb_process_escape_sequence((const char **)&p); 897 if (*pp == '\\') *s++ = '\\'; 898 if (p == pp) *s++ = *p++; 969 if (*pp == '\\') 970 *s++ = '\\'; 971 if (p == pp) 972 *s++ = *p++; 899 973 } 900 974 } … … 905 979 } else if (*p == '.' || isdigit(*p)) { 906 980 /* it's a number */ 907 t .number= strtod(p, &p);981 t_double = strtod(p, &p); 908 982 if (*p == '.') 909 983 syntax_error(EMSG_UNEXP_TOKEN); … … 925 999 * then this is what we are looking for 926 1000 */ 927 if ((tc & (expected | TC_WORD | TC_NEWLINE)) && 928 *tl == *p && strncmp(p, tl, l) == 0 && 929 !((tc & TC_WORD) && isalnum_(*(p + l)))) { 930 t.info = *ti; 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; 931 1006 p += l; 932 1007 break; … … 936 1011 } 937 1012 938 if (! 1013 if (!*tl) { 939 1014 /* it's a name (var/array/function), 940 1015 * otherwise it's something wrong 941 1016 */ 942 if (! 1017 if (!isalnum_(*p)) 943 1018 syntax_error(EMSG_UNEXP_TOKEN); 944 1019 945 t .string = --p;946 while (isalnum_(*(++p))) {1020 t_string = --p; 1021 while (isalnum_(*(++p))) { 947 1022 *(p-1) = *p; 948 1023 } … … 950 1025 tc = TC_VARIABLE; 951 1026 /* also consume whitespace between functionname and bracket */ 952 if (! (expected & TC_VARIABLE)) skip_spaces(&p); 1027 if (!(expected & TC_VARIABLE)) 1028 skip_spaces(&p); 953 1029 if (*p == '(') { 954 1030 tc = TC_FUNCTION; … … 961 1037 } 962 1038 } 963 pos = p;1039 g_pos = p; 964 1040 965 1041 /* skipping newlines in some cases */ … … 968 1044 969 1045 /* insert concatenation operator when needed */ 970 if ((ltclass &TC_CONCAT1) && (tc&TC_CONCAT2) && (expected&TC_BINOP)) {1046 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) { 971 1047 concat_inserted = TRUE; 972 1048 save_tclass = tc; 973 save_info = t .info;1049 save_info = t_info; 974 1050 tc = TC_BINOP; 975 t .info = OC_CONCAT | SS | P(35);976 } 977 978 t .tclass = tc;979 } 980 ltclass = t .tclass;1051 t_info = OC_CONCAT | SS | P(35); 1052 } 1053 1054 t_tclass = tc; 1055 } 1056 ltclass = t_tclass; 981 1057 982 1058 /* Are we ready for this? */ 983 if (! 1059 if (!(ltclass & expected)) 984 1060 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ? 985 1061 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); 986 1062 987 1063 return ltclass; 988 } 989 990 static void rollback_token(void) { t.rollback = TRUE; } 1064 #undef concat_inserted 1065 #undef save_tclass 1066 #undef save_info 1067 #undef ltclass 1068 } 1069 1070 static void rollback_token(void) 1071 { 1072 t_rollback = TRUE; 1073 } 991 1074 992 1075 static node *new_node(uint32_t info) 993 1076 { 994 registernode *n;995 996 n = (node *)xzalloc(sizeof(node));1077 node *n; 1078 1079 n = xzalloc(sizeof(node)); 997 1080 n->info = info; 998 n->lineno = lineno;1081 n->lineno = g_lineno; 999 1082 return n; 1000 1083 } 1001 1084 1002 static node *mk_re_node(c har *s, node *n, regex_t *re)1085 static node *mk_re_node(const char *s, node *n, regex_t *re) 1003 1086 { 1004 1087 n->info = OC_REGEXP; … … 1006 1089 n->r.ire = re + 1; 1007 1090 xregcomp(re, s, REG_EXTENDED); 1008 xregcomp(re +1, s, REG_EXTENDED | REG_ICASE);1091 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE); 1009 1092 1010 1093 return n; … … 1031 1114 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; 1032 1115 1033 while (! 1034 if (glptr && (t .info == (OC_COMPARE|VV|P(39)|2))) {1116 while (!((tc = next_token(xtc)) & iexp)) { 1117 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { 1035 1118 /* input redirection (<) attached to glptr node */ 1036 cn = glptr->l.n = new_node(OC_CONCAT |SS|P(37));1119 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); 1037 1120 cn->a.n = glptr; 1038 1121 xtc = TC_OPERAND | TC_UOPPRE; … … 1043 1126 * previous operators with higher priority */ 1044 1127 vn = cn; 1045 while ( ((t .info & PRIMASK) > (vn->a.n->info & PRIMASK2)) ||1046 ((t.info == vn->info) && ((t.info & OPCLSMASK) == OC_COLON)) )1128 while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) 1129 || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) ) 1047 1130 vn = vn->a.n; 1048 if ((t .info & OPCLSMASK) == OC_TERNARY)1049 t .info += P(6);1050 cn = vn->a.n->r.n = new_node(t .info);1131 if ((t_info & OPCLSMASK) == OC_TERNARY) 1132 t_info += P(6); 1133 cn = vn->a.n->r.n = new_node(t_info); 1051 1134 cn->a.n = vn->a.n; 1052 1135 if (tc & TC_BINOP) { 1053 1136 cn->l.n = vn; 1054 1137 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; 1055 if ((t .info & OPCLSMASK) == OC_PGETLINE) {1138 if ((t_info & OPCLSMASK) == OC_PGETLINE) { 1056 1139 /* it's a pipe */ 1057 1140 next_token(TC_GETLINE); … … 1070 1153 * to last node */ 1071 1154 vn = cn; 1072 cn = vn->r.n = new_node(t .info);1155 cn = vn->r.n = new_node(t_info); 1073 1156 cn->a.n = vn; 1074 1157 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; … … 1078 1161 * only simple tclasses should be used! */ 1079 1162 switch (tc) { 1080 1081 1163 case TC_VARIABLE: 1164 case TC_ARRAY: 1082 1165 cn->info = OC_VAR; 1083 if ((v = hash_search(ahash, t.string)) != NULL) { 1166 v = hash_search(ahash, t_string); 1167 if (v != NULL) { 1084 1168 cn->info = OC_FNARG; 1085 1169 cn->l.i = v->x.aidx; 1086 1170 } else { 1087 cn->l.v = newvar(t .string);1171 cn->l.v = newvar(t_string); 1088 1172 } 1089 1173 if (tc & TC_ARRAY) { … … 1093 1177 break; 1094 1178 1095 1096 1179 case TC_NUMBER: 1180 case TC_STRING: 1097 1181 cn->info = OC_VAR; 1098 1182 v = cn->l.v = xzalloc(sizeof(var)); 1099 1183 if (tc & TC_NUMBER) 1100 setvar_i(v, t .number);1184 setvar_i(v, t_double); 1101 1185 else 1102 setvar_s(v, t .string);1186 setvar_s(v, t_string); 1103 1187 break; 1104 1188 1105 case TC_REGEXP: 1106 mk_re_node(t.string, cn, 1107 (regex_t *)xzalloc(sizeof(regex_t)*2)); 1189 case TC_REGEXP: 1190 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2)); 1108 1191 break; 1109 1192 1110 1193 case TC_FUNCTION: 1111 1194 cn->info = OC_FUNC; 1112 cn->r.f = newfunc(t .string);1195 cn->r.f = newfunc(t_string); 1113 1196 cn->l.n = condition(); 1114 1197 break; 1115 1198 1116 1199 case TC_SEQSTART: 1117 1200 cn = vn->r.n = parse_expr(TC_SEQTERM); 1118 1201 cn->a.n = vn; 1119 1202 break; 1120 1203 1121 1204 case TC_GETLINE: 1122 1205 glptr = cn; 1123 1206 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; 1124 1207 break; 1125 1208 1126 1209 case TC_BUILTIN: 1127 1210 cn->l.n = condition(); 1128 1211 break; … … 1137 1220 static node *chain_node(uint32_t info) 1138 1221 { 1139 registernode *n;1140 1141 if (! 1222 node *n; 1223 1224 if (!seq->first) 1142 1225 seq->first = seq->last = new_node(0); 1143 1226 1144 if (seq->programname != programname) {1145 seq->programname = programname;1227 if (seq->programname != g_progname) { 1228 seq->programname = g_progname; 1146 1229 n = chain_node(OC_NEWSOURCE); 1147 n->l.s = bb_xstrdup(programname);1230 n->l.s = xstrdup(g_progname); 1148 1231 } 1149 1232 … … 1161 1244 n = chain_node(info); 1162 1245 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM); 1163 if (t .tclass & TC_GRPTERM)1246 if (t_tclass & TC_GRPTERM) 1164 1247 rollback_token(); 1165 1248 } … … 1199 1282 1200 1283 if (c & TC_GRPSTART) { 1201 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {1202 if (t .tclass & TC_NEWLINE) continue;1284 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { 1285 if (t_tclass & TC_NEWLINE) continue; 1203 1286 rollback_token(); 1204 1287 chain_group(); … … 1208 1291 chain_expr(OC_EXEC | Vx); 1209 1292 } else { /* TC_STATEMNT */ 1210 switch (t.info & OPCLSMASK) { 1211 case ST_IF: 1212 n = chain_node(OC_BR | Vx); 1213 n->l.n = condition(); 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) { 1214 1301 chain_group(); 1215 n2 = chain_node(OC_EXEC); 1216 n->r.n = seq->last; 1217 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE)==TC_ELSE) { 1218 chain_group(); 1219 n2->a.n = seq->last; 1220 } else { 1221 rollback_token(); 1222 } 1223 break; 1224 1225 case ST_WHILE: 1226 n2 = condition(); 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; 1227 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); 1228 1336 n->l.n = n2; 1229 break; 1230 1231 case ST_DO: 1232 n2 = chain_node(OC_EXEC); 1233 n = chain_loop(NULL); 1234 n2->a.n = n->a.n; 1235 next_token(TC_WHILE); 1236 n->l.n = condition(); 1237 break; 1238 1239 case ST_FOR: 1240 next_token(TC_SEQSTART); 1241 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); 1242 if (t.tclass & TC_SEQTERM) { /* for-in */ 1243 if ((n2->info & OPCLSMASK) != OC_IN) 1244 syntax_error(EMSG_UNEXP_TOKEN); 1245 n = chain_node(OC_WALKINIT | VV); 1246 n->l.n = n2->l.n; 1247 n->r.n = n2->r.n; 1248 n = chain_loop(NULL); 1249 n->info = OC_WALKNEXT | Vx; 1250 n->l.n = n2->l.n; 1251 } else { /* for(;;) */ 1252 n = chain_node(OC_EXEC | Vx); 1253 n->l.n = n2; 1254 n2 = parse_expr(TC_SEMICOL); 1255 n3 = parse_expr(TC_SEQTERM); 1256 n = chain_loop(n3); 1257 n->l.n = n2; 1258 if (! n2) 1259 n->info = OC_EXEC; 1260 } 1261 break; 1262 1263 case OC_PRINT: 1264 case OC_PRINTF: 1265 n = chain_node(t.info); 1266 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM); 1267 if (t.tclass & TC_OUTRDR) { 1268 n->info |= t.info; 1269 n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM); 1270 } 1271 if (t.tclass & TC_GRPTERM) 1272 rollback_token(); 1273 break; 1274 1275 case OC_BREAK: 1276 n = chain_node(OC_EXEC); 1277 n->a.n = break_ptr; 1278 break; 1279 1280 case OC_CONTINUE: 1281 n = chain_node(OC_EXEC); 1282 n->a.n = continue_ptr; 1283 break; 1284 1285 /* delete, next, nextfile, return, exit */ 1286 default: 1287 chain_expr(t.info); 1288 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); 1289 1371 } 1290 1372 } … … 1298 1380 var *v; 1299 1381 1300 pos = p;1301 t .lineno = 1;1302 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |1303 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) { 1304 1386 1305 1387 if (tclass & TC_OPTERM) … … 1317 1399 } else if (tclass & TC_FUNCDECL) { 1318 1400 next_token(TC_FUNCTION); 1319 pos++;1320 f = newfunc(t .string);1401 g_pos++; 1402 f = newfunc(t_string); 1321 1403 f->body.first = NULL; 1322 1404 f->nargs = 0; 1323 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {1324 v = findvar(ahash, t .string);1405 while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { 1406 v = findvar(ahash, t_string); 1325 1407 v->x.aidx = (f->nargs)++; 1326 1408 … … 1336 1418 cn = chain_node(OC_TEST); 1337 1419 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); 1338 if (t .tclass & TC_GRPSTART) {1420 if (t_tclass & TC_GRPSTART) { 1339 1421 rollback_token(); 1340 1422 chain_group(); … … 1354 1436 /* -------- program execution part -------- */ 1355 1437 1356 static node *mk_splitter(c har *s, tsplitter *spl)1357 { 1358 reg ister regex_t *re, *ire;1438 static node *mk_splitter(const char *s, tsplitter *spl) 1439 { 1440 regex_t *re, *ire; 1359 1441 node *n; 1360 1442 … … 1362 1444 ire = &spl->re[1]; 1363 1445 n = &spl->n; 1364 if ((n->info & &OPCLSMASK) == OC_REGEXP) {1446 if ((n->info & OPCLSMASK) == OC_REGEXP) { 1365 1447 regfree(re); 1366 regfree(ire); 1448 regfree(ire); // TODO: nuke ire, use re+1? 1367 1449 } 1368 1450 if (strlen(s) > 1) { … … 1382 1464 { 1383 1465 var *v; 1384 c har *s;1466 const char *s; 1385 1467 1386 1468 if ((op->info & OPCLSMASK) == OC_REGEXP) { 1387 1469 return icase ? op->r.ire : op->l.re; 1388 } else { 1389 v = nvalloc(1); 1390 s = getvar_s(evaluate(op, v)); 1391 xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED); 1392 nvfree(v); 1393 return preg; 1394 } 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; 1395 1476 } 1396 1477 … … 1398 1479 static void qrealloc(char **b, int n, int *size) 1399 1480 { 1400 if (! 1481 if (!*b || n >= *size) 1401 1482 *b = xrealloc(*b, *size = n + (n>>1) + 80); 1402 1483 } … … 1405 1486 static void fsrealloc(int size) 1406 1487 { 1407 static int maxfields = 0;1408 1488 int i; 1409 1489 … … 1411 1491 i = maxfields; 1412 1492 maxfields = size + 16; 1413 Fields = (var *)xrealloc(Fields, maxfields * sizeof(var));1414 for (; i <maxfields; i++) {1493 Fields = xrealloc(Fields, maxfields * sizeof(var)); 1494 for (; i < maxfields; i++) { 1415 1495 Fields[i].type = VF_SPECIAL; 1416 1496 Fields[i].string = NULL; … … 1419 1499 1420 1500 if (size < nfields) { 1421 for (i =size; i<nfields; i++) {1422 clrvar(Fields +i);1501 for (i = size; i < nfields; i++) { 1502 clrvar(Fields + i); 1423 1503 } 1424 1504 } … … 1426 1506 } 1427 1507 1428 static int awk_split(c har *s, node *spl, char **slist)1429 { 1430 int l, n =0;1508 static int awk_split(const char *s, node *spl, char **slist) 1509 { 1510 int l, n = 0; 1431 1511 char c[4]; 1432 1512 char *s1; 1433 regmatch_t pmatch[2]; 1513 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... 1434 1514 1435 1515 /* in worst case, each char would be a separate field */ 1436 *slist = s1 = bb_xstrndup(s, strlen(s) * 2 + 3); 1516 *slist = s1 = xzalloc(strlen(s) * 2 + 3); 1517 strcpy(s1, s); 1437 1518 1438 1519 c[0] = c[1] = (char)spl->info; 1439 1520 c[2] = c[3] = '\0'; 1440 if (*getvar_s(V[RS]) == '\0') c[2] = '\n'; 1441 1442 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */ 1443 while (*s) { 1444 l = strcspn(s, c+2); 1445 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0 && 1446 pmatch[0].rm_so <= l) { 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 ) { 1447 1533 l = pmatch[0].rm_so; 1448 if (pmatch[0].rm_eo == 0) { l++; pmatch[0].rm_eo++; } 1534 if (pmatch[0].rm_eo == 0) { 1535 l++; 1536 pmatch[0].rm_eo++; 1537 } 1538 n++; /* we saw yet another delimiter */ 1449 1539 } else { 1450 1540 pmatch[0].rm_eo = l; 1451 if (*(s+l)) pmatch[0].rm_eo++; 1452 } 1453 1541 if (s[l]) pmatch[0].rm_eo++; 1542 } 1454 1543 memcpy(s1, s, l); 1455 *(s1+l)= '\0';1544 s1[l] = '\0'; 1456 1545 nextword(&s1); 1457 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'; 1458 1554 n++; 1459 1555 } 1460 } else if (c[0] == '\0') { /* null split */ 1461 while(*s) { 1462 *(s1++) = *(s++); 1463 *(s1++) = '\0'; 1464 n++; 1465 } 1466 } else if (c[0] != ' ') { /* single-character split */ 1556 return n; 1557 } 1558 if (c[0] != ' ') { /* single-character split */ 1467 1559 if (icase) { 1468 1560 c[0] = toupper(c[0]); … … 1471 1563 if (*s1) n++; 1472 1564 while ((s1 = strpbrk(s1, c))) { 1473 * (s1++)= '\0';1565 *s1++ = '\0'; 1474 1566 n++; 1475 1567 } 1476 } else { /* space split */ 1477 while (*s) { 1478 while (isspace(*s)) s++; 1479 if (! *s) break; 1480 n++; 1481 while (*s && !isspace(*s)) 1482 *(s1++) = *(s++); 1483 *(s1++) = '\0'; 1484 } 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'; 1485 1578 } 1486 1579 return n; … … 1489 1582 static void split_f0(void) 1490 1583 { 1491 static char *fstrings = NULL; 1584 /* static char *fstrings; */ 1585 #define fstrings (G.split_f0__fstrings) 1586 1492 1587 int i, n; 1493 1588 char *s; … … 1499 1594 free(fstrings); 1500 1595 fsrealloc(0); 1501 n = awk_split(getvar_s( V[F0]), &fsplitter.n, &fstrings);1596 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings); 1502 1597 fsrealloc(n); 1503 1598 s = fstrings; 1504 for (i =0; i<n; i++) {1599 for (i = 0; i < n; i++) { 1505 1600 Fields[i].string = nextword(&s); 1506 1601 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY); … … 1508 1603 1509 1604 /* set NF manually to avoid side effects */ 1510 clrvar(V[NF]); 1511 V[NF]->type = VF_NUMBER | VF_SPECIAL; 1512 V[NF]->number = nfields; 1605 clrvar(intvar[NF]); 1606 intvar[NF]->type = VF_NUMBER | VF_SPECIAL; 1607 intvar[NF]->number = nfields; 1608 #undef fstrings 1513 1609 } 1514 1610 … … 1517 1613 { 1518 1614 int n; 1519 char *b, *sep, *s; 1615 char *b; 1616 const char *sep, *s; 1520 1617 int sl, l, len, i, bsize; 1521 1618 1522 if (! 1619 if (!(v->type & VF_SPECIAL)) 1523 1620 return; 1524 1621 1525 if (v == V[NF]) {1622 if (v == intvar[NF]) { 1526 1623 n = (int)getvar_i(v); 1527 1624 fsrealloc(n); 1528 1625 1529 1626 /* recalculate $0 */ 1530 sep = getvar_s( V[OFS]);1627 sep = getvar_s(intvar[OFS]); 1531 1628 sl = strlen(sep); 1532 1629 b = NULL; 1533 1630 len = 0; 1534 for (i =0; i<n; i++) {1631 for (i = 0; i < n; i++) { 1535 1632 s = getvar_s(&Fields[i]); 1536 1633 l = strlen(s); … … 1543 1640 len += l; 1544 1641 } 1545 if (b) b[len] = '\0'; 1546 setvar_p(V[F0], b); 1642 if (b) 1643 b[len] = '\0'; 1644 setvar_p(intvar[F0], b); 1547 1645 is_f0_split = TRUE; 1548 1646 1549 } else if (v == V[F0]) {1647 } else if (v == intvar[F0]) { 1550 1648 is_f0_split = FALSE; 1551 1649 1552 } else if (v == V[FS]) {1650 } else if (v == intvar[FS]) { 1553 1651 mk_splitter(getvar_s(v), &fsplitter); 1554 1652 1555 } else if (v == V[RS]) {1653 } else if (v == intvar[RS]) { 1556 1654 mk_splitter(getvar_s(v), &rsplitter); 1557 1655 1558 } else if (v == V[IGNORECASE]) {1656 } else if (v == intvar[IGNORECASE]) { 1559 1657 icase = istrue(v); 1560 1658 1561 } else { 1562 n = getvar_i( V[NF]);1563 setvar_i( V[NF], n > v-Fields ? n : v-Fields+1);1659 } else { /* $n */ 1660 n = getvar_i(intvar[NF]); 1661 setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1); 1564 1662 /* right here v is invalid. Just to note... */ 1565 1663 } … … 1591 1689 1592 1690 v->type |= VF_WALK; 1593 w = v->x.walker = (char **)xzalloc(2 + 2*sizeof(char *) + array->glen);1594 *w = *(w+1)= (char *)(w + 2);1595 for (i =0; i<array->csize; i++) {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++) { 1596 1694 hi = array->items[i]; 1597 while (hi) {1695 while (hi) { 1598 1696 strcpy(*w, hi->name); 1599 1697 nextword(w); … … 1608 1706 1609 1707 w = v->x.walker; 1610 if ( *(w+1) == *w)1708 if (w[1] == w[0]) 1611 1709 return FALSE; 1612 1710 … … 1618 1716 static int ptest(node *pattern) 1619 1717 { 1620 static var v;1621 return istrue(evaluate(pattern, & v));1718 /* ptest__v is "static": to save stack space? */ 1719 return istrue(evaluate(pattern, &G.ptest__v)); 1622 1720 } 1623 1721 … … 1642 1740 rp = 0; 1643 1741 1644 if (! 1742 if (!m) qrealloc(&m, 256, &size); 1645 1743 do { 1646 1744 b = m + a; … … 1650 1748 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) { 1651 1749 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re, 1652 1750 b, 1, pmatch, 0) == 0) { 1653 1751 so = pmatch[0].rm_so; 1654 1752 eo = pmatch[0].rm_eo; … … 1658 1756 } else if (c != '\0') { 1659 1757 s = strchr(b+pp, c); 1660 if (! 1758 if (!s) s = memchr(b+pp, '\0', p - pp); 1661 1759 if (s) { 1662 1760 so = eo = s-b; … … 1690 1788 p = 0; 1691 1789 r = 0; 1692 setvar_i( V[ERRNO], errno);1790 setvar_i(intvar[ERRNO], errno); 1693 1791 } 1694 1792 b[p] = '\0'; … … 1704 1802 b[so] = c; 1705 1803 c = b[eo]; b[eo] = '\0'; 1706 setvar_s( V[RT], b+so);1804 setvar_s(intvar[RT], b+so); 1707 1805 b[eo] = c; 1708 1806 } … … 1718 1816 static int fmt_num(char *b, int size, const char *format, double n, int int_as_int) 1719 1817 { 1720 int r =0;1818 int r = 0; 1721 1819 char c; 1722 const char *s =format;1820 const char *s = format; 1723 1821 1724 1822 if (int_as_int && n == (int)n) { 1725 1823 r = snprintf(b, size, "%d", (int)n); 1726 1824 } else { 1727 do { c = *s; } while ( *s&& *++s);1825 do { c = *s; } while (c && *++s); 1728 1826 if (strchr("diouxX", c)) { 1729 1827 r = snprintf(b, size, format, (int)n); … … 1731 1829 r = snprintf(b, size, format, n); 1732 1830 } else { 1733 runtime_error(EMSG_INV_FMT);1831 syntax_error(EMSG_INV_FMT); 1734 1832 } 1735 1833 } … … 1742 1840 { 1743 1841 char *b = NULL; 1744 char *fmt, *s, *s1, *f; 1842 char *fmt, *s, *f; 1843 const char *s1; 1745 1844 int i, j, incr, bsize; 1746 1845 char c, c1; … … 1748 1847 1749 1848 v = nvalloc(1); 1750 fmt = f = bb_xstrdup(getvar_s(evaluate(nextarg(&n), v)));1849 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v))); 1751 1850 1752 1851 i = 0; … … 1755 1854 while (*f && (*f != '%' || *(++f) == '%')) 1756 1855 f++; 1757 while (*f && !isalpha(*f)) 1856 while (*f && !isalpha(*f)) { 1857 if (*f == '*') 1858 syntax_error("%*x formats are not supported"); 1758 1859 f++; 1860 } 1759 1861 1760 1862 incr = (f - s) + MAXVARFMT; 1761 qrealloc(&b, incr+i, &bsize); 1762 c = *f; if (c != '\0') f++; 1763 c1 = *f ; *f = '\0'; 1863 qrealloc(&b, incr + i, &bsize); 1864 c = *f; 1865 if (c != '\0') f++; 1866 c1 = *f; 1867 *f = '\0'; 1764 1868 arg = evaluate(nextarg(&n), v); 1765 1869 1766 1870 j = i; 1767 1871 if (c == 'c' || !c) { 1768 i += sprintf(b+i, s, 1769 is_numeric(arg) ? (char)getvar_i(arg) : *getvar_s(arg)); 1770 1872 i += sprintf(b+i, s, is_numeric(arg) ? 1873 (char)getvar_i(arg) : *getvar_s(arg)); 1771 1874 } else if (c == 's') { 1772 1875 s1 = getvar_s(arg); 1773 1876 qrealloc(&b, incr+i+strlen(s1), &bsize); 1774 1877 i += sprintf(b+i, s, s1); 1775 1776 1878 } else { 1777 1879 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE); … … 1781 1883 /* if there was an error while sprintf, return value is negative */ 1782 1884 if (i < j) i = j; 1783 1784 } 1785 1786 b = xrealloc(b, i+1); 1885 } 1886 1887 b = xrealloc(b, i + 1); 1787 1888 free(fmt); 1788 1889 nvfree(v); … … 1797 1898 * subexpression matching (\1-\9) 1798 1899 */ 1799 static int awk_sub(node *rn, c har *repl, int nm, var *src, var *dest, int ex)1900 static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex) 1800 1901 { 1801 1902 char *ds = NULL; 1802 char *sp, *s; 1903 const char *s; 1904 const char *sp; 1803 1905 int c, i, j, di, rl, so, eo, nbs, n, dssize; 1804 1906 regmatch_t pmatch[10]; … … 1806 1908 1807 1909 re = as_regex(rn, &sreg); 1808 if (! src) src = V[F0];1809 if (! dest) dest = V[F0];1910 if (!src) src = intvar[F0]; 1911 if (!dest) dest = intvar[F0]; 1810 1912 1811 1913 i = di = 0; 1812 1914 sp = getvar_s(src); 1813 1915 rl = strlen(repl); 1814 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 :REG_NOTBOL) == 0) {1916 while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) { 1815 1917 so = pmatch[0].rm_so; 1816 1918 eo = pmatch[0].rm_eo; … … 1852 1954 if (i == nm) break; 1853 1955 if (eo == so) { 1854 if (! (ds[di++] = *sp++)) break; 1956 ds[di] = *sp++; 1957 if (!ds[di++]) break; 1855 1958 } 1856 1959 } … … 1865 1968 static var *exec_builtin(node *op, var *res) 1866 1969 { 1970 #define tspl (G.exec_builtin__tspl) 1971 1867 1972 int (*to_xxx)(int); 1868 1973 var *tv; 1869 1974 node *an[4]; 1870 var 1871 c har *as[4];1975 var *av[4]; 1976 const char *as[4]; 1872 1977 regmatch_t pmatch[2]; 1873 1978 regex_t sreg, *re; 1874 static tsplitter tspl;1875 1979 node *spl; 1876 1980 uint32_t isr, info; … … 1885 1989 1886 1990 av[2] = av[3] = NULL; 1887 for (i =0 ; i<4 && op; i++) {1991 for (i = 0; i < 4 && op; i++) { 1888 1992 an[i] = nextarg(&op); 1889 1993 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]); … … 1894 1998 nargs = i; 1895 1999 if (nargs < (info >> 30)) 1896 runtime_error(EMSG_TOO_FEW_ARGS);2000 syntax_error(EMSG_TOO_FEW_ARGS); 1897 2001 1898 2002 switch (info & OPNMASK) { 1899 2003 1900 1901 #if def CONFIG_FEATURE_AWK_MATH2004 case B_a2: 2005 #if ENABLE_FEATURE_AWK_MATH 1902 2006 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1]))); 1903 2007 #else 1904 runtime_error(EMSG_NO_MATH);2008 syntax_error(EMSG_NO_MATH); 1905 2009 #endif 1906 2010 break; 1907 2011 1908 2012 case B_sp: 1909 2013 if (nargs > 2) { 1910 2014 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ? … … 1923 2027 break; 1924 2028 1925 2029 case B_ss: 1926 2030 l = strlen(as[0]); 1927 2031 i = getvar_i(av[1]) - 1; 1928 if (i>l) i=l; if (i<0) i=0; 2032 if (i > l) i = l; 2033 if (i < 0) i = 0; 1929 2034 n = (nargs > 2) ? getvar_i(av[2]) : l-i; 1930 if (n <0) n=0;2035 if (n < 0) n = 0; 1931 2036 s = xmalloc(n+1); 1932 2037 strncpy(s, as[0]+i, n); … … 1935 2040 break; 1936 2041 1937 case B_lo: 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: 1938 2067 to_xxx = tolower; 1939 2068 goto lo_cont; 1940 2069 1941 2070 case B_up: 1942 2071 to_xxx = toupper; 1943 lo_cont:1944 s1 = s = bb_xstrdup(as[0]);2072 lo_cont: 2073 s1 = s = xstrdup(as[0]); 1945 2074 while (*s1) { 1946 2075 *s1 = (*to_xxx)(*s1); … … 1950 2079 break; 1951 2080 1952 2081 case B_ix: 1953 2082 n = 0; 1954 2083 ll = strlen(as[1]); 1955 2084 l = strlen(as[0]) - ll; 1956 2085 if (ll > 0 && l >= 0) { 1957 if (! 2086 if (!icase) { 1958 2087 s = strstr(as[0], as[1]); 1959 2088 if (s) n = (s - as[0]) + 1; … … 1973 2102 break; 1974 2103 1975 2104 case B_ti: 1976 2105 if (nargs > 1) 1977 2106 tt = getvar_i(av[1]); 1978 2107 else 1979 2108 time(&tt); 1980 s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"; 1981 i = strftime(buf, MAXVARFMT, s, localtime(&tt)); 1982 buf[i] = '\0'; 1983 setvar_s(res, buf); 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); 1984 2115 break; 1985 2116 1986 2117 case B_ma: 1987 2118 re = as_regex(an[1], &sreg); 1988 2119 n = regexec(re, as[0], 1, pmatch, 0); … … 2000 2131 break; 2001 2132 2002 2133 case B_ge: 2003 2134 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE); 2004 2135 break; 2005 2136 2006 2137 case B_gs: 2007 2138 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE)); 2008 2139 break; 2009 2140 2010 2141 case B_su: 2011 2142 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE)); 2012 2143 break; … … 2015 2146 nvfree(tv); 2016 2147 return res; 2148 #undef tspl 2017 2149 } 2018 2150 … … 2025 2157 static var *evaluate(node *op, var *res) 2026 2158 { 2027 /* This procedure is recursive so we should count every byte */ 2028 static var *fnargs = NULL; 2029 static unsigned int seed = 1; 2030 static regex_t sreg; 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 2031 2165 node *op1; 2032 2166 var *v1; 2033 2167 union { 2034 2168 var *v; 2035 c har *s;2169 const char *s; 2036 2170 double d; 2037 2171 int i; 2038 2172 } L, R; 2039 2173 uint32_t opinfo; 2040 short opn;2174 int opn; 2041 2175 union { 2042 2176 char *s; … … 2048 2182 } X; 2049 2183 2050 if (! 2184 if (!op) 2051 2185 return setvar_s(res, NULL); 2052 2186 … … 2054 2188 2055 2189 while (op) { 2056 2057 2190 opinfo = op->info; 2058 opn = ( short)(opinfo & OPNMASK);2059 lineno = op->lineno;2191 opn = (opinfo & OPNMASK); 2192 g_lineno = op->lineno; 2060 2193 2061 2194 /* execute inevitable things */ … … 2069 2202 switch (XC(opinfo & OPCLSMASK)) { 2070 2203 2071 2072 2073 2074 2204 /* -- iterative node type -- */ 2205 2206 /* test pattern */ 2207 case XC( OC_TEST ): 2075 2208 if ((op1->info & OPCLSMASK) == OC_COMMA) { 2076 2209 /* it's range pattern */ … … 2089 2222 break; 2090 2223 2091 2092 2093 break; 2094 2095 2096 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 ): 2097 2230 op = istrue(L.v) ? op->a.n : op->r.n; 2098 2231 break; 2099 2232 2100 2101 2233 /* initialize for-in loop */ 2234 case XC( OC_WALKINIT ): 2102 2235 hashwalk_init(L.v, iamarray(R.v)); 2103 2236 break; 2104 2237 2105 2106 2238 /* get next array item */ 2239 case XC( OC_WALKNEXT ): 2107 2240 op = hashwalk_next(L.v) ? op->a.n : op->r.n; 2108 2241 break; 2109 2242 2110 2111 2243 case XC( OC_PRINT ): 2244 case XC( OC_PRINTF ): 2112 2245 X.F = stdout; 2113 2246 if (op->r.n) { 2114 2247 X.rsm = newfile(R.s); 2115 if (! 2248 if (!X.rsm->F) { 2116 2249 if (opn == '|') { 2117 if((X.rsm->F = popen(R.s, "w")) == NULL) 2250 X.rsm->F = popen(R.s, "w"); 2251 if (X.rsm->F == NULL) 2118 2252 bb_perror_msg_and_die("popen"); 2119 2253 X.rsm->is_pipe = 1; 2120 2254 } else { 2121 X.rsm->F = bb_xfopen(R.s, opn=='w' ? "w" : "a");2255 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a"); 2122 2256 } 2123 2257 } … … 2126 2260 2127 2261 if ((opinfo & OPCLSMASK) == OC_PRINT) { 2128 if (! 2129 fputs(getvar_s( V[F0]), X.F);2262 if (!op1) { 2263 fputs(getvar_s(intvar[F0]), X.F); 2130 2264 } else { 2131 2265 while (op1) { 2132 2266 L.v = evaluate(nextarg(&op1), v1); 2133 2267 if (L.v->type & VF_NUMBER) { 2134 fmt_num( buf, MAXVARFMT, getvar_s(V[OFMT]),2135 2136 fputs( buf, X.F);2268 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]), 2269 getvar_i(L.v), TRUE); 2270 fputs(g_buf, X.F); 2137 2271 } else { 2138 2272 fputs(getvar_s(L.v), X.F); 2139 2273 } 2140 2274 2141 if (op1) fputs(getvar_s( V[OFS]), X.F);2275 if (op1) fputs(getvar_s(intvar[OFS]), X.F); 2142 2276 } 2143 2277 } 2144 fputs(getvar_s( V[ORS]), X.F);2278 fputs(getvar_s(intvar[ORS]), X.F); 2145 2279 2146 2280 } else { /* OC_PRINTF */ 2147 2281 L.s = awk_printf(op1); 2148 2282 fputs(L.s, X.F); 2149 free( L.s);2283 free((char*)L.s); 2150 2284 } 2151 2285 fflush(X.F); 2152 2286 break; 2153 2287 2154 2288 case XC( OC_DELETE ): 2155 2289 X.info = op1->info & OPCLSMASK; 2156 2290 if (X.info == OC_VAR) { … … 2159 2293 R.v = &fnargs[op1->l.i]; 2160 2294 } else { 2161 runtime_error(EMSG_NOT_ARRAY);2295 syntax_error(EMSG_NOT_ARRAY); 2162 2296 } 2163 2297 … … 2171 2305 break; 2172 2306 2173 2174 programname = op->l.s;2175 break; 2176 2177 2307 case XC( OC_NEWSOURCE ): 2308 g_progname = op->l.s; 2309 break; 2310 2311 case XC( OC_RETURN ): 2178 2312 copyvar(res, L.v); 2179 2313 break; 2180 2314 2181 2315 case XC( OC_NEXTFILE ): 2182 2316 nextfile = TRUE; 2183 2317 case XC( OC_NEXT ): 2184 2318 nextrec = TRUE; 2185 2319 case XC( OC_DONE ): 2186 2320 clrvar(res); 2187 2321 break; 2188 2322 2189 2323 case XC( OC_EXIT ): 2190 2324 awk_exit(L.d); 2191 2325 2192 2193 2194 2326 /* -- recursive node type -- */ 2327 2328 case XC( OC_VAR ): 2195 2329 L.v = op->l.v; 2196 if (L.v == V[NF])2330 if (L.v == intvar[NF]) 2197 2331 split_f0(); 2198 2332 goto v_cont; 2199 2333 2200 2334 case XC( OC_FNARG ): 2201 2335 L.v = &fnargs[op->l.i]; 2202 2203 v_cont: 2204 res = (op->r.n) ? findvar(iamarray(L.v), R.s) : L.v; 2205 break; 2206 2207 case XC( OC_IN ): 2336 v_cont: 2337 res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v; 2338 break; 2339 2340 case XC( OC_IN ): 2208 2341 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0); 2209 2342 break; 2210 2343 2211 2344 case XC( OC_REGEXP ): 2212 2345 op1 = op; 2213 L.s = getvar_s( V[F0]);2346 L.s = getvar_s(intvar[F0]); 2214 2347 goto re_cont; 2215 2348 2216 2349 case XC( OC_MATCH ): 2217 2350 op1 = op->r.n; 2218 re_cont:2351 re_cont: 2219 2352 X.re = as_regex(op1, &sreg); 2220 2353 R.i = regexec(X.re, L.s, 0, NULL, 0); … … 2223 2356 break; 2224 2357 2225 2358 case XC( OC_MOVE ): 2226 2359 /* if source is a temporary string, jusk relink it to dest */ 2227 2360 if (R.v == v1+1 && R.v->string) { … … 2233 2366 break; 2234 2367 2235 2368 case XC( OC_TERNARY ): 2236 2369 if ((op->r.n->info & OPCLSMASK) != OC_COLON) 2237 runtime_error(EMSG_POSSIBLE_ERROR);2370 syntax_error(EMSG_POSSIBLE_ERROR); 2238 2371 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); 2239 2372 break; 2240 2373 2241 2242 if (! 2243 runtime_error(EMSG_UNDEF_FUNC);2374 case XC( OC_FUNC ): 2375 if (!op->r.f->body.first) 2376 syntax_error(EMSG_UNDEF_FUNC); 2244 2377 2245 2378 X.v = R.v = nvalloc(op->r.f->nargs+1); … … 2256 2389 fnargs = X.v; 2257 2390 2258 L.s = programname;2391 L.s = g_progname; 2259 2392 res = evaluate(op->r.f->body.first, res); 2260 programname = L.s;2393 g_progname = L.s; 2261 2394 2262 2395 nvfree(fnargs); … … 2264 2397 break; 2265 2398 2266 2267 2399 case XC( OC_GETLINE ): 2400 case XC( OC_PGETLINE ): 2268 2401 if (op1) { 2269 2402 X.rsm = newfile(L.s); 2270 if (! 2403 if (!X.rsm->F) { 2271 2404 if ((opinfo & OPCLSMASK) == OC_PGETLINE) { 2272 2405 X.rsm->F = popen(L.s, "r"); 2273 2406 X.rsm->is_pipe = TRUE; 2274 2407 } else { 2275 X.rsm->F = fopen(L.s, "r"); /* not bb_xfopen! */2408 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */ 2276 2409 } 2277 2410 } 2278 2411 } else { 2279 if (! 2412 if (!iF) iF = next_input_file(); 2280 2413 X.rsm = iF; 2281 2414 } 2282 2415 2283 if (! 2284 setvar_i( V[ERRNO], errno);2416 if (!X.rsm->F) { 2417 setvar_i(intvar[ERRNO], errno); 2285 2418 setvar_i(res, -1); 2286 2419 break; 2287 2420 } 2288 2421 2289 if (! 2290 R.v = V[F0];2422 if (!op->r.n) 2423 R.v = intvar[F0]; 2291 2424 2292 2425 L.i = awk_getline(X.rsm, R.v); 2293 2426 if (L.i > 0) { 2294 if (! 2295 incvar( V[FNR]);2296 incvar( V[NR]);2427 if (!op1) { 2428 incvar(intvar[FNR]); 2429 incvar(intvar[NR]); 2297 2430 } 2298 2431 } … … 2300 2433 break; 2301 2434 2302 2303 2435 /* simple builtins */ 2436 case XC( OC_FBLTIN ): 2304 2437 switch (opn) { 2305 2438 2306 2439 case F_in: 2307 2440 R.d = (int)L.d; 2308 2441 break; 2309 2442 2310 2311 R.d = 2443 case F_rn: 2444 R.d = (double)rand() / (double)RAND_MAX; 2312 2445 break; 2313 2314 #ifdef CONFIG_FEATURE_AWK_MATH 2315 case F_co: 2446 #if ENABLE_FEATURE_AWK_MATH 2447 case F_co: 2316 2448 R.d = cos(L.d); 2317 2449 break; 2318 2450 2319 2451 case F_ex: 2320 2452 R.d = exp(L.d); 2321 2453 break; 2322 2454 2323 2455 case F_lg: 2324 2456 R.d = log(L.d); 2325 2457 break; 2326 2458 2327 2459 case F_si: 2328 2460 R.d = sin(L.d); 2329 2461 break; 2330 2462 2331 2463 case F_sq: 2332 2464 R.d = sqrt(L.d); 2333 2465 break; 2334 2466 #else 2335 2336 2337 2338 2339 2340 runtime_error(EMSG_NO_MATH);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); 2341 2473 break; 2342 2474 #endif 2343 2344 case F_sr: 2475 case F_sr: 2345 2476 R.d = (double)seed; 2346 seed = op1 ? (unsigned int)L.d : (unsigned int)time(NULL);2477 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL); 2347 2478 srand(seed); 2348 2479 break; 2349 2480 2350 2481 case F_ti: 2351 2482 R.d = time(NULL); 2352 2483 break; 2353 2484 2354 2355 if (! 2356 L.s = getvar_s( V[F0]);2485 case F_le: 2486 if (!op1) 2487 L.s = getvar_s(intvar[F0]); 2357 2488 R.d = strlen(L.s); 2358 2489 break; 2359 2490 2360 2491 case F_sy: 2361 2492 fflush(NULL); 2362 R.d = (L.s && *L.s) ? (system(L.s) >> 8) : 0; 2493 R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s) 2494 ? (system(L.s) >> 8) : 0; 2363 2495 break; 2364 2496 2365 2366 if (! 2497 case F_ff: 2498 if (!op1) 2367 2499 fflush(stdout); 2368 2500 else { … … 2376 2508 break; 2377 2509 2378 2510 case F_cl: 2379 2511 X.rsm = (rstream *)hash_search(fdhash, L.s); 2380 2512 if (X.rsm) { … … 2384 2516 } 2385 2517 if (R.i != 0) 2386 setvar_i( V[ERRNO], errno);2518 setvar_i(intvar[ERRNO], errno); 2387 2519 R.d = (double)R.i; 2388 2520 break; … … 2391 2523 break; 2392 2524 2393 2525 case XC( OC_BUILTIN ): 2394 2526 res = exec_builtin(op, res); 2395 2527 break; 2396 2528 2397 2529 case XC( OC_SPRINTF ): 2398 2530 setvar_p(res, awk_printf(op1)); 2399 2531 break; 2400 2532 2401 2533 case XC( OC_UNARY ): 2402 2534 X.v = R.v; 2403 2535 L.d = R.d = getvar_i(R.v); 2404 2536 switch (opn) { 2405 2537 case 'P': 2406 2538 L.d = ++R.d; 2407 2539 goto r_op_change; 2408 2540 case 'p': 2409 2541 R.d++; 2410 2542 goto r_op_change; 2411 2543 case 'M': 2412 2544 L.d = --R.d; 2413 2545 goto r_op_change; 2414 2546 case 'm': 2415 2547 R.d--; 2416 2548 goto r_op_change; 2417 2418 2549 case '!': 2550 L.d = istrue(X.v) ? 0 : 1; 2419 2551 break; 2420 2552 case '-': 2421 2553 L.d = -R.d; 2422 2554 break; 2423 2555 r_op_change: 2424 2556 setvar_i(X.v, R.d); 2425 2557 } … … 2427 2559 break; 2428 2560 2429 2561 case XC( OC_FIELD ): 2430 2562 R.i = (int)getvar_i(R.v); 2431 2563 if (R.i == 0) { 2432 res = V[F0];2564 res = intvar[F0]; 2433 2565 } else { 2434 2566 split_f0(); 2435 2567 if (R.i > nfields) 2436 2568 fsrealloc(R.i); 2437 2438 res = &Fields[R.i-1]; 2439 } 2440 break; 2441 2442 /* concatenation (" ") and index joining (",") */ 2443 case XC( OC_CONCAT ): 2444 case XC( OC_COMMA ): 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 ): 2445 2576 opn = strlen(L.s) + strlen(R.s) + 2; 2446 X.s = (char *)xmalloc(opn);2577 X.s = xmalloc(opn); 2447 2578 strcpy(X.s, L.s); 2448 2579 if ((opinfo & OPCLSMASK) == OC_COMMA) { 2449 L.s = getvar_s( V[SUBSEP]);2450 X.s = (char *)xrealloc(X.s, opn + strlen(L.s));2580 L.s = getvar_s(intvar[SUBSEP]); 2581 X.s = xrealloc(X.s, opn + strlen(L.s)); 2451 2582 strcat(X.s, L.s); 2452 2583 } … … 2455 2586 break; 2456 2587 2457 2588 case XC( OC_LAND ): 2458 2589 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0); 2459 2590 break; 2460 2591 2461 2592 case XC( OC_LOR ): 2462 2593 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n)); 2463 2594 break; 2464 2595 2465 2466 2596 case XC( OC_BINARY ): 2597 case XC( OC_REPLACE ): 2467 2598 R.d = getvar_i(R.v); 2468 2599 switch (opn) { 2469 2600 case '+': 2470 2601 L.d += R.d; 2471 2602 break; 2472 2603 case '-': 2473 2604 L.d -= R.d; 2474 2605 break; 2475 2606 case '*': 2476 2607 L.d *= R.d; 2477 2608 break; 2478 2479 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);2609 case '/': 2610 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO); 2480 2611 L.d /= R.d; 2481 2612 break; 2482 2483 #if def CONFIG_FEATURE_AWK_MATH2613 case '&': 2614 #if ENABLE_FEATURE_AWK_MATH 2484 2615 L.d = pow(L.d, R.d); 2485 2616 #else 2486 runtime_error(EMSG_NO_MATH);2617 syntax_error(EMSG_NO_MATH); 2487 2618 #endif 2488 2619 break; 2489 2490 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);2620 case '%': 2621 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO); 2491 2622 L.d -= (int)(L.d / R.d) * R.d; 2492 2623 break; 2493 2624 } 2494 res = setvar_i(((opinfo &OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);2495 break; 2496 2497 2625 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d); 2626 break; 2627 2628 case XC( OC_COMPARE ): 2498 2629 if (is_numeric(L.v) && is_numeric(R.v)) { 2499 2630 L.d = getvar_i(L.v) - getvar_i(R.v); … … 2504 2635 } 2505 2636 switch (opn & 0xfe) { 2506 2637 case 0: 2507 2638 R.i = (L.d > 0); 2508 2639 break; 2509 2640 case 2: 2510 2641 R.i = (L.d >= 0); 2511 2642 break; 2512 2643 case 4: 2513 2644 R.i = (L.d == 0); 2514 2645 break; … … 2517 2648 break; 2518 2649 2519 2520 runtime_error(EMSG_POSSIBLE_ERROR);2650 default: 2651 syntax_error(EMSG_POSSIBLE_ERROR); 2521 2652 } 2522 2653 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS) … … 2529 2660 nvfree(v1); 2530 2661 return res; 2662 #undef fnargs 2663 #undef seed 2664 #undef sreg 2531 2665 } 2532 2666 … … 2536 2670 static int awk_exit(int r) 2537 2671 { 2538 unsigned int i; 2672 var tv; 2673 unsigned i; 2539 2674 hash_item *hi; 2540 static var tv; 2541 2542 if (! exiting) { 2675 2676 zero_out_var(&tv); 2677 2678 if (!exiting) { 2543 2679 exiting = TRUE; 2544 2680 nextrec = FALSE; … … 2547 2683 2548 2684 /* waiting for children */ 2549 for (i =0; i<fdhash->csize; i++) {2685 for (i = 0; i < fdhash->csize; i++) { 2550 2686 hi = fdhash->items[i]; 2551 while (hi) {2687 while (hi) { 2552 2688 if (hi->data.rs.F && hi->data.rs.is_pipe) 2553 2689 pclose(hi->data.rs.F); … … 2565 2701 char *exprc, *s, *s0, *s1; 2566 2702 2567 exprc = bb_xstrdup(expr);2703 exprc = xstrdup(expr); 2568 2704 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) { 2569 2705 free(exprc); … … 2585 2721 static rstream *next_input_file(void) 2586 2722 { 2587 static rstream rsm; 2723 #define rsm (G.next_input_file__rsm) 2724 #define files_happen (G.next_input_file__files_happen) 2725 2588 2726 FILE *F = NULL; 2589 char *fname, *ind; 2590 static int files_happen = FALSE; 2727 const char *fname, *ind; 2591 2728 2592 2729 if (rsm.F) fclose(rsm.F); … … 2595 2732 2596 2733 do { 2597 if (getvar_i( V[ARGIND])+1 >= getvar_i(V[ARGC])) {2734 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) { 2598 2735 if (files_happen) 2599 2736 return NULL; … … 2601 2738 F = stdin; 2602 2739 } else { 2603 ind = getvar_s(incvar( V[ARGIND]));2604 fname = getvar_s(findvar(iamarray( V[ARGV]), ind));2740 ind = getvar_s(incvar(intvar[ARGIND])); 2741 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind)); 2605 2742 if (fname && *fname && !is_assignment(fname)) 2606 2743 F = afopen(fname, "r"); … … 2609 2746 2610 2747 files_happen = TRUE; 2611 setvar_s( V[FILENAME], fname);2748 setvar_s(intvar[FILENAME], fname); 2612 2749 rsm.F = F; 2613 2750 return &rsm; 2614 } 2615 2751 #undef rsm 2752 #undef files_happen 2753 } 2754 2755 int awk_main(int argc, char **argv); 2616 2756 int awk_main(int argc, char **argv) 2617 2757 { 2618 char *s, *s1; 2619 int i, j, c, flen; 2758 unsigned opt; 2759 char *opt_F, *opt_W; 2760 llist_t *opt_v = NULL; 2761 int i, j, flen; 2620 2762 var *v; 2621 staticvar tv;2763 var tv; 2622 2764 char **envp; 2623 static int from_file = FALSE; 2624 rstream *rsm; 2625 FILE *F, *stdfiles[3]; 2626 static char * stdnames = "/dev/stdin\0/dev/stdout\0/dev/stderr"; 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); 2627 2776 2628 2777 /* allocate global buffer */ 2629 buf = xmalloc(MAXVARFMT+1);2778 g_buf = xmalloc(MAXVARFMT + 1); 2630 2779 2631 2780 vhash = hash_init(); … … 2635 2784 2636 2785 /* initialize variables */ 2637 for (i =0; *vNames;i++) {2638 V[i] = v = newvar(nextword(&vNames));2639 if (*v Values != '\377')2640 setvar_s(v, nextword(&v Values));2786 for (i = 0; *vnames; i++) { 2787 intvar[i] = v = newvar(nextword(&vnames)); 2788 if (*vvalues != '\377') 2789 setvar_s(v, nextword(&vvalues)); 2641 2790 else 2642 2791 setvar_i(v, 0); 2643 2792 2644 if (*v Names == '*') {2793 if (*vnames == '*') { 2645 2794 v->type |= VF_SPECIAL; 2646 vNames++; 2647 } 2648 } 2649 2650 handle_special(V[FS]); 2651 handle_special(V[RS]); 2652 2653 stdfiles[0] = stdin; 2654 stdfiles[1] = stdout; 2655 stdfiles[2] = stderr; 2656 for (i=0; i<3; i++) { 2657 rsm = newfile(nextword(&stdnames)); 2658 rsm->F = stdfiles[i]; 2659 } 2660 2661 for (envp=environ; *envp; envp++) { 2662 s = bb_xstrdup(*envp); 2663 s1 = strchr(s, '='); 2664 if (!s1) { 2665 goto keep_going; 2666 } 2667 *(s1++) = '\0'; 2668 setvar_u(findvar(iamarray(V[ENVIRON]), s), s1); 2669 keep_going: 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); 2670 2847 free(s); 2671 } 2672 2673 while((c = getopt(argc, argv, "F:v:f:W:")) != EOF) { 2674 switch (c) { 2675 case 'F': 2676 setvar_s(V[FS], optarg); 2677 break; 2678 case 'v': 2679 if (! is_assignment(optarg)) 2680 bb_show_usage(); 2681 break; 2682 case 'f': 2683 from_file = TRUE; 2684 F = afopen(programname = optarg, "r"); 2685 s = NULL; 2686 /* one byte is reserved for some trick in next_token */ 2687 if (fseek(F, 0, SEEK_END) == 0) { 2688 flen = ftell(F); 2689 s = (char *)xmalloc(flen+4); 2690 fseek(F, 0, SEEK_SET); 2691 i = 1 + fread(s+1, 1, flen, F); 2692 } else { 2693 for (i=j=1; j>0; i+=j) { 2694 s = (char *)xrealloc(s, i+4096); 2695 j = fread(s+i, 1, 4094, F); 2696 } 2697 } 2698 s[i] = '\0'; 2699 fclose(F); 2700 parse_program(s+1); 2701 free(s); 2702 break; 2703 case 'W': 2704 bb_error_msg("Warning: unrecognized option '-W %s' ignored\n", optarg); 2705 break; 2706 2707 default: 2708 bb_show_usage(); 2709 } 2710 } 2711 2712 if (!from_file) { 2713 if (argc == optind) 2848 } else { // no -f: take program from 1st parameter 2849 if (!argc) 2714 2850 bb_show_usage(); 2715 programname="cmd. line"; 2716 parse_program(argv[optind++]); 2717 2718 } 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); 2719 2857 2720 2858 /* fill in ARGV array */ 2721 setvar_i(V[ARGC], argc - optind + 1); 2722 setari_u(V[ARGV], 0, "awk"); 2723 for(i=optind; i < argc; i++) 2724 setari_u(V[ARGV], i+1-optind, argv[i]); 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++); 2725 2864 2726 2865 evaluate(beginseq.first, &tv); 2727 if (! mainseq.first && !endseq.first)2866 if (!mainseq.first && !endseq.first) 2728 2867 awk_exit(EXIT_SUCCESS); 2729 2868 2730 2869 /* input file could already be opened in BEGIN block */ 2731 if (! 2870 if (!iF) iF = next_input_file(); 2732 2871 2733 2872 /* passing through input files */ 2734 2873 while (iF) { 2735 2736 2874 nextfile = FALSE; 2737 setvar_i(V[FNR], 0); 2738 2739 while ((c = awk_getline(iF, V[F0])) > 0) { 2740 2875 setvar_i(intvar[FNR], 0); 2876 2877 while ((i = awk_getline(iF, intvar[F0])) > 0) { 2741 2878 nextrec = FALSE; 2742 incvar( V[NR]);2743 incvar( V[FNR]);2879 incvar(intvar[NR]); 2880 incvar(intvar[FNR]); 2744 2881 evaluate(mainseq.first, &tv); 2745 2882 … … 2748 2885 } 2749 2886 2750 if ( c< 0)2751 runtime_error(strerror(errno));2887 if (i < 0) 2888 syntax_error(strerror(errno)); 2752 2889 2753 2890 iF = next_input_file(); 2754 2755 2891 } 2756 2892 2757 2893 awk_exit(EXIT_SUCCESS); 2758 2759 return 0; 2760 } 2761 2894 /*return 0;*/ 2895 }
Note:
See TracChangeset
for help on using the changeset viewer.