diff options
-rw-r--r-- | ChangeLog | 32 | ||||
-rw-r--r-- | awk.h | 10 | ||||
-rw-r--r-- | builtin.c | 16 | ||||
-rw-r--r-- | eval.c | 9 | ||||
-rw-r--r-- | field.c | 135 | ||||
-rw-r--r-- | gawkapi.c | 57 | ||||
-rw-r--r-- | int_array.c | 4 | ||||
-rw-r--r-- | interpret.h | 6 | ||||
-rw-r--r-- | mpfr.c | 5 | ||||
-rw-r--r-- | node.c | 19 | ||||
-rw-r--r-- | test/ChangeLog | 7 | ||||
-rw-r--r-- | test/Makefile.am | 10 | ||||
-rw-r--r-- | test/Makefile.in | 20 | ||||
-rw-r--r-- | test/Maketests | 10 | ||||
-rw-r--r-- | test/apiterm.awk | 8 | ||||
-rw-r--r-- | test/apiterm.in | 1 | ||||
-rw-r--r-- | test/apiterm.ok | 3 | ||||
-rw-r--r-- | test/fldterm.awk | 10 | ||||
-rw-r--r-- | test/fldterm.in | 1 | ||||
-rw-r--r-- | test/fldterm.ok | 2 |
20 files changed, 233 insertions, 132 deletions
@@ -1,3 +1,35 @@ +2016-07-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awk.h: Restore previous comment about unterminated strings, since + I am removing the string termination patches from field.c + (free_api_string_copies): Declare new gawkapi function. + * builtin.c (do_mktime, do_system): Restore temporary string + termination to protect against unterminated field values. + (nondec2awknum): Remove comment about unnecessary termination. + * eval.c (posix_compare): Restore temporary string termination. + * field.c (databuf): Remove struct no longer needed. + (set_field): Remove memcpy for string termination, since we will support + unterminated field string values. + (rebuild_record): Ditto. Also no need to allocate space for terminated + string copies. + (allocate_databuf): Remove function, since memory management can again + be done inside set_record. + (set_record): Restore inline buffer management logic. + (reset_record): Remove calls to allocate_databuf, since we no longer + need space for making terminated copies of field strings. + * gawkapi.c (free_api_string_copies): New function to free strings + that we made to provide terminated copies to API functions. + (assign_string): New function to convert a string to an awk_value, + making sure to copy it if we need to terminate it. + (node_to_awk_value): Use assign_string to return string values with + NUL termination protection. + * int_array.c (is_integer): Restore temporary string termination. + * interpret.h (Op_push_i): Ditto. + (Op_ext_builtin): After external function returns, call + free_api_string_copies to free temporary string copies. + * mpfr.c (force_mpnum): Restore temporary string termination. + * node.c (r_force_number, get_ieee_magic_val): Ditto. + 2016-07-08 Arnold D. Robbins <arnold@skeeve.com> * dfa.c: Sync with GNU grep. @@ -475,7 +475,14 @@ typedef struct exp_node { #define re_cnt flags /* Node_val */ -/* Note that the string in stptr will always be NUL-terminated. */ +/* + * Note that the string in stptr may not be NUL-terminated, but it is + * guaranteed to have at least one extra byte that may be temporarily set + * to '\0'. This is helpful when calling functions such as strtod that require + * a NUL-terminated argument. In particular, field values $n for n > 0 and + * n < NF will not have a NUL terminator, since they point into the $0 buffer. + * All other strings are NUL-terminated. + */ #define stptr sub.val.sp #define stlen sub.val.slen #define valref sub.val.sref @@ -1497,6 +1504,7 @@ extern void update_ext_api(void); extern NODE *awk_value_to_node(const awk_value_t *); extern void run_ext_exit_handlers(int exitval); extern void print_ext_versions(void); +extern void free_api_string_copies(void); /* gawkmisc.c */ extern char *gawk_name(const char *filespec); @@ -2035,12 +2035,16 @@ do_mktime(int nargs) int month, day, hour, minute, second, count; int dst = -1; /* default is unknown */ time_t then_stamp; + char save; t1 = POP_SCALAR(); if (do_lint && (fixtype(t1)->flags & STRING) == 0) lintwarn(_("mktime: received non-string argument")); t1 = force_string(t1); + save = t1->stptr[t1->stlen]; + t1->stptr[t1->stlen] = '\0'; + count = sscanf(t1->stptr, "%ld %d %d %d %d %d %d", & year, & month, & day, & hour, & minute, & second, @@ -2054,6 +2058,7 @@ do_mktime(int nargs) || (month < 1 || month > 12) )) lintwarn(_("mktime: at least one of the values is out of the default range")); + t1->stptr[t1->stlen] = save; DEREF(t1); if (count < 6 @@ -2083,6 +2088,7 @@ do_system(int nargs) NODE *tmp; AWKNUM ret = 0; /* floating point on purpose, compat Unix awk */ char *cmd; + char save; int status; if (do_sandbox) @@ -2095,6 +2101,10 @@ do_system(int nargs) cmd = force_string(tmp)->stptr; if (cmd && *cmd) { + /* insure arg to system is zero-terminated */ + save = cmd[tmp->stlen]; + cmd[tmp->stlen] = '\0'; + os_restore_mode(fileno(stdin)); #ifdef SIGPIPE signal(SIGPIPE, SIG_DFL); @@ -2138,6 +2148,7 @@ do_system(int nargs) signal(SIGPIPE, SIG_IGN); #endif + cmd[tmp->stlen] = save; } DEREF(tmp); return make_number((AWKNUM) ret); @@ -3621,11 +3632,6 @@ nondec2awknum(char *str, size_t len, char **endptr) *endptr = str; } else { decimal: - /* - * Terminating is probably unnecessary, since the caller always - * passes a string ending with '\0' or white space, but it - * seems safest to leave this to avoid future problems. - */ save = str[len]; str[len] = '\0'; retval = strtod(str, endptr); @@ -493,8 +493,15 @@ static int posix_compare(NODE *s1, NODE *s2) { int ret = 0; + char save1, save2; size_t l = 0; + save1 = s1->stptr[s1->stlen]; + s1->stptr[s1->stlen] = '\0'; + + save2 = s2->stptr[s2->stlen]; + s2->stptr[s2->stlen] = '\0'; + if (gawk_mb_cur_max == 1) { if (strlen(s1->stptr) == s1->stlen && strlen(s2->stptr) == s2->stlen) ret = strcoll(s1->stptr, s2->stptr); @@ -556,6 +563,8 @@ posix_compare(NODE *s1, NODE *s2) } #endif + s1->stptr[s1->stlen] = save1; + s2->stptr[s2->stlen] = save2; return ret; } @@ -56,7 +56,6 @@ static void set_element(long num, char * str, long len, NODE *arr); static void grow_fields_arr(long num); static void set_field(long num, char *str, long len, NODE *dummy); static void purge_record(void); -static void allocate_databuf(size_t, bool); static char *parse_extent; /* marks where to restart parse of record */ static long parse_high_water = 0; /* field number that we have parsed so far */ @@ -117,15 +116,6 @@ grow_fields_arr(long num) nf_high_water = num; } -static struct { - char *p; /* buffer for $0 and field copies */ - size_t size; /* buffer size */ - char *space; /* - * Pointer to free space in databuf.p for making - * NUL-terminated copies of $1 thru $NF - */ -} databuf; - /* set_field --- set the value of a particular field */ /*ARGSUSED*/ @@ -140,18 +130,7 @@ set_field(long num, if (num > nf_high_water) grow_fields_arr(num); n = fields_arr[num]; - /* - * Make a NUL-terminated copy. It is tempting to do this only if - * str[len] != '\0', but the parse methods cannot be relied upon to - * avoid altering the contents of the record during parsing. For - * example, def_parse_field changes the final NUL to a space. In - * principle, the method could change other characters, so it does - * not seem safe to rely upon the value of str[len]. - */ - memcpy(databuf.space, str, len); - databuf.space[len] = '\0'; - n->stptr = databuf.space; - databuf.space += len+1; + n->stptr = str; n->stlen = len; n->flags = (STRCUR|STRING|MAYBE_NUM); /* do not set MALLOC */ } @@ -207,8 +186,6 @@ rebuild_record() } } tmp = make_str_node(ops, tlen, ALREADY_MALLOCED); - allocate_databuf(tlen, false); - databuf.space = databuf.p; /* * Since we are about to unref fields_arr[0], we want to find @@ -223,7 +200,7 @@ rebuild_record() * the new $0 buffer, although that's how previous versions did * it. It seems faster to leave the malloc'ed fields in place. */ - if ((r->flags & MALLOC) == 0) { + if (r->stlen > 0 && (r->flags & MALLOC) == 0) { NODE *n; getnode(n); @@ -246,16 +223,7 @@ rebuild_record() r->flags |= MALLOC; } - if (cops[n->stlen] == '\0') - /* should be the case for $NF */ - n->stptr = cops; - else { - /* make a NUL-terminated copy */ - memcpy(databuf.space, cops, n->stlen); - databuf.space[n->stlen] = '\0'; - n->stptr = databuf.space; - databuf.space += n->stlen+1; - } + n->stptr = cops; unref(r); fields_arr[i] = n; assert((n->flags & WSTRCUR) == 0); @@ -273,57 +241,6 @@ rebuild_record() field0_valid = true; } -static void -allocate_databuf(size_t reclen, bool need_zero) -{ - size_t needed; -#define INITIAL_SIZE 512 -#define MAX_SIZE ((size_t) ~0) /* maximally portable ... */ - - /* buffer management: */ - if (databuf.size == 0) { /* first time */ - emalloc(databuf.p, char *, INITIAL_SIZE, "set_record"); - databuf.size = INITIAL_SIZE; - - } - /* - * Make sure there's enough room. We need space for $0 plus a NUL - * terminator plus room for NUL-terminated copies of $1 through $NF. - * We use reclen as an upper bound for NF, assuming at least 1 byte - * for a field and its field separator (or fixed-width column). So our - * total requirement is reclen + 1 + 2*reclen -> 3*reclen + 1. - * It is tempting to skip the copy if the field value is already - * terminated with a NUL; this should normally be the case for $NF. - * Unfortunately, the parse methods often alter the string while - * parsing, typically changing the final NUL to a sentinel. So when - * set_field is called, the value of the character after the string - * in question may not be the actual value once parsing is complete. - * To be safe, it is prudent to copy all of the fields. - */ - needed = 2*reclen; /* for copying $1..$NF */ - if (need_zero) - needed += reclen + 1; /* for $0 plus '\0' */ -#ifdef GAWKDEBUG - /* malloc precise size so we can check for overruns with valgrind */ - if (needed == 0) - needed = 1; /* erealloc requires non-zero bytes */ - databuf.size = needed; - erealloc(databuf.p, char *, databuf.size, "set_record"); -#else - if (needed > databuf.size) { - do { - if (databuf.size > MAX_SIZE/2) - fatal(_("input record too large")); - databuf.size *= 2; - } while (needed > databuf.size); - erealloc(databuf.p, char *, databuf.size, "set_record"); - } -#endif - -#undef INITIAL_SIZE -#undef MAX_SIZE -} - /* * set_record: * setup $0, but defer parsing rest of line until reference is made to $(>0) @@ -338,19 +255,42 @@ void set_record(const char *buf, int cnt) { NODE *n; + static char *databuf; + static unsigned long databuf_size; +#define INITIAL_SIZE 512 +#define MAX_SIZE ((unsigned long) ~0) /* maximally portable ... */ purge_record(); - allocate_databuf(cnt, true); + /* buffer management: */ + if (databuf_size == 0) { /* first time */ + emalloc(databuf, char *, INITIAL_SIZE, "set_record"); + databuf_size = INITIAL_SIZE; + memset(databuf, '\0', INITIAL_SIZE); + + } + /* + * Make sure there's enough room. Since we sometimes need + * to place a sentinel at the end, we make sure + * databuf_size is > cnt after allocation. + */ + if (cnt >= databuf_size) { + do { + if (databuf_size > MAX_SIZE/2) + fatal(_("input record too large")); + databuf_size *= 2; + } while (cnt >= databuf_size); + erealloc(databuf, char *, databuf_size, "set_record"); + memset(databuf, '\0', databuf_size); + } /* copy the data */ - memcpy(databuf.p, buf, cnt); + memcpy(databuf, buf, cnt); /* * Add terminating '\0' so that C library routines * will know when to stop. */ - databuf.p[cnt] = '\0'; - databuf.space = databuf.p + cnt + 1; + databuf[cnt] = '\0'; /* manage field 0: */ #ifndef NDEBUG @@ -359,13 +299,16 @@ set_record(const char *buf, int cnt) #endif unref(fields_arr[0]); getnode(n); - n->stptr = databuf.p; + n->stptr = databuf; n->stlen = cnt; n->valref = 1; n->type = Node_val; n->stfmt = STFMT_UNUSED; n->flags = (STRING|STRCUR|MAYBE_NUM); /* do not set MALLOC */ fields_arr[0] = n; + +#undef INITIAL_SIZE +#undef MAX_SIZE } /* reset_record --- start over again with current $0 */ @@ -375,16 +318,6 @@ reset_record() { fields_arr[0] = force_string(fields_arr[0]); purge_record(); - if ((fields_arr[0]->flags & MALLOC) != 0) { - allocate_databuf(fields_arr[0]->stlen, false); - databuf.space = databuf.p; - } - else { - allocate_databuf(fields_arr[0]->stlen, true); - /* may have been realloced, so set stptr */ - fields_arr[0]->stptr = databuf.p; - databuf.space = databuf.p + fields_arr[0]->stlen + 1; - } } static void @@ -391,6 +391,52 @@ api_awk_atexit(awk_ext_id_t id, list_head = p; } +static struct { + char **strings; + size_t i, size; +} scopy; + +void +free_api_string_copies() +{ + size_t i; + + for (i = 0; i < scopy.i; i++) + free(scopy.strings[i]); + scopy.i = 0; +} + +/* return a node string with nul termination */ + +static inline void +assign_string(NODE *node, awk_value_t *val) +{ + val->val_type = AWK_STRING; + if (node->stptr[node->stlen] != '\0') { + /* + * This is an unterminated field string, so make a copy. + * This should happen only for $n where n > 0 and n < NF. + */ + char *s; + assert((node->flags & MALLOC) == 0); + if (scopy.i == scopy.size) { + /* expand list */ + if (scopy.size == 0) + scopy.size = 8; /* initial size */ + else + scopy.size *= 2; + erealloc(scopy.strings, char **, scopy.size * sizeof(char *), "assign_string"); + } + emalloc(s, char *, node->stlen + 1, "assign_string"); + memcpy(s, node->stptr, node->stlen); + s[node->stlen] = '\0'; + val->str_value.str = scopy.strings[scopy.i++] = s; + } + else + val->str_value.str = node->stptr; + val->str_value.len = node->stlen; +} + /* node_to_awk_value --- convert a node into a value for an extension */ static awk_bool_t @@ -435,12 +481,8 @@ node_to_awk_value(NODE *node, awk_value_t *val, awk_valtype_t wanted) break; case AWK_STRING: - val->val_type = AWK_STRING; - (void) force_string(node); - val->str_value.str = node->stptr; - val->str_value.len = node->stlen; - assert(val->str_value.str[val->str_value.len] == '\0'); + assign_string(node, val); ret = awk_true; break; @@ -466,10 +508,7 @@ node_to_awk_value(NODE *node, awk_value_t *val, awk_valtype_t wanted) val->num_value = get_number_d(node); ret = awk_true; } else if ((node->flags & STRING) != 0) { - val->val_type = AWK_STRING; - val->str_value.str = node->stptr; - val->str_value.len = node->stlen; - assert(val->str_value.str[val->str_value.len] == '\0'); + assign_string(node, val); ret = awk_true; } else val->val_type = AWK_UNDEFINED; diff --git a/int_array.c b/int_array.c index 937a91cf..9981fafe 100644 --- a/int_array.c +++ b/int_array.c @@ -128,6 +128,7 @@ is_integer(NODE *symbol, NODE *subs) /* must be a STRING */ char *cp = subs->stptr, *cpend, *ptr; + char save; size_t len = subs->stlen; if (len == 0 || (! isdigit((unsigned char) *cp) && *cp != '-')) @@ -151,9 +152,12 @@ is_integer(NODE *symbol, NODE *subs) } cpend = cp + len; + save = *cpend; + *cpend = '\0'; errno = 0; l = strtol(cp, & ptr, 10); + *cpend = save; if (errno != 0 || ptr != cpend) return NULL; diff --git a/interpret.h b/interpret.h index 9d7b423e..7d13f7f8 100644 --- a/interpret.h +++ b/interpret.h @@ -135,10 +135,13 @@ top: case Op_push_i: m = pc->memory; if (! do_traditional && (m->flags & INTLSTR) != 0) { - char *orig, *trans; + char *orig, *trans, save; + save = m->stptr[m->stlen]; + m->stptr[m->stlen] = '\0'; orig = m->stptr; trans = dgettext(TEXTDOMAIN, orig); + m->stptr[m->stlen] = save; m = make_string(trans, strlen(trans)); } else UPREF(m); @@ -959,6 +962,7 @@ arrayfor: if (t1->type == Node_val) DEREF(t1); } + free_api_string_copies(); PUSH(r); } break; @@ -275,6 +275,7 @@ static int force_mpnum(NODE *n, int do_nondec, int use_locale) { char *cp, *cpend, *ptr, *cp1; + char save; int tval, base = 10; if (n->stlen == 0) { @@ -291,6 +292,9 @@ force_mpnum(NODE *n, int do_nondec, int use_locale) return false; } + save = *cpend; + *cpend = '\0'; + if (*cp == '+' || *cp == '-') cp1 = cp + 1; else @@ -325,6 +329,7 @@ done: /* trailing space is OK for NUMBER */ while (ptr < cpend && isspace((unsigned char) *ptr)) ptr++; + *cpend = save; if (errno == 0 && ptr == cpend) return true; errno = 0; @@ -59,6 +59,7 @@ r_force_number(NODE *n) { char *cp; char *cpend; + char save; char *ptr; extern double strtod(); @@ -132,13 +133,10 @@ r_force_number(NODE *n) /* nondec2awknum() saves and restores the byte after the string itself */ n->numbr = nondec2awknum(cp, cpend - cp, &ptr); } else { - /* - * There is no need to set *cpend to '\0' because it is either - * pointing to white space or the '\0' at the end of the string. - * In either case, strtod should terminate on that character - * or earlier due to non-numeric characters. - */ + save = *cpend; + *cpend = '\0'; n->numbr = (AWKNUM) strtod((const char *) cp, &ptr); + *cpend = save; } if (errno == 0) { @@ -944,14 +942,13 @@ get_ieee_magic_val(char *val) static bool first = true; static AWKNUM inf; static AWKNUM nan; + char save; char *ptr; - /* - * There is no need to set val[4] to '\0' because it is either white - * space or the NUL character at the end of the string. Either way, - * strtod should terminate on that character. - */ + save = val[4]; + val[4] = '\0'; AWKNUM v = strtod(val, &ptr); + val[4] = save; if (val == ptr) { /* Older strtod implementations don't support inf or nan. */ if (first) { diff --git a/test/ChangeLog b/test/ChangeLog index 6821488c..c585120a 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,10 @@ +2016-07-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (apiterm, fldterm): New tests to make sure that we + are handling unterminated field string values properly. + * apiterm.awk, apiterm.in, apiterm.ok: New files. + * fldterm.awk, fldterm.in, fldterm.ok: New files. + 2016-07-06 Andrew J. Schorr <aschorr@telemetry-investments.com> * forcenum.awk: We no longer need to force the strnum conversion, diff --git a/test/Makefile.am b/test/Makefile.am index a13a01c9..f884ba34 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -47,6 +47,9 @@ EXTRA_DIST = \ anchgsub.awk \ anchgsub.in \ anchgsub.ok \ + apiterm.awk \ + apiterm.in \ + apiterm.ok \ argarray.awk \ argarray.in \ argarray.ok \ @@ -274,6 +277,9 @@ EXTRA_DIST = \ fldchgnf.awk \ fldchgnf.in \ fldchgnf.ok \ + fldterm.awk \ + fldterm.in \ + fldterm.ok \ fmtspcl-mpfr.ok \ fmtspcl.awk \ fmtspcl.tok \ @@ -1148,7 +1154,7 @@ BASIC_TESTS = \ concat3 concat4 convfmt \ datanonl defref delargv delarpm2 delarprm delfunc dfamb1 dfastress dynlj \ eofsplit exit2 exitval1 exitval2 exitval3 \ - fcall_exit fcall_exit2 fldchg fldchgnf fnamedat fnarray fnarray2 \ + fcall_exit fcall_exit2 fldchg fldchgnf fldterm fnamedat fnarray fnarray2 \ fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsnul1 fsrs fsspcoln \ fstabplus funsemnl funsmnam funstack \ getline getline2 getline3 getline4 getline5 getlnbuf getnr2tb getnr2tm \ @@ -1227,7 +1233,7 @@ LOCALE_CHARSET_TESTS = \ mbprintf1 mbprintf2 mbprintf3 mbprintf4 rebt8b2 rtlenmb sort1 sprintfc SHLIB_TESTS = \ - fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \ + apiterm fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \ ordchr ordchr2 readdir readfile readfile2 revout revtwoway rwarray testext time # List of the tests which should be run with --lint option: diff --git a/test/Makefile.in b/test/Makefile.in index 6db4c34c..45593f15 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -304,6 +304,9 @@ EXTRA_DIST = \ anchgsub.awk \ anchgsub.in \ anchgsub.ok \ + apiterm.awk \ + apiterm.in \ + apiterm.ok \ argarray.awk \ argarray.in \ argarray.ok \ @@ -531,6 +534,9 @@ EXTRA_DIST = \ fldchgnf.awk \ fldchgnf.in \ fldchgnf.ok \ + fldterm.awk \ + fldterm.in \ + fldterm.ok \ fmtspcl-mpfr.ok \ fmtspcl.awk \ fmtspcl.tok \ @@ -1404,7 +1410,7 @@ BASIC_TESTS = \ concat3 concat4 convfmt \ datanonl defref delargv delarpm2 delarprm delfunc dfamb1 dfastress dynlj \ eofsplit exit2 exitval1 exitval2 exitval3 \ - fcall_exit fcall_exit2 fldchg fldchgnf fnamedat fnarray fnarray2 \ + fcall_exit fcall_exit2 fldchg fldchgnf fldterm fnamedat fnarray fnarray2 \ fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsnul1 fsrs fsspcoln \ fstabplus funsemnl funsmnam funstack \ getline getline2 getline3 getline4 getline5 getlnbuf getnr2tb getnr2tm \ @@ -1480,7 +1486,7 @@ LOCALE_CHARSET_TESTS = \ mbprintf1 mbprintf2 mbprintf3 mbprintf4 rebt8b2 rtlenmb sort1 sprintfc SHLIB_TESTS = \ - fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \ + apiterm fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \ ordchr ordchr2 readdir readfile readfile2 revout revtwoway rwarray testext time @@ -3032,6 +3038,11 @@ fldchgnf: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +fldterm: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + fnamedat: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -4313,6 +4324,11 @@ sprintfc: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +apiterm: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + fnmatch: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/Maketests b/test/Maketests index 2aafd2bb..4c85c44a 100644 --- a/test/Maketests +++ b/test/Maketests @@ -275,6 +275,11 @@ fldchgnf: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +fldterm: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + fnamedat: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1556,6 +1561,11 @@ sprintfc: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +apiterm: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + fnmatch: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/apiterm.awk b/test/apiterm.awk new file mode 100644 index 00000000..95e4b120 --- /dev/null +++ b/test/apiterm.awk @@ -0,0 +1,8 @@ +@load "filefuncs" + +{ + print $1 + # check whether API terminates field strings properly + print chdir($1) + print ERRNO +} diff --git a/test/apiterm.in b/test/apiterm.in new file mode 100644 index 00000000..c4732514 --- /dev/null +++ b/test/apiterm.in @@ -0,0 +1 @@ +. fubar diff --git a/test/apiterm.ok b/test/apiterm.ok new file mode 100644 index 00000000..ef4043be --- /dev/null +++ b/test/apiterm.ok @@ -0,0 +1,3 @@ +. +0 + diff --git a/test/fldterm.awk b/test/fldterm.awk new file mode 100644 index 00000000..26fe01fb --- /dev/null +++ b/test/fldterm.awk @@ -0,0 +1,10 @@ +BEGIN { + # choose a field separator that is numeric, so we can test whether + # force_number properly handles unterminated numeric field strings + FS = "3" +} + +{ + print $1+0 + print $1 +} diff --git a/test/fldterm.in b/test/fldterm.in new file mode 100644 index 00000000..14a41cae --- /dev/null +++ b/test/fldterm.in @@ -0,0 +1 @@ +5.53apple diff --git a/test/fldterm.ok b/test/fldterm.ok new file mode 100644 index 00000000..ecd7600e --- /dev/null +++ b/test/fldterm.ok @@ -0,0 +1,2 @@ +5.5 +5.5 |