Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/editors/awk.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.815  
changed lines
  Added in v.816