[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gawk-diffs] [SCM] gawk branch, feature/nocopy, created. gawk-4.1.0-1906
From: |
Andrew J. Schorr |
Subject: |
[gawk-diffs] [SCM] gawk branch, feature/nocopy, created. gawk-4.1.0-1906-gc86137f |
Date: |
Fri, 8 Jul 2016 19:28:12 +0000 (UTC) |
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".
The branch, feature/nocopy has been created
at c86137f472fdf876c2c223c8d99f673f477b7554 (commit)
- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=c86137f472fdf876c2c223c8d99f673f477b7554
commit c86137f472fdf876c2c223c8d99f673f477b7554
Author: Andrew J. Schorr <address@hidden>
Date: Fri Jul 8 15:26:00 2016 -0400
Optimization: support unterminated field strings inside gawk, but make
terminated copies for the API.
diff --git a/ChangeLog b/ChangeLog
index 41d0138..e32a255 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2016-07-08 Andrew J. Schorr <address@hidden>
+
+ * 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 <address@hidden>
* dfa.c: Sync with GNU grep.
diff --git a/awk.h b/awk.h
index 9e1fae1..91159a2 100644
--- a/awk.h
+++ b/awk.h
@@ -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);
diff --git a/builtin.c b/builtin.c
index 032f0ec..da3c252 100644
--- a/builtin.c
+++ b/builtin.c
@@ -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);
diff --git a/eval.c b/eval.c
index cfb1d1e..675422e 100644
--- a/eval.c
+++ b/eval.c
@@ -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;
}
diff --git a/field.c b/field.c
index 3307ace..1b3751d 100644
--- a/field.c
+++ b/field.c
@@ -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
diff --git a/gawkapi.c b/gawkapi.c
index afefa4f..97825a3 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -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 937a91c..9981faf 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 9d7b423..7d13f7f 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;
diff --git a/mpfr.c b/mpfr.c
index b239e4b..cd929d4 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -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;
diff --git a/node.c b/node.c
index 37aa946..f40ccdc 100644
--- a/node.c
+++ b/node.c
@@ -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 6821488..c585120 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,10 @@
+2016-07-08 Andrew J. Schorr <address@hidden>
+
+ * 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 <address@hidden>
* forcenum.awk: We no longer need to force the strnum conversion,
diff --git a/test/Makefile.am b/test/Makefile.am
index a13a01c..f884ba3 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 6db4c34..45593f1 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 address@hidden <
"$(srcdir)"/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/address@hidden _$@ && rm -f _$@
+fldterm:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f address@hidden <
"$(srcdir)"/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/address@hidden _$@ && rm -f _$@
+
fnamedat:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f address@hidden <
"$(srcdir)"/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -4313,6 +4324,11 @@ sprintfc:
@AWKPATH="$(srcdir)" $(AWK) -f address@hidden <
"$(srcdir)"/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/address@hidden _$@ && rm -f _$@
+apiterm:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f address@hidden <
"$(srcdir)"/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/address@hidden _$@ && rm -f _$@
+
fnmatch:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
diff --git a/test/Maketests b/test/Maketests
index 2aafd2b..4c85c44 100644
--- a/test/Maketests
+++ b/test/Maketests
@@ -275,6 +275,11 @@ fldchgnf:
@AWKPATH="$(srcdir)" $(AWK) -f address@hidden <
"$(srcdir)"/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/address@hidden _$@ && rm -f _$@
+fldterm:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f address@hidden <
"$(srcdir)"/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/address@hidden _$@ && rm -f _$@
+
fnamedat:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f address@hidden <
"$(srcdir)"/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1556,6 +1561,11 @@ sprintfc:
@AWKPATH="$(srcdir)" $(AWK) -f address@hidden <
"$(srcdir)"/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/address@hidden _$@ && rm -f _$@
+apiterm:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f address@hidden <
"$(srcdir)"/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/address@hidden _$@ && rm -f _$@
+
fnmatch:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
diff --git a/test/apiterm.awk b/test/apiterm.awk
new file mode 100644
index 0000000..95e4b12
--- /dev/null
+++ b/test/apiterm.awk
@@ -0,0 +1,8 @@
address@hidden "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 0000000..c473251
--- /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 0000000..ef4043b
--- /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 0000000..26fe01f
--- /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 0000000..14a41ca
--- /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 0000000..ecd7600
--- /dev/null
+++ b/test/fldterm.ok
@@ -0,0 +1,2 @@
+5.5
+5.5
-----------------------------------------------------------------------
hooks/post-receive
--
gawk
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gawk-diffs] [SCM] gawk branch, feature/nocopy, created. gawk-4.1.0-1906-gc86137f,
Andrew J. Schorr <=