- use bb_error_msg
[oweals/busybox.git] / editors / awk.c
index b776dd7965088a0ec4ef28ae709b2c5a3843475f..a18025ef0ab42373668ca4abab2680ff13f2fae8 100644 (file)
 #include <math.h>
 
 
-#define        MAXVARFMT       240
-#define        MINNVBLOCK      64
+#define        MAXVARFMT       240
+#define        MINNVBLOCK      64
 
 /* variable flags */
-#define        VF_NUMBER       0x0001  /* 1 = primary type is number */
-#define        VF_ARRAY        0x0002  /* 1 = it's an array */
+#define        VF_NUMBER       0x0001  /* 1 = primary type is number */
+#define        VF_ARRAY        0x0002  /* 1 = it's an array */
 
-#define        VF_CACHED       0x0100  /* 1 = num/str value has cached str/num eq */
-#define        VF_USER         0x0200  /* 1 = user input (may be numeric string) */
-#define        VF_SPECIAL      0x0400  /* 1 = requires extra handling when changed */
-#define        VF_WALK         0x0800  /* 1 = variable has alloc'd x.walker list */
-#define        VF_FSTR         0x1000  /* 1 = string points to fstring buffer */
-#define        VF_CHILD        0x2000  /* 1 = function arg; x.parent points to source */
-#define        VF_DIRTY        0x4000  /* 1 = variable was set explicitly */
+#define        VF_CACHED       0x0100  /* 1 = num/str value has cached str/num eq */
+#define        VF_USER         0x0200  /* 1 = user input (may be numeric string) */
+#define        VF_SPECIAL      0x0400  /* 1 = requires extra handling when changed */
+#define        VF_WALK         0x0800  /* 1 = variable has alloc'd x.walker list */
+#define        VF_FSTR         0x1000  /* 1 = var::string points to fstring buffer */
+#define        VF_CHILD        0x2000  /* 1 = function arg; x.parent points to source */
+#define        VF_DIRTY        0x4000  /* 1 = variable was set explicitly */
 
 /* these flags are static, don't change them when value is changed */
-#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)
 
 /* Variable */
 typedef struct var_s {
-       unsigned short type;            /* flags */
+       unsigned short type;            /* flags */
        double number;
        char *string;
        union {
-               int aidx;                               /* func arg idx (for compilation stage) */
-               struct xhash_s *array;  /* array ptr */
-               struct var_s *parent;   /* for func args, ptr to actual parameter */
-               char **walker;                  /* list of array elements (for..in) */
+               int aidx;               /* func arg idx (for compilation stage) */
+               struct xhash_s *array;  /* array ptr */
+               struct var_s *parent;   /* for func args, ptr to actual parameter */
+               char **walker;          /* list of array elements (for..in) */
        } x;
 } var;
 
@@ -47,7 +47,7 @@ typedef struct var_s {
 typedef struct chain_s {
        struct node_s *first;
        struct node_s *last;
-       char *programname;
+       const char *programname;
 } chain;
 
 /* Function */
@@ -77,10 +77,10 @@ typedef struct hash_item_s {
 } hash_item;
 
 typedef struct xhash_s {
-       unsigned int nel;                                       /* num of elements */
-       unsigned int csize;                                     /* current hash size */
-       unsigned int nprime;                            /* next hash size in PRIMES[] */
-       unsigned int glen;                                      /* summary length of item names */
+       unsigned nel;                                   /* num of elements */
+       unsigned csize;                                 /* current hash size */
+       unsigned nprime;                                /* next hash size in PRIMES[] */
+       unsigned glen;                                  /* summary length of item names */
        struct hash_item_s **items;
 } xhash;
 
@@ -260,88 +260,87 @@ enum {
 
 #define        OC_B    OC_BUILTIN
 
-static char * const tokenlist =
-       "\1("           NTC
-       "\1)"           NTC
-       "\1/"           NTC                                                                     /* REGEXP */
-       "\2>>"          "\1>"           "\1|"           NTC                     /* OUTRDR */
-       "\2++"          "\2--"          NTC                                             /* UOPPOST */
-       "\2++"          "\2--"          "\1$"           NTC                     /* UOPPRE1 */
-       "\2=="          "\1="           "\2+="          "\2-="          /* BINOPX */
-       "\2*="          "\2/="          "\2%="          "\2^="
-       "\1+"           "\1-"           "\3**="         "\2**"
-       "\1/"           "\1%"           "\1^"           "\1*"
-       "\2!="          "\2>="          "\2<="          "\1>"
-       "\1<"           "\2!~"          "\1~"           "\2&&"
-       "\2||"          "\1?"           "\1:"           NTC
-       "\2in"          NTC
-       "\1,"           NTC
-       "\1|"           NTC
-       "\1+"           "\1-"           "\1!"           NTC                     /* UOPPRE2 */
-       "\1]"           NTC
-       "\1{"           NTC
-       "\1}"           NTC
-       "\1;"           NTC
-       "\1\n"          NTC
-       "\2if"          "\2do"          "\3for"         "\5break"       /* STATX */
-       "\10continue"                   "\6delete"      "\5print"
-       "\6printf"      "\4next"        "\10nextfile"
-       "\6return"      "\4exit"        NTC
-       "\5while"       NTC
-       "\4else"        NTC
-
-       "\3and"         "\5compl"       "\6lshift"      "\2or"
-       "\6rshift"      "\3xor"
-       "\5close"       "\6system"      "\6fflush"      "\5atan2"       /* BUILTIN */
-       "\3cos"         "\3exp"         "\3int"         "\3log"
-       "\4rand"        "\3sin"         "\4sqrt"        "\5srand"
-       "\6gensub"      "\4gsub"        "\5index"       "\6length"
-       "\5match"       "\5split"       "\7sprintf"     "\3sub"
-       "\6substr"      "\7systime"     "\10strftime"
-       "\7tolower"     "\7toupper"     NTC
-       "\7getline"     NTC
-       "\4func"        "\10function"   NTC
-       "\5BEGIN"       NTC
-       "\3END"         "\0"
+static const char tokenlist[] =
+       "\1("       NTC
+       "\1)"       NTC
+       "\1/"       NTC                                 /* REGEXP */
+       "\2>>"      "\1>"       "\1|"       NTC         /* OUTRDR */
+       "\2++"      "\2--"      NTC                     /* UOPPOST */
+       "\2++"      "\2--"      "\1$"       NTC         /* UOPPRE1 */
+       "\2=="      "\1="       "\2+="      "\2-="      /* BINOPX */
+       "\2*="      "\2/="      "\2%="      "\2^="
+       "\1+"       "\1-"       "\3**="     "\2**"
+       "\1/"       "\1%"       "\1^"       "\1*"
+       "\2!="      "\2>="      "\2<="      "\1>"
+       "\1<"       "\2!~"      "\1~"       "\2&&"
+       "\2||"      "\1?"       "\1:"       NTC
+       "\2in"      NTC
+       "\1,"       NTC
+       "\1|"       NTC
+       "\1+"       "\1-"       "\1!"       NTC         /* UOPPRE2 */
+       "\1]"       NTC
+       "\1{"       NTC
+       "\1}"       NTC
+       "\1;"       NTC
+       "\1\n"      NTC
+       "\2if"      "\2do"      "\3for"     "\5break"   /* STATX */
+       "\10continue"           "\6delete"  "\5print"
+       "\6printf"  "\4next"    "\10nextfile"
+       "\6return"  "\4exit"    NTC
+       "\5while"   NTC
+       "\4else"    NTC
+
+       "\3and"     "\5compl"   "\6lshift"  "\2or"
+       "\6rshift"  "\3xor"
+       "\5close"   "\6system"  "\6fflush"  "\5atan2"   /* BUILTIN */
+       "\3cos"     "\3exp"     "\3int"     "\3log"
+       "\4rand"    "\3sin"     "\4sqrt"    "\5srand"
+       "\6gensub"  "\4gsub"    "\5index"   "\6length"
+       "\5match"   "\5split"   "\7sprintf" "\3sub"
+       "\6substr"  "\7systime" "\10strftime"
+       "\7tolower" "\7toupper" NTC
+       "\7getline" NTC
+       "\4func"    "\10function"   NTC
+       "\5BEGIN"   NTC
+       "\3END"     "\0"
        ;
 
 static const uint32_t tokeninfo[] = {
-
        0,
        0,
        OC_REGEXP,
-       xS|'a',         xS|'w',         xS|'|',
-       OC_UNARY|xV|P(9)|'p',           OC_UNARY|xV|P(9)|'m',
-       OC_UNARY|xV|P(9)|'P',           OC_UNARY|xV|P(9)|'M',
-               OC_FIELD|xV|P(5),
-       OC_COMPARE|VV|P(39)|5,          OC_MOVE|VV|P(74),
-               OC_REPLACE|NV|P(74)|'+',        OC_REPLACE|NV|P(74)|'-',
-       OC_REPLACE|NV|P(74)|'*',        OC_REPLACE|NV|P(74)|'/',
-               OC_REPLACE|NV|P(74)|'%',        OC_REPLACE|NV|P(74)|'&',
-       OC_BINARY|NV|P(29)|'+',         OC_BINARY|NV|P(29)|'-',
-               OC_REPLACE|NV|P(74)|'&',        OC_BINARY|NV|P(15)|'&',
-       OC_BINARY|NV|P(25)|'/',         OC_BINARY|NV|P(25)|'%',
-               OC_BINARY|NV|P(15)|'&',         OC_BINARY|NV|P(25)|'*',
-       OC_COMPARE|VV|P(39)|4,          OC_COMPARE|VV|P(39)|3,
-               OC_COMPARE|VV|P(39)|0,          OC_COMPARE|VV|P(39)|1,
-       OC_COMPARE|VV|P(39)|2,          OC_MATCH|Sx|P(45)|'!',
-               OC_MATCH|Sx|P(45)|'~',          OC_LAND|Vx|P(55),
-       OC_LOR|Vx|P(59),                        OC_TERNARY|Vx|P(64)|'?',
-               OC_COLON|xx|P(67)|':',
+       xS|'a',     xS|'w',     xS|'|',
+       OC_UNARY|xV|P(9)|'p',       OC_UNARY|xV|P(9)|'m',
+       OC_UNARY|xV|P(9)|'P',       OC_UNARY|xV|P(9)|'M',
+           OC_FIELD|xV|P(5),
+       OC_COMPARE|VV|P(39)|5,      OC_MOVE|VV|P(74),
+           OC_REPLACE|NV|P(74)|'+',    OC_REPLACE|NV|P(74)|'-',
+       OC_REPLACE|NV|P(74)|'*',    OC_REPLACE|NV|P(74)|'/',
+           OC_REPLACE|NV|P(74)|'%',    OC_REPLACE|NV|P(74)|'&',
+       OC_BINARY|NV|P(29)|'+',     OC_BINARY|NV|P(29)|'-',
+           OC_REPLACE|NV|P(74)|'&',    OC_BINARY|NV|P(15)|'&',
+       OC_BINARY|NV|P(25)|'/',     OC_BINARY|NV|P(25)|'%',
+           OC_BINARY|NV|P(15)|'&',     OC_BINARY|NV|P(25)|'*',
+       OC_COMPARE|VV|P(39)|4,      OC_COMPARE|VV|P(39)|3,
+           OC_COMPARE|VV|P(39)|0,      OC_COMPARE|VV|P(39)|1,
+       OC_COMPARE|VV|P(39)|2,      OC_MATCH|Sx|P(45)|'!',
+           OC_MATCH|Sx|P(45)|'~',      OC_LAND|Vx|P(55),
+       OC_LOR|Vx|P(59),            OC_TERNARY|Vx|P(64)|'?',
+           OC_COLON|xx|P(67)|':',
        OC_IN|SV|P(49),
        OC_COMMA|SS|P(80),
        OC_PGETLINE|SV|P(37),
-       OC_UNARY|xV|P(19)|'+',          OC_UNARY|xV|P(19)|'-',
-               OC_UNARY|xV|P(19)|'!',
+       OC_UNARY|xV|P(19)|'+',      OC_UNARY|xV|P(19)|'-',
+           OC_UNARY|xV|P(19)|'!',
        0,
        0,
        0,
        0,
        0,
-       ST_IF,                  ST_DO,                  ST_FOR,                 OC_BREAK,
-       OC_CONTINUE,                                    OC_DELETE|Vx,   OC_PRINT,
-       OC_PRINTF,              OC_NEXT,                OC_NEXTFILE,
-       OC_RETURN|Vx,   OC_EXIT|Nx,
+       ST_IF,          ST_DO,          ST_FOR,         OC_BREAK,
+       OC_CONTINUE,                    OC_DELETE|Vx,   OC_PRINT,
+       OC_PRINTF,      OC_NEXT,        OC_NEXTFILE,
+       OC_RETURN|Vx,   OC_EXIT|Nx,
        ST_WHILE,
        0,
 
@@ -363,32 +362,32 @@ static const uint32_t tokeninfo[] = {
 /* internal variable names and their initial values       */
 /* asterisk marks SPECIAL vars; $ is just no-named Field0 */
 enum {
-       CONVFMT=0,      OFMT,           FS,                     OFS,
-       ORS,            RS,                     RT,                     FILENAME,
-       SUBSEP,         ARGIND,         ARGC,           ARGV,
-       ERRNO,          FNR,
-       NR,                     NF,                     IGNORECASE,
-       ENVIRON,        F0,                     _intvarcount_
+       CONVFMT=0,  OFMT,       FS,         OFS,
+       ORS,        RS,         RT,         FILENAME,
+       SUBSEP,     ARGIND,     ARGC,       ARGV,
+       ERRNO,      FNR,
+       NR,         NF,         IGNORECASE,
+       ENVIRON,    F0,         _intvarcount_
 };
 
-static char * vNames =
-       "CONVFMT\0"     "OFMT\0"        "FS\0*"         "OFS\0"
-       "ORS\0"         "RS\0*"         "RT\0"          "FILENAME\0"
-       "SUBSEP\0"      "ARGIND\0"      "ARGC\0"        "ARGV\0"
-       "ERRNO\0"       "FNR\0"
-       "NR\0"          "NF\0*"         "IGNORECASE\0*"
-       "ENVIRON\0"     "$\0*"          "\0";
-
-static char * vValues =
-       "%.6g\0"        "%.6g\0"        " \0"           " \0"
-       "\n\0"          "\n\0"          "\0"            "\0"
+static const char vNames[] =
+       "CONVFMT\0" "OFMT\0"    "FS\0*"     "OFS\0"
+       "ORS\0"     "RS\0*"     "RT\0"      "FILENAME\0"
+       "SUBSEP\0"  "ARGIND\0"  "ARGC\0"    "ARGV\0"
+       "ERRNO\0"   "FNR\0"
+       "NR\0"      "NF\0*"     "IGNORECASE\0*"
+       "ENVIRON\0" "$\0*"      "\0";
+
+static const char vValues[] =
+       "%.6g\0"    "%.6g\0"    " \0"       " \0"
+       "\n\0"      "\n\0"      "\0"        "\0"
        "\034\0"
        "\377";
 
 /* hash size may grow to these values */
 #define FIRST_PRIME 61;
-static const unsigned int PRIMES[] = { 251, 1021, 4093, 16381, 65521 };
-enum { NPRIMES = sizeof(PRIMES) / sizeof(unsigned int) };
+static const unsigned PRIMES[] = { 251, 1021, 4093, 16381, 65521 };
+enum { NPRIMES = sizeof(PRIMES) / sizeof(unsigned) };
 
 /* globals */
 
@@ -400,7 +399,7 @@ static int nextrec, nextfile;
 static node *break_ptr, *continue_ptr;
 static rstream *iF;
 static xhash *vhash, *ahash, *fdhash, *fnhash;
-static char *programname;
+static const char *programname;
 static short lineno;
 static int is_f0_split;
 static int nfields;
@@ -441,10 +440,15 @@ static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin";
 static const char EMSG_NOT_ARRAY[] = "Not an array";
 static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error";
 static const char EMSG_UNDEF_FUNC[] = "Call to undefined function";
-#ifndef CONFIG_FEATURE_AWK_MATH
+#if !ENABLE_FEATURE_AWK_MATH
 static const char EMSG_NO_MATH[] = "Math support is not compiled in";
 #endif
 
+static void zero_out_var(var * vp)
+{
+       memset(vp, 0, sizeof(*vp));
+}
+
 static void syntax_error(const char * const message) ATTRIBUTE_NORETURN;
 static void syntax_error(const char * const message)
 {
@@ -456,11 +460,11 @@ static void syntax_error(const char * const message)
 
 /* ---- hash stuff ---- */
 
-static unsigned int hashidx(const char *name)
+static unsigned hashidx(const char *name)
 {
-       unsigned int idx=0;
+       unsigned idx = 0;
 
-       while (*name)  idx = *name++ + (idx << 6) - idx;
+       while (*name) idx = *name++ + (idx << 6) - idx;
        return idx;
 }
 
@@ -469,9 +473,9 @@ static xhash *hash_init(void)
 {
        xhash *newhash;
 
-       newhash = (xhash *)xzalloc(sizeof(xhash));
+       newhash = xzalloc(sizeof(xhash));
        newhash->csize = FIRST_PRIME;
-       newhash->items = (hash_item **)xzalloc(newhash->csize * sizeof(hash_item *));
+       newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
 
        return newhash;
 }
@@ -493,14 +497,14 @@ static void *hash_search(xhash *hash, const char *name)
 /* grow hash if it becomes too big */
 static void hash_rebuild(xhash *hash)
 {
-       unsigned int newsize, i, idx;
+       unsigned newsize, i, idx;
        hash_item **newitems, *hi, *thi;
 
        if (hash->nprime == NPRIMES)
                return;
 
        newsize = PRIMES[hash->nprime++];
-       newitems = (hash_item **)xzalloc(newsize * sizeof(hash_item *));
+       newitems = xzalloc(newsize * sizeof(hash_item *));
 
        for (i=0; i<hash->csize; i++) {
                hi = hash->items[i];
@@ -522,7 +526,7 @@ static void hash_rebuild(xhash *hash)
 static void *hash_find(xhash *hash, const char *name)
 {
        hash_item *hi;
-       unsigned int idx;
+       unsigned idx;
        int l;
 
        hi = hash_search(hash, name);
@@ -542,10 +546,10 @@ static void *hash_find(xhash *hash, const char *name)
        return &(hi->data);
 }
 
-#define findvar(hash, name) (var *) hash_find ( (hash) , (name) )
-#define newvar(name) (var *) hash_find ( vhash , (name) )
-#define newfile(name) (rstream *) hash_find ( fdhash , (name) )
-#define newfunc(name) (func *) hash_find ( fnhash , (name) )
+#define findvar(hash, name) ((var*)    hash_find((hash) , (name)))
+#define newvar(name)        ((var*)    hash_find(vhash , (name)))
+#define newfile(name)       ((rstream*)hash_find(fdhash ,(name)))
+#define newfunc(name)       ((func*)   hash_find(fnhash , (name)))
 
 static void hash_remove(xhash *hash, const char *name)
 {
@@ -571,7 +575,7 @@ static void skip_spaces(char **s)
 {
        char *p = *s;
 
-       while(*p == ' ' || *p == '\t' ||
+       while (*p == ' ' || *p == '\t' ||
                        (*p == '\\' && *(p+1) == '\n' && (++p, ++t.lineno))) {
                p++;
        }
@@ -582,7 +586,7 @@ static char *nextword(char **s)
 {
        char *p = *s;
 
-       while (*(*s)++) ;
+       while (*(*s)++) /* */;
 
        return p;
 }
@@ -626,7 +630,7 @@ static xhash *iamarray(var *v)
 
 static void clear_array(xhash *array)
 {
-       unsigned int i;
+       unsigned i;
        hash_item *hi, *thi;
 
        for (i=0; i<array->csize; i++) {
@@ -699,7 +703,7 @@ static var *setvar_i(var *v, double value)
        return v;
 }
 
-static char *getvar_s(var *v)
+static const char *getvar_s(var *v)
 {
        /* if v is numeric and has no cached string, convert it to string */
        if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
@@ -736,7 +740,7 @@ static var *copyvar(var *dest, const var *src)
 {
        if (dest != src) {
                clrvar(dest);
-               dest->type |= (src->type & ~VF_DONTTOUCH);
+               dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
                dest->number = src->number;
                if (src->string)
                        dest->string = xstrdup(src->string);
@@ -781,7 +785,7 @@ static var *nvalloc(int n)
 
        if (! cb) {
                size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
-               cb = (nvblock *)xmalloc(sizeof(nvblock) + size * sizeof(var));
+               cb = xmalloc(sizeof(nvblock) + size * sizeof(var));
                cb->size = size;
                cb->pos = cb->nv;
                cb->prev = pb;
@@ -833,30 +837,27 @@ static void nvfree(var *v)
  */
 static uint32_t next_token(uint32_t expected)
 {
+       static int concat_inserted;
+       static uint32_t save_tclass, save_info;
+       static uint32_t ltclass = TC_OPTERM;
+
        char *p, *pp, *s;
-       char *tl;
+       const char *tl;
        uint32_t tc;
        const uint32_t *ti;
        int l;
-       static int concat_inserted;
-       static uint32_t save_tclass, save_info;
-       static uint32_t ltclass = TC_OPTERM;
 
        if (t.rollback) {
-
                t.rollback = FALSE;
 
        } else if (concat_inserted) {
-
                concat_inserted = FALSE;
                t.tclass = save_tclass;
                t.info = save_info;
 
        } else {
-
                p = pos;
-
-       readnext:
+ readnext:
                skip_spaces(&p);
                lineno = t.lineno;
                if (*p == '#')
@@ -930,21 +931,21 @@ static uint32_t next_token(uint32_t expected)
                                tl += l;
                        }
 
-                       if (! *tl) {
+                       if (!*tl) {
                                /* it's a name (var/array/function),
                                 * otherwise it's something wrong
                                 */
-                               if (! isalnum_(*p))
+                               if (!isalnum_(*p))
                                        syntax_error(EMSG_UNEXP_TOKEN);
 
                                t.string = --p;
-                               while(isalnum_(*(++p))) {
+                               while (isalnum_(*(++p))) {
                                        *(p-1) = *p;
                                }
                                *(p-1) = '\0';
                                tc = TC_VARIABLE;
                                /* also consume whitespace between functionname and bracket */
-                               if (! (expected & TC_VARIABLE)) skip_spaces(&p);
+                               if (!(expected & TC_VARIABLE)) skip_spaces(&p);
                                if (*p == '(') {
                                        tc = TC_FUNCTION;
                                } else {
@@ -988,13 +989,13 @@ static node *new_node(uint32_t info)
 {
        node *n;
 
-       n = (node *)xzalloc(sizeof(node));
+       n = xzalloc(sizeof(node));
        n->info = info;
        n->lineno = lineno;
        return n;
 }
 
-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)
 {
        n->info = OC_REGEXP;
        n->l.re = re;
@@ -1072,8 +1073,8 @@ static node *parse_expr(uint32_t iexp)
                                /* one should be very careful with switch on tclass -
                                 * only simple tclasses should be used! */
                                switch (tc) {
-                                 case TC_VARIABLE:
-                                 case TC_ARRAY:
+                               case TC_VARIABLE:
+                               case TC_ARRAY:
                                        cn->info = OC_VAR;
                                        if ((v = hash_search(ahash, t.string)) != NULL) {
                                                cn->info = OC_FNARG;
@@ -1087,8 +1088,8 @@ static node *parse_expr(uint32_t iexp)
                                        }
                                        break;
 
-                                 case TC_NUMBER:
-                                 case TC_STRING:
+                               case TC_NUMBER:
+                               case TC_STRING:
                                        cn->info = OC_VAR;
                                        v = cn->l.v = xzalloc(sizeof(var));
                                        if (tc & TC_NUMBER)
@@ -1097,28 +1098,27 @@ static node *parse_expr(uint32_t iexp)
                                                setvar_s(v, t.string);
                                        break;
 
-                                 case TC_REGEXP:
-                                       mk_re_node(t.string, cn,
-                                                                       (regex_t *)xzalloc(sizeof(regex_t)*2));
+                               case TC_REGEXP:
+                                       mk_re_node(t.string, cn, xzalloc(sizeof(regex_t)*2));
                                        break;
 
-                                 case TC_FUNCTION:
+                               case TC_FUNCTION:
                                        cn->info = OC_FUNC;
                                        cn->r.f = newfunc(t.string);
                                        cn->l.n = condition();
                                        break;
 
-                                 case TC_SEQSTART:
+                               case TC_SEQSTART:
                                        cn = vn->r.n = parse_expr(TC_SEQTERM);
                                        cn->a.n = vn;
                                        break;
 
-                                 case TC_GETLINE:
+                               case TC_GETLINE:
                                        glptr = cn;
                                        xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
                                        break;
 
-                                 case TC_BUILTIN:
+                               case TC_BUILTIN:
                                        cn->l.n = condition();
                                        break;
                                }
@@ -1193,7 +1193,7 @@ static void chain_group(void)
        } while (c & TC_NEWLINE);
 
        if (c & TC_GRPSTART) {
-               while(next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
+               while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
                        if (t.tclass & TC_NEWLINE) continue;
                        rollback_token();
                        chain_group();
@@ -1234,7 +1234,7 @@ static void chain_group(void)
                        case ST_FOR:
                                next_token(TC_SEQSTART);
                                n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
-                               if (t.tclass & TC_SEQTERM) {                            /* for-in */
+                               if (t.tclass & TC_SEQTERM) {    /* for-in */
                                        if ((n2->info & OPCLSMASK) != OC_IN)
                                                syntax_error(EMSG_UNEXP_TOKEN);
                                        n = chain_node(OC_WALKINIT | VV);
@@ -1243,7 +1243,7 @@ static void chain_group(void)
                                        n = chain_loop(NULL);
                                        n->info = OC_WALKNEXT | Vx;
                                        n->l.n = n2->l.n;
-                               } else {                                                                        /* for(;;) */
+                               } else {                        /* for (;;) */
                                        n = chain_node(OC_EXEC | Vx);
                                        n->l.n = n2;
                                        n2 = parse_expr(TC_SEMICOL);
@@ -1280,7 +1280,6 @@ static void chain_group(void)
                        /* delete, next, nextfile, return, exit */
                        default:
                                chain_expr(t.info);
-
                }
        }
 }
@@ -1294,7 +1293,7 @@ static void parse_program(char *p)
 
        pos = p;
        t.lineno = 1;
-       while((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
+       while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
                                TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
 
                if (tclass & TC_OPTERM)
@@ -1315,7 +1314,7 @@ static void parse_program(char *p)
                        f = newfunc(t.string);
                        f->body.first = NULL;
                        f->nargs = 0;
-                       while(next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
+                       while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
                                v = findvar(ahash, t.string);
                                v->x.aidx = (f->nargs)++;
 
@@ -1348,7 +1347,7 @@ static void parse_program(char *p)
 
 /* -------- program execution part -------- */
 
-static node *mk_splitter(char *s, tsplitter *spl)
+static node *mk_splitter(const char *s, tsplitter *spl)
 {
        regex_t *re, *ire;
        node *n;
@@ -1376,7 +1375,7 @@ static node *mk_splitter(char *s, tsplitter *spl)
 static regex_t *as_regex(node *op, regex_t *preg)
 {
        var *v;
-       char *s;
+       const char *s;
 
        if ((op->info & OPCLSMASK) == OC_REGEXP) {
                return icase ? op->r.ire : op->l.re;
@@ -1392,43 +1391,44 @@ static regex_t *as_regex(node *op, regex_t *preg)
 /* gradually increasing buffer */
 static void qrealloc(char **b, int n, int *size)
 {
-       if (! *b || n >= *size)
+       if (!*b || n >= *size)
                *b = xrealloc(*b, *size = n + (n>>1) + 80);
 }
 
 /* resize field storage space */
 static void fsrealloc(int size)
 {
-       static int maxfields = 0;
+       static int maxfields; /* = 0;*/
        int i;
 
        if (size >= maxfields) {
                i = maxfields;
                maxfields = size + 16;
-               Fields = (var *)xrealloc(Fields, maxfields * sizeof(var));
-               for (; i<maxfields; i++) {
+               Fields = xrealloc(Fields, maxfields * sizeof(var));
+               for (; i < maxfields; i++) {
                        Fields[i].type = VF_SPECIAL;
                        Fields[i].string = NULL;
                }
        }
 
        if (size < nfields) {
-               for (i=size; i<nfields; i++) {
-                       clrvar(Fields+i);
+               for (i = size; i < nfields; i++) {
+                       clrvar(Fields + i);
                }
        }
        nfields = size;
 }
 
-static int awk_split(char *s, node *spl, char **slist)
+static int awk_split(const char *s, node *spl, char **slist)
 {
-       int l, n=0;
+       int l, n = 0;
        char c[4];
        char *s1;
        regmatch_t pmatch[2];
 
        /* in worst case, each char would be a separate field */
-       *slist = s1 = xstrndup(s, strlen(s) * 2 + 3);
+       *slist = s1 = xzalloc(strlen(s) * 2 + 3);
+       strcpy(s1, s);
 
        c[0] = c[1] = (char)spl->info;
        c[2] = c[3] = '\0';
@@ -1437,25 +1437,26 @@ static int awk_split(char *s, node *spl, char **slist)
        if ((spl->info & OPCLSMASK) == OC_REGEXP) {             /* regex split */
                while (*s) {
                        l = strcspn(s, c+2);
-                       if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0 &&
-                       pmatch[0].rm_so <= l) {
+                       if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
+                        && pmatch[0].rm_so <= l
+                       ) {
                                l = pmatch[0].rm_so;
                                if (pmatch[0].rm_eo == 0) { l++; pmatch[0].rm_eo++; }
                        } else {
                                pmatch[0].rm_eo = l;
-                               if (*(s+l)) pmatch[0].rm_eo++;
+                               if (s[l]) pmatch[0].rm_eo++;
                        }
 
                        memcpy(s1, s, l);
-                       *(s1+l) = '\0';
+                       s1[l] = '\0';
                        nextword(&s1);
                        s += pmatch[0].rm_eo;
                        n++;
                }
        } else if (c[0] == '\0') {              /* null split */
-               while(*s) {
-                       *(s1++) = *(s++);
-                       *(s1++) = '\0';
+               while (*s) {
+                       *s1++ = *s++;
+                       *s1++ = '\0';
                        n++;
                }
        } else if (c[0] != ' ') {               /* single-character split */
@@ -1465,17 +1466,17 @@ static int awk_split(char *s, node *spl, char **slist)
                }
                if (*s1) n++;
                while ((s1 = strpbrk(s1, c))) {
-                       *(s1++) = '\0';
+                       *s1++ = '\0';
                        n++;
                }
        } else {                                /* space split */
                while (*s) {
                        s = skip_whitespace(s);
-                       if (! *s) break;
+                       if (!*s) break;
                        n++;
                        while (*s && !isspace(*s))
-                               *(s1++) = *(s++);
-                       *(s1++) = '\0';
+                               *s1++ = *s++;
+                       *s1++ = '\0';
                }
        }
        return n;
@@ -1496,7 +1497,7 @@ static void split_f0(void)
        n = awk_split(getvar_s(V[F0]), &fsplitter.n, &fstrings);
        fsrealloc(n);
        s = fstrings;
-       for (i=0; i<n; i++) {
+       for (i = 0; i < n; i++) {
                Fields[i].string = nextword(&s);
                Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
        }
@@ -1511,10 +1512,11 @@ static void split_f0(void)
 static void handle_special(var *v)
 {
        int n;
-       char *b, *sep, *s;
+       char *b;
+       const char *sep, *s;
        int sl, l, len, i, bsize;
 
-       if (! (v->type & VF_SPECIAL))
+       if (!(v->type & VF_SPECIAL))
                return;
 
        if (v == V[NF]) {
@@ -1537,7 +1539,8 @@ static void handle_special(var *v)
                        memcpy(b+len, s, l);
                        len += l;
                }
-               if (b) b[len] = '\0';
+               if (b)
+                       b[len] = '\0';
                setvar_p(V[F0], b);
                is_f0_split = TRUE;
 
@@ -1553,7 +1556,7 @@ static void handle_special(var *v)
        } else if (v == V[IGNORECASE]) {
                icase = istrue(v);
 
-       } else {                                                /* $n */
+       } else {                                /* $n */
                n = getvar_i(V[NF]);
                setvar_i(V[NF], n > v-Fields ? n : v-Fields+1);
                /* right here v is invalid. Just to note... */
@@ -1585,11 +1588,11 @@ static void hashwalk_init(var *v, xhash *array)
                free(v->x.walker);
 
        v->type |= VF_WALK;
-       w = v->x.walker = (char **)xzalloc(2 + 2*sizeof(char *) + array->glen);
+       w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
        *w = *(w+1) = (char *)(w + 2);
        for (i=0; i<array->csize; i++) {
                hi = array->items[i];
-               while(hi) {
+               while (hi) {
                        strcpy(*w, hi->name);
                        nextword(w);
                        hi = hi->next;
@@ -1612,7 +1615,8 @@ static int hashwalk_next(var *v)
 /* evaluate node, return 1 when result is true, 0 otherwise */
 static int ptest(node *pattern)
 {
-       static var v;
+       static var v; /* static: to save stack space? */
+
        return istrue(evaluate(pattern, &v));
 }
 
@@ -1712,14 +1716,14 @@ static int awk_getline(rstream *rsm, var *v)
 
 static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
 {
-       int r=0;
+       int r = 0;
        char c;
-       const char *s=format;
+       const char *s = format;
 
        if (int_as_int && n == (int)n) {
                r = snprintf(b, size, "%d", (int)n);
        } else {
-               do { c = *s; } while (*s && *++s);
+               do { c = *s; } while (c && *++s);
                if (strchr("diouxX", c)) {
                        r = snprintf(b, size, format, (int)n);
                } else if (strchr("eEfgG", c)) {
@@ -1736,7 +1740,8 @@ static int fmt_num(char *b, int size, const char *format, double n, int int_as_i
 static char *awk_printf(node *n)
 {
        char *b = NULL;
-       char *fmt, *s, *s1, *f;
+       char *fmt, *s, *f;
+       const char *s1;
        int i, j, incr, bsize;
        char c, c1;
        var *v, *arg;
@@ -1753,15 +1758,17 @@ static char *awk_printf(node *n)
                        f++;
 
                incr = (f - s) + MAXVARFMT;
-               qrealloc(&b, incr+i, &bsize);
-               c = *f; if (c != '\0') f++;
-               c1 = *f ; *f = '\0';
+               qrealloc(&b, incr + i, &bsize);
+               c = *f;
+               if (c != '\0') f++;
+               c1 = *f;
+               *f = '\0';
                arg = evaluate(nextarg(&n), v);
 
                j = i;
                if (c == 'c' || !c) {
-                       i += sprintf(b+i, s,
-                                       is_numeric(arg) ? (char)getvar_i(arg) : *getvar_s(arg));
+                       i += sprintf(b+i, s, is_numeric(arg) ?
+                                       (char)getvar_i(arg) : *getvar_s(arg));
 
                } else if (c == 's') {
                        s1 = getvar_s(arg);
@@ -1775,10 +1782,9 @@ static char *awk_printf(node *n)
 
                /* if there was an error while sprintf, return value is negative */
                if (i < j) i = j;
-
        }
 
-       b = xrealloc(b, i+1);
+       b = xrealloc(b, i + 1);
        free(fmt);
        nvfree(v);
        b[i] = '\0';
@@ -1791,10 +1797,11 @@ static char *awk_printf(node *n)
  * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
  * subexpression matching (\1-\9)
  */
-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)
 {
        char *ds = NULL;
-       char *sp, *s;
+       const char *s;
+       const char *sp;
        int c, i, j, di, rl, so, eo, nbs, n, dssize;
        regmatch_t pmatch[10];
        regex_t sreg, *re;
@@ -1863,7 +1870,7 @@ static var *exec_builtin(node *op, var *res)
        var *tv;
        node *an[4];
        var  *av[4];
-       char *as[4];
+       const char *as[4];
        regmatch_t pmatch[2];
        regex_t sreg, *re;
        static tsplitter tspl;
@@ -1892,15 +1899,15 @@ static var *exec_builtin(node *op, var *res)
 
        switch (info & OPNMASK) {
 
-         case B_a2:
-#ifdef CONFIG_FEATURE_AWK_MATH
+       case B_a2:
+#if ENABLE_FEATURE_AWK_MATH
                setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
 #else
                runtime_error(EMSG_NO_MATH);
 #endif
                break;
 
-         case B_sp:
+       case B_sp:
                if (nargs > 2) {
                        spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
                                an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
@@ -1917,7 +1924,7 @@ static var *exec_builtin(node *op, var *res)
                setvar_i(res, n);
                break;
 
-         case B_ss:
+       case B_ss:
                l = strlen(as[0]);
                i = getvar_i(av[1]) - 1;
                if (i>l) i=l; if (i<0) i=0;
@@ -1928,38 +1935,38 @@ static var *exec_builtin(node *op, var *res)
                s[n] = '\0';
                setvar_p(res, s);
                break;
-               
-        case B_an:
+
+       case B_an:
                setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
                break;
-               
-        case B_co:
+
+       case B_co:
                setvar_i(res, ~(long)getvar_i(av[0]));
                break;
 
-        case B_ls:
+       case B_ls:
                setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
                break;
 
-        case B_or:
+       case B_or:
                setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
                break;
 
-        case B_rs:
+       case B_rs:
                setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
                break;
 
-        case B_xo:
+       case B_xo:
                setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
                break;
 
-         case B_lo:
+       case B_lo:
                to_xxx = tolower;
                goto lo_cont;
 
-         case B_up:
+       case B_up:
                to_xxx = toupper;
-lo_cont:
+ lo_cont:
                s1 = s = xstrdup(as[0]);
                while (*s1) {
                        *s1 = (*to_xxx)(*s1);
@@ -1968,7 +1975,7 @@ lo_cont:
                setvar_p(res, s);
                break;
 
-         case B_ix:
+       case B_ix:
                n = 0;
                ll = strlen(as[1]);
                l = strlen(as[0]) - ll;
@@ -1991,18 +1998,20 @@ lo_cont:
                setvar_i(res, n);
                break;
 
-         case B_ti:
+       case B_ti:
                if (nargs > 1)
                        tt = getvar_i(av[1]);
                else
                        time(&tt);
-               s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
-               i = strftime(buf, MAXVARFMT, s, localtime(&tt));
+               //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
+               i = strftime(buf, MAXVARFMT,
+                       ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
+                       localtime(&tt));
                buf[i] = '\0';
                setvar_s(res, buf);
                break;
 
-         case B_ma:
+       case B_ma:
                re = as_regex(an[1], &sreg);
                n = regexec(re, as[0], 1, pmatch, 0);
                if (n == 0) {
@@ -2018,15 +2027,15 @@ lo_cont:
                if (re == &sreg) regfree(re);
                break;
 
-         case B_ge:
+       case B_ge:
                awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
                break;
 
-         case B_gs:
+       case B_gs:
                setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
                break;
 
-         case B_su:
+       case B_su:
                setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
                break;
        }
@@ -2045,13 +2054,14 @@ static var *evaluate(node *op, var *res)
 {
        /* This procedure is recursive so we should count every byte */
        static var *fnargs = NULL;
-       static unsigned int seed = 1;
+       static unsigned seed = 1;
        static regex_t sreg;
+
        node *op1;
        var *v1;
        union {
                var *v;
-               char *s;
+               const char *s;
                double d;
                int i;
        } L, R;
@@ -2066,7 +2076,7 @@ static var *evaluate(node *op, var *res)
                uint32_t info;
        } X;
 
-       if (! op)
+       if (!op)
                return setvar_s(res, NULL);
 
        v1 = nvalloc(2);
@@ -2090,7 +2100,7 @@ static var *evaluate(node *op, var *res)
                  /* -- iterative node type -- */
 
                  /* test pattern */
-                 case XC( OC_TEST ):
+               case XC( OC_TEST ):
                        if ((op1->info & OPCLSMASK) == OC_COMMA) {
                                /* it's range pattern */
                                if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
@@ -2108,26 +2118,26 @@ static var *evaluate(node *op, var *res)
                        break;
 
                  /* just evaluate an expression, also used as unconditional jump */
-                 case XC( OC_EXEC ):
+               case XC( OC_EXEC ):
                        break;
 
                  /* branch, used in if-else and various loops */
-                 case XC( OC_BR ):
+               case XC( OC_BR ):
                        op = istrue(L.v) ? op->a.n : op->r.n;
                        break;
 
                  /* initialize for-in loop */
-                 case XC( OC_WALKINIT ):
+               case XC( OC_WALKINIT ):
                        hashwalk_init(L.v, iamarray(R.v));
                        break;
 
                  /* get next array item */
-                 case XC( OC_WALKNEXT ):
+               case XC( OC_WALKNEXT ):
                        op = hashwalk_next(L.v) ? op->a.n : op->r.n;
                        break;
 
-                 case XC( OC_PRINT ):
-                 case XC( OC_PRINTF ):
+               case XC( OC_PRINT ):
+               case XC( OC_PRINTF ):
                        X.F = stdout;
                        if (op->r.n) {
                                X.rsm = newfile(R.s);
@@ -2151,7 +2161,7 @@ static var *evaluate(node *op, var *res)
                                                L.v = evaluate(nextarg(&op1), v1);
                                                if (L.v->type & VF_NUMBER) {
                                                        fmt_num(buf, MAXVARFMT, getvar_s(V[OFMT]),
-                                                                                                               getvar_i(L.v), TRUE);
+                                                                       getvar_i(L.v), TRUE);
                                                        fputs(buf, X.F);
                                                } else {
                                                        fputs(getvar_s(L.v), X.F);
@@ -2165,12 +2175,12 @@ static var *evaluate(node *op, var *res)
                        } else {        /* OC_PRINTF */
                                L.s = awk_printf(op1);
                                fputs(L.s, X.F);
-                               free(L.s);
+                               free((char*)L.s);
                        }
                        fflush(X.F);
                        break;
 
-                 case XC( OC_DELETE ):
+               case XC( OC_DELETE ):
                        X.info = op1->info & OPCLSMASK;
                        if (X.info == OC_VAR) {
                                R.v = op1->l.v;
@@ -2189,59 +2199,58 @@ static var *evaluate(node *op, var *res)
                        }
                        break;
 
-                 case XC( OC_NEWSOURCE ):
+               case XC( OC_NEWSOURCE ):
                        programname = op->l.s;
                        break;
 
-                 case XC( OC_RETURN ):
+               case XC( OC_RETURN ):
                        copyvar(res, L.v);
                        break;
 
-                 case XC( OC_NEXTFILE ):
+               case XC( OC_NEXTFILE ):
                        nextfile = TRUE;
-                 case XC( OC_NEXT ):
+               case XC( OC_NEXT ):
                        nextrec = TRUE;
-                 case XC( OC_DONE ):
+               case XC( OC_DONE ):
                        clrvar(res);
                        break;
 
-                 case XC( OC_EXIT ):
+               case XC( OC_EXIT ):
                        awk_exit(L.d);
 
                  /* -- recursive node type -- */
 
-                 case XC( OC_VAR ):
+               case XC( OC_VAR ):
                        L.v = op->l.v;
                        if (L.v == V[NF])
                                split_f0();
                        goto v_cont;
 
-                 case XC( OC_FNARG ):
+               case XC( OC_FNARG ):
                        L.v = &fnargs[op->l.i];
-
-v_cont:
-                       res = (op->r.n) ? findvar(iamarray(L.v), R.s) : L.v;
+ v_cont:
+                       res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
                        break;
 
-                 case XC( OC_IN ):
+               case XC( OC_IN ):
                        setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
                        break;
 
-                 case XC( OC_REGEXP ):
+               case XC( OC_REGEXP ):
                        op1 = op;
                        L.s = getvar_s(V[F0]);
                        goto re_cont;
 
-                 case XC( OC_MATCH ):
+               case XC( OC_MATCH ):
                        op1 = op->r.n;
-re_cont:
+ re_cont:
                        X.re = as_regex(op1, &sreg);
                        R.i = regexec(X.re, L.s, 0, NULL, 0);
                        if (X.re == &sreg) regfree(X.re);
                        setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
                        break;
 
-                 case XC( OC_MOVE ):
+               case XC( OC_MOVE ):
                        /* if source is a temporary string, jusk relink it to dest */
                        if (R.v == v1+1 && R.v->string) {
                                res = setvar_p(L.v, R.v->string);
@@ -2251,13 +2260,13 @@ re_cont:
                        }
                        break;
 
-                 case XC( OC_TERNARY ):
+               case XC( OC_TERNARY ):
                        if ((op->r.n->info & OPCLSMASK) != OC_COLON)
                                runtime_error(EMSG_POSSIBLE_ERROR);
                        res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
                        break;
 
-                 case XC( OC_FUNC ):
+               case XC( OC_FUNC ):
                        if (! op->r.f->body.first)
                                runtime_error(EMSG_UNDEF_FUNC);
 
@@ -2282,8 +2291,8 @@ re_cont:
                        fnargs = R.v;
                        break;
 
-                 case XC( OC_GETLINE ):
-                 case XC( OC_PGETLINE ):
+               case XC( OC_GETLINE ):
+               case XC( OC_PGETLINE ):
                        if (op1) {
                                X.rsm = newfile(L.s);
                                if (! X.rsm->F) {
@@ -2319,69 +2328,70 @@ re_cont:
                        break;
 
                  /* simple builtins */
-                 case XC( OC_FBLTIN ):
+               case XC( OC_FBLTIN ):
                        switch (opn) {
 
-                         case F_in:
+                       case F_in:
                                R.d = (int)L.d;
                                break;
 
-                         case F_rn:
-                               R.d =  (double)rand() / (double)RAND_MAX;
+                       case F_rn:
+                               R.d = (double)rand() / (double)RAND_MAX;
                                break;
 
-#ifdef CONFIG_FEATURE_AWK_MATH
-                         case F_co:
+#if ENABLE_FEATURE_AWK_MATH
+                       case F_co:
                                R.d = cos(L.d);
                                break;
 
-                         case F_ex:
+                       case F_ex:
                                R.d = exp(L.d);
                                break;
 
-                         case F_lg:
+                       case F_lg:
                                R.d = log(L.d);
                                break;
 
-                         case F_si:
+                       case F_si:
                                R.d = sin(L.d);
                                break;
 
-                         case F_sq:
+                       case F_sq:
                                R.d = sqrt(L.d);
                                break;
 #else
-                         case F_co:
-                         case F_ex:
-                         case F_lg:
-                         case F_si:
-                         case F_sq:
+                       case F_co:
+                       case F_ex:
+                       case F_lg:
+                       case F_si:
+                       case F_sq:
                                runtime_error(EMSG_NO_MATH);
                                break;
 #endif
 
-                         case F_sr:
+                       case F_sr:
                                R.d = (double)seed;
-                               seed = op1 ? (unsigned int)L.d : (unsigned int)time(NULL);
+                               seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
                                srand(seed);
                                break;
 
-                         case F_ti:
+                       case F_ti:
                                R.d = time(NULL);
                                break;
 
-                         case F_le:
+                       case F_le:
                                if (! op1)
                                        L.s = getvar_s(V[F0]);
                                R.d = strlen(L.s);
                                break;
 
-                         case F_sy:
+                       case F_sy:
                                fflush(NULL);
-                               R.d = (L.s && *L.s) ? (system(L.s) >> 8) : 0;
+                               R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
+                                               ? (system(L.s) >> 8) : 0;
                                break;
 
-                         case F_ff:
+                       case F_ff:
                                if (! op1)
                                        fflush(stdout);
                                else {
@@ -2394,7 +2404,7 @@ re_cont:
                                }
                                break;
 
-                         case F_cl:
+                       case F_cl:
                                X.rsm = (rstream *)hash_search(fdhash, L.s);
                                if (X.rsm) {
                                        R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
@@ -2409,43 +2419,43 @@ re_cont:
                        setvar_i(res, R.d);
                        break;
 
-                 case XC( OC_BUILTIN ):
+               case XC( OC_BUILTIN ):
                        res = exec_builtin(op, res);
                        break;
 
-                 case XC( OC_SPRINTF ):
+               case XC( OC_SPRINTF ):
                        setvar_p(res, awk_printf(op1));
                        break;
 
-                 case XC( OC_UNARY ):
+               case XC( OC_UNARY ):
                        X.v = R.v;
                        L.d = R.d = getvar_i(R.v);
                        switch (opn) {
-                         case 'P':
+                       case 'P':
                                L.d = ++R.d;
                                goto r_op_change;
-                         case 'p':
+                       case 'p':
                                R.d++;
                                goto r_op_change;
-                         case 'M':
+                       case 'M':
                                L.d = --R.d;
                                goto r_op_change;
-                         case 'm':
+                       case 'm':
                                R.d--;
                                goto r_op_change;
-                         case '!':
+                       case '!':
                                L.d = istrue(X.v) ? 0 : 1;
                                break;
-                         case '-':
+                       case '-':
                                L.d = -R.d;
                                break;
                      r_op_change:
+ r_op_change:
                                setvar_i(X.v, R.d);
                        }
                        setvar_i(res, L.d);
                        break;
 
-                 case XC( OC_FIELD ):
+               case XC( OC_FIELD ):
                        R.i = (int)getvar_i(R.v);
                        if (R.i == 0) {
                                res = V[F0];
@@ -2459,53 +2469,53 @@ re_cont:
                        break;
 
                  /* concatenation (" ") and index joining (",") */
-                 case XC( OC_CONCAT ):
-                 case XC( OC_COMMA ):
+               case XC( OC_CONCAT ):
+               case XC( OC_COMMA ):
                        opn = strlen(L.s) + strlen(R.s) + 2;
-                       X.s = (char *)xmalloc(opn);
+                       X.s = xmalloc(opn);
                        strcpy(X.s, L.s);
                        if ((opinfo & OPCLSMASK) == OC_COMMA) {
                                L.s = getvar_s(V[SUBSEP]);
-                               X.s = (char *)xrealloc(X.s, opn + strlen(L.s));
+                               X.s = xrealloc(X.s, opn + strlen(L.s));
                                strcat(X.s, L.s);
                        }
                        strcat(X.s, R.s);
                        setvar_p(res, X.s);
                        break;
 
-                 case XC( OC_LAND ):
+               case XC( OC_LAND ):
                        setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
                        break;
 
-                 case XC( OC_LOR ):
+               case XC( OC_LOR ):
                        setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
                        break;
 
-                 case XC( OC_BINARY ):
-                 case XC( OC_REPLACE ):
+               case XC( OC_BINARY ):
+               case XC( OC_REPLACE ):
                        R.d = getvar_i(R.v);
                        switch (opn) {
-                         case '+':
+                       case '+':
                                L.d += R.d;
                                break;
-                         case '-':
+                       case '-':
                                L.d -= R.d;
                                break;
-                         case '*':
+                       case '*':
                                L.d *= R.d;
                                break;
-                         case '/':
+                       case '/':
                                if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
                                L.d /= R.d;
                                break;
-                         case '&':
-#ifdef CONFIG_FEATURE_AWK_MATH
+                       case '&':
+#if ENABLE_FEATURE_AWK_MATH
                                L.d = pow(L.d, R.d);
 #else
                                runtime_error(EMSG_NO_MATH);
 #endif
                                break;
-                         case '%':
+                       case '%':
                                if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
                                L.d -= (int)(L.d / R.d) * R.d;
                                break;
@@ -2513,7 +2523,7 @@ re_cont:
                        res = setvar_i(((opinfo&OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
                        break;
 
-                 case XC( OC_COMPARE ):
+               case XC( OC_COMPARE ):
                        if (is_numeric(L.v) && is_numeric(R.v)) {
                                L.d = getvar_i(L.v) - getvar_i(R.v);
                        } else {
@@ -2522,20 +2532,20 @@ re_cont:
                                L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
                        }
                        switch (opn & 0xfe) {
-                         case 0:
+                       case 0:
                                R.i = (L.d > 0);
                                break;
-                         case 2:
+                       case 2:
                                R.i = (L.d >= 0);
                                break;
-                         case 4:
+                       case 4:
                                R.i = (L.d == 0);
                                break;
                        }
                        setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
                        break;
 
-                 default:
+               default:
                        runtime_error(EMSG_POSSIBLE_ERROR);
                }
                if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
@@ -2554,20 +2564,22 @@ re_cont:
 
 static int awk_exit(int r)
 {
-       unsigned int i;
+       var tv;
+       unsigned i;
        hash_item *hi;
-       static var tv;
 
-       if (! exiting) {
+       zero_out_var(&tv);
+
+       if (!exiting) {
                exiting = TRUE;
                nextrec = FALSE;
                evaluate(endseq.first, &tv);
        }
 
        /* waiting for children */
-       for (i=0; i<fdhash->csize; i++) {
+       for (i = 0; i < fdhash->csize; i++) {
                hi = fdhash->items[i];
-               while(hi) {
+               while (hi) {
                        if (hi->data.rs.F && hi->data.rs.is_pipe)
                                pclose(hi->data.rs.F);
                        hi = hi->next;
@@ -2605,7 +2617,7 @@ static rstream *next_input_file(void)
 {
        static rstream rsm;
        FILE *F = NULL;
-       char *fname, *ind;
+       const char *fname, *ind;
        static int files_happen = FALSE;
 
        if (rsm.F) fclose(rsm.F);
@@ -2632,22 +2644,28 @@ static rstream *next_input_file(void)
        return &rsm;
 }
 
+int awk_main(int argc, char **argv);
 int awk_main(int argc, char **argv)
 {
        unsigned opt;
-       char *opt_F, *opt_v, *opt_W;
-       char *s, *s1;
-       int i, j, c, flen;
+       char *opt_F, *opt_W;
+       llist_t *opt_v = NULL;
+       int i, j, flen;
        var *v;
-       static var tv;
+       var tv;
        char **envp;
-       static int from_file = FALSE;
-       rstream *rsm;
-       FILE *F, *stdfiles[3];
-       static char * stdnames = "/dev/stdin\0/dev/stdout\0/dev/stderr";
+       char *vnames = (char *)vNames; /* cheat */
+       char *vvalues = (char *)vValues;
+
+       /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
+        * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
+       if (ENABLE_LOCALE_SUPPORT)
+               setlocale(LC_NUMERIC, "C");
+
+       zero_out_var(&tv);
 
        /* allocate global buffer */
-       buf = xmalloc(MAXVARFMT+1);
+       buf = xmalloc(MAXVARFMT + 1);
 
        vhash = hash_init();
        ahash = hash_init();
@@ -2655,98 +2673,94 @@ int awk_main(int argc, char **argv)
        fnhash = hash_init();
 
        /* initialize variables */
-       for (i=0;  *vNames;  i++) {
-               V[i] = v = newvar(nextword(&vNames));
-               if (*vValues != '\377')
-                       setvar_s(v, nextword(&vValues));
+       for (i = 0; *vnames; i++) {
+               V[i] = v = newvar(nextword(&vnames));
+               if (*vvalues != '\377')
+                       setvar_s(v, nextword(&vvalues));
                else
                        setvar_i(v, 0);
 
-               if (*vNames == '*') {
+               if (*vnames == '*') {
                        v->type |= VF_SPECIAL;
-                       vNames++;
+                       vnames++;
                }
        }
 
        handle_special(V[FS]);
        handle_special(V[RS]);
 
-       stdfiles[0] = stdin;
-       stdfiles[1] = stdout;
-       stdfiles[2] = stderr;
-       for (i=0; i<3; i++) {
-               rsm = newfile(nextword(&stdnames));
-               rsm->F = stdfiles[i];
-       }
+       newfile("/dev/stdin")->F = stdin;
+       newfile("/dev/stdout")->F = stdout;
+       newfile("/dev/stderr")->F = stderr;
 
-       for (envp=environ; *envp; envp++) {
-               s = xstrdup(*envp);
-               s1 = strchr(s, '=');
-               if (!s1) {
-                       goto keep_going;
+       for (envp = environ; *envp; envp++) {
+               char *s = xstrdup(*envp);
+               char *s1 = strchr(s, '=');
+               if (s1) {
+                       *s1++ = '\0';
+                       setvar_u(findvar(iamarray(V[ENVIRON]), s), s1);
                }
-               *(s1++) = '\0';
-               setvar_u(findvar(iamarray(V[ENVIRON]), s), s1);
-keep_going:
                free(s);
        }
-
+       opt_complementary = "v::";
        opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &programname, &opt_W);
+       argv += optind;
+       argc -= optind;
        if (opt & 0x1) setvar_s(V[FS], opt_F); // -F
-       if (opt & 0x2) if (!is_assignment(opt_v)) bb_show_usage(); // -v
+       opt_v = llist_rev(opt_v);
+       while (opt_v) { /* -v */
+               if (!is_assignment(llist_pop(&opt_v)))
+                       bb_show_usage();
+       }
        if (opt & 0x4) { // -f
-               from_file = TRUE;
-               F = afopen(programname, "r");
-               s = NULL;
+               char *s = s; /* die, gcc, die */
+               FILE *from_file = afopen(programname, "r");
                /* one byte is reserved for some trick in next_token */
-               if (fseek(F, 0, SEEK_END) == 0) {
-                       flen = ftell(F);
-                       s = (char *)xmalloc(flen+4);
-                       fseek(F, 0, SEEK_SET);
-                       i = 1 + fread(s+1, 1, flen, F);
+               if (fseek(from_file, 0, SEEK_END) == 0) {
+                       flen = ftell(from_file);
+                       s = xmalloc(flen + 4);
+                       fseek(from_file, 0, SEEK_SET);
+                       i = 1 + fread(s + 1, 1, flen, from_file);
                } else {
-                       for (i=j=1; j>0; i+=j) {
-                               s = (char *)xrealloc(s, i+4096);
-                               j = fread(s+i, 1, 4094, F);
+                       for (i = j = 1; j > 0; i += j) {
+                               s = xrealloc(s, i + 4096);
+                               j = fread(s + i, 1, 4094, from_file);
                        }
                }
                s[i] = '\0';
-               fclose(F);
-               parse_program(s+1);
+               fclose(from_file);
+               parse_program(s + 1);
                free(s);
-       }
-       if (opt & 0x8) // -W
-               bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
-
-       if (!from_file) {
-               if (argc == optind)
+       } else { // no -f: take program from 1st parameter
+               if (!argc)
                        bb_show_usage();
                programname = "cmd. line";
-               parse_program(argv[optind++]);
-
+               parse_program(*argv++);
+               argc--;
        }
+       if (opt & 0x8) // -W
+               bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
 
        /* fill in ARGV array */
-       setvar_i(V[ARGC], argc - optind + 1);
+       setvar_i(V[ARGC], argc + 1);
        setari_u(V[ARGV], 0, "awk");
-       for(i=optind; i < argc; i++)
-               setari_u(V[ARGV], i+1-optind, argv[i]);
+       i = 0;
+       while (*argv)
+               setari_u(V[ARGV], ++i, *argv++);
 
        evaluate(beginseq.first, &tv);
-       if (! mainseq.first && ! endseq.first)
+       if (!mainseq.first && !endseq.first)
                awk_exit(EXIT_SUCCESS);
 
        /* input file could already be opened in BEGIN block */
-       if (! iF) iF = next_input_file();
+       if (!iF) iF = next_input_file();
 
        /* passing through input files */
        while (iF) {
-
                nextfile = FALSE;
                setvar_i(V[FNR], 0);
 
-               while ((c = awk_getline(iF, V[F0])) > 0) {
-
+               while ((i = awk_getline(iF, V[F0])) > 0) {
                        nextrec = FALSE;
                        incvar(V[NR]);
                        incvar(V[FNR]);
@@ -2756,15 +2770,12 @@ keep_going:
                                break;
                }
 
-               if (c < 0)
+               if (i < 0)
                        runtime_error(strerror(errno));
 
                iF = next_input_file();
-
        }
 
        awk_exit(EXIT_SUCCESS);
-
-       return 0;
+       /*return 0;*/
 }
-