#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;
typedef struct chain_s {
struct node_s *first;
struct node_s *last;
- char *programname;
+ const char *programname;
} chain;
/* Function */
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;
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) {
{
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);
int l;
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 == '#')
/* 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;
*(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 {
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;
/* -------- 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;
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;
/* 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) {
}
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;
char c[4];
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';
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 {
}
} else if (c[0] == '\0') { /* null split */
while (*s) {
- *(s1++) = *(s++);
- *(s1++) = '\0';
+ *s1++ = *s++;
+ *s1++ = '\0';
n++;
}
} else if (c[0] != ' ') { /* single-character split */
}
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;
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]) {
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;
} 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... */
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;
/* if there was an error while sprintf, return value is negative */
if (i < j) i = j;
-
}
b = xrealloc(b, i + 1);
* 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;
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;
s[n] = '\0';
setvar_p(res, s);
break;
-
+
case B_an:
setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
break;
-
+
case B_co:
setvar_i(res, ~(long)getvar_i(av[0]));
break;
case B_up:
to_xxx = toupper;
-lo_cont:
+ lo_cont:
s1 = s = xstrdup(as[0]);
while (*s1) {
*s1 = (*to_xxx)(*s1);
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;
static var *fnargs = NULL;
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;
uint32_t info;
} X;
- if (! op)
+ if (!op)
return setvar_s(res, NULL);
v1 = nvalloc(2);
} 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_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_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);
{
static rstream rsm;
FILE *F = NULL;
- char *fname, *ind;
+ const char *fname, *ind;
static int files_happen = FALSE;
if (rsm.F) fclose(rsm.F);
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 *opt_F, *opt_W;
+ llist_t *opt_v = NULL;
int i, j, flen;
var *v;
var tv;
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 */
}
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
char *s = s; /* die, gcc, die */
FILE *from_file = afopen(programname, "r");