gawk-diffs
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]