summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editors/awk.c182
-rwxr-xr-xtestsuite/awk.tests6
2 files changed, 102 insertions, 86 deletions
diff --git a/editors/awk.c b/editors/awk.c
index 2245cad..fb3bf6b 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -283,88 +283,80 @@ enum {
#define OC_B OC_BUILTIN
static const char tokenlist[] ALIGN1 =
- "\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" "\6mktime"
- "\7tolower" "\7toupper" NTC
- "\7getline" NTC
- "\4func" "\10function" NTC
- "\5BEGIN" NTC
- "\3END" "\0"
+ "\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" "\6mktime"
+ "\7tolower" "\7toupper" NTC
+ "\7getline" NTC
+ "\4func" "\10function" NTC
+ "\5BEGIN" NTC
+ "\3END"
+ /* compiler adds trailing "\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)|':',
- OC_IN|SV|P(49),
+ 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), /* in */
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,
- 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,
+ 0, /* \n */
+ 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,
+ 0, /* else */
OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
@@ -376,9 +368,9 @@ static const uint32_t tokeninfo[] = {
OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b),
OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
OC_GETLINE|SV|P(0),
- 0, 0,
+ 0, 0,
0,
- 0
+ 0 /* END */
};
/* internal variable names and their initial values */
@@ -1836,6 +1828,8 @@ static int awk_getline(rstream *rsm, var *v)
int fd, so, eo, r, rp;
char c, *m, *s;
+ debug_printf_eval("entered %s()\n", __func__);
+
/* we're using our own buffer since we need access to accumulating
* characters
*/
@@ -1922,6 +1916,8 @@ static int awk_getline(rstream *rsm, var *v)
rsm->pos = p - eo;
rsm->size = size;
+ debug_printf_eval("returning from %s(): %d\n", __func__, r);
+
return r;
}
@@ -2347,6 +2343,8 @@ static var *evaluate(node *op, var *res)
if (!op)
return setvar_s(res, NULL);
+ debug_printf_eval("entered %s()\n", __func__);
+
v1 = nvalloc(2);
while (op) {
@@ -2367,7 +2365,7 @@ static var *evaluate(node *op, var *res)
opn = (opinfo & OPNMASK);
g_lineno = op->lineno;
op1 = op->l.n;
- debug_printf_eval("opinfo:%08x opn:%08x XC:%x\n", opinfo, opn, XC(opinfo & OPCLSMASK));
+ debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
/* execute inevitable things */
if (opinfo & OF_RES1)
@@ -2387,6 +2385,7 @@ static var *evaluate(node *op, var *res)
debug_printf_eval("L_d:%f\n", L_d);
}
+ debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK));
switch (XC(opinfo & OPCLSMASK)) {
/* -- iterative node type -- */
@@ -2642,8 +2641,6 @@ static var *evaluate(node *op, var *res)
/* simple builtins */
case XC( OC_FBLTIN ): {
- int i;
- rstream *rsm;
double R_d = R_d; /* for compiler */
switch (opn) {
@@ -2709,26 +2706,37 @@ static var *evaluate(node *op, var *res)
if (!op1) {
fflush(stdout);
} else if (L.s && *L.s) {
- rsm = newfile(L.s);
+ rstream *rsm = newfile(L.s);
fflush(rsm->F);
} else {
fflush_all();
}
break;
- case F_cl:
- i = 0;
+ case F_cl: {
+ rstream *rsm;
+ int err = 0;
rsm = (rstream *)hash_search(fdhash, L.s);
+ debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm);
if (rsm) {
- i = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
+ debug_printf_eval("OC_FBLTIN F_cl "
+ "rsm->is_pipe:%d, ->F:%p\n",
+ rsm->is_pipe, rsm->F);
+ /* Can be NULL if open failed. Example:
+ * getline line <"doesnt_exist";
+ * close("doesnt_exist"); <--- here rsm->F is NULL
+ */
+ if (rsm->F)
+ err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
free(rsm->buffer);
hash_remove(fdhash, L.s);
}
- if (i != 0)
+ if (err)
setvar_i(intvar[ERRNO], errno);
- R_d = (double)i;
+ R_d = (double)err;
break;
}
+ } /* switch */
setvar_i(res, R_d);
break;
}
@@ -2877,6 +2885,7 @@ static var *evaluate(node *op, var *res)
} /* while (op) */
nvfree(v1);
+ debug_printf_eval("returning from %s(): %p\n", __func__, res);
return res;
#undef fnargs
#undef seed
@@ -2919,18 +2928,19 @@ static int is_assignment(const char *expr)
{
char *exprc, *s, *s0, *s1;
- exprc = xstrdup(expr);
- if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
- free(exprc);
+ if (!isalnum_(*expr) || (s0 = strchr(expr, '=')) == NULL) {
return FALSE;
}
+ exprc = xstrdup(expr);
+ s0 = exprc + (s0 - expr);
*s++ = '\0';
- s0 = s1 = s;
+
+ s = s1 = s0;
while (*s)
*s1++ = nextchar(&s);
-
*s1 = '\0';
+
setvar_u(newvar(exprc), s0);
free(exprc);
return TRUE;
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 56b11ca..0afe9b9 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -77,6 +77,12 @@ testing "awk string cast (bug 725)" \
testing "awk handles whitespace before array subscript" \
"awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" ""
+# GNU awk 3.1.5's "print ERRNO" prints "No such file or directory" instead of "2",
+# do we need to emulate that as well?
+testing "awk handles non-existing file correctly" \
+ "awk 'BEGIN { getline line <\"doesnt_exist\"; print ERRNO; ERRNO=0; close(\"doesnt_exist\"); print ERRNO; print \"Ok\" }'" \
+ "2\n0\nOk\n" "" ""
+
prg='
BEGIN {
u["a"]=1