Print this page
3731 Update nawk to version 20121220

@@ -22,20 +22,36 @@
 /*
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/*        All Rights Reserved   */
-
-#pragma ident   "%Z%%M% %I%     %E% SMI"
+/*
+ * Copyright (C) Lucent Technologies 1997
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and this
+ * permission notice and warranty disclaimer appear in supporting
+ * documentation, and that the name Lucent Technologies or any of
+ * its entities not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.
+ *
+ * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
 
 #define DEBUG
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
+#include <math.h>
 #include "awk.h"
 #include "y.tab.h"
 
 #define FULLTAB 2       /* rehash when table gets this x full */
 #define GROWTAB 4       /* grow table by this factor */

@@ -45,62 +61,59 @@
 uchar   **FS;           /* initial field sep */
 uchar   **RS;           /* initial record sep */
 uchar   **OFS;          /* output field sep */
 uchar   **ORS;          /* output record sep */
 uchar   **OFMT;         /* output format for numbers */
+uchar   **CONVFMT;      /* format for conversions in getsval */
 Awkfloat *NF;           /* number of fields in current record */
 Awkfloat *NR;           /* number of current record */
 Awkfloat *FNR;          /* number of current record in current file */
 uchar   **FILENAME;     /* current filename argument */
 Awkfloat *ARGC;         /* number of arguments from command line */
 uchar   **SUBSEP;       /* subscript separator for a[i,j,k]; default \034 */
 Awkfloat *RSTART;       /* start of re matched with ~; origin 1 (!) */
 Awkfloat *RLENGTH;      /* length of same */
 
-Cell    *recloc;        /* location of record */
+Cell    *fsloc;         /* FS */
 Cell    *nrloc;         /* NR */
 Cell    *nfloc;         /* NF */
 Cell    *fnrloc;        /* FNR */
 Array   *ARGVtab;       /* symbol table containing ARGV[...] */
 Array   *ENVtab;        /* symbol table containing ENVIRON[...] */
 Cell    *rstartloc;     /* RSTART */
 Cell    *rlengthloc;    /* RLENGTH */
 Cell    *symtabloc;     /* SYMTAB */
 
-Cell    *nullloc;
+Cell    *nullloc;       /* a guaranteed empty cell */
 Node    *nullnode;      /* zero&null, converted into a node for comparisons */
+Cell    *literal0;
 
 static  void    rehash(Array *);
 
 void
-syminit(void)
+syminit(void)           /* initialize symbol table with builtin vars */
 {
-        init_buf(&record, &record_size, LINE_INCR);
-
-        /* initialize $0 */
-        recloc = getfld(0);
-        recloc->nval = (uchar *)"$0";
-        recloc->sval = record;
-        recloc->tval = REC|STR|DONTFREE;
-
-        symtab = makesymtab(NSYMTAB);
-        (void) setsymtab((uchar *)"0", (uchar *)"0", 0.0,
+        literal0 = setsymtab((uchar *)"0", (uchar *)"0", 0.0,
             NUM|STR|CON|DONTFREE, symtab);
         /* this is used for if(x)... tests: */
         nullloc = setsymtab((uchar *)"$zero&null", (uchar *)"", 0.0,
             NUM|STR|CON|DONTFREE, symtab);
-        nullnode = valtonode(nullloc, CCON);
-        FS = &setsymtab((uchar *)"FS", (uchar *)" ", 0.0,
-            STR|DONTFREE, symtab)->sval;
+        nullnode = celltonode(nullloc, CCON);
+
+        fsloc = setsymtab((uchar *)"FS", (uchar *)" ", 0.0,
+            STR|DONTFREE, symtab);
+        FS = &fsloc->sval;
         RS = &setsymtab((uchar *)"RS", (uchar *)"\n", 0.0,
             STR|DONTFREE, symtab)->sval;
         OFS = &setsymtab((uchar *)"OFS", (uchar *)" ", 0.0,
             STR|DONTFREE, symtab)->sval;
         ORS = &setsymtab((uchar *)"ORS", (uchar *)"\n", 0.0,
             STR|DONTFREE, symtab)->sval;
         OFMT = &setsymtab((uchar *)"OFMT", (uchar *)"%.6g", 0.0,
             STR|DONTFREE, symtab)->sval;
+        CONVFMT = &setsymtab((uchar *)"CONVFMT", (uchar *)"%.6g", 0.0,
+            STR|DONTFREE, symtab)->sval;
         FILENAME = &setsymtab((uchar *)"FILENAME", (uchar *)"-", 0.0,
             STR|DONTFREE, symtab)->sval;
         nfloc = setsymtab((uchar *)"NF", (uchar *)"", 0.0, NUM, symtab);
         NF = &nfloc->fval;
         nrloc = setsymtab((uchar *)"NR", (uchar *)"", 0.0, NUM, symtab);

@@ -118,29 +131,21 @@
         symtabloc = setsymtab((uchar *)"SYMTAB", (uchar *)"", 0.0, ARR, symtab);
         symtabloc->sval = (uchar *)symtab;
 }
 
 void
-arginit(int ac, uchar *av[])
+arginit(int ac, uchar *av[]) /* set up ARGV and ARGC */
 {
         Cell *cp;
         int i;
-        uchar temp[11];
+        uchar temp[50];
 
-        /* first make FILENAME first real argument */
-        for (i = 1; i < ac; i++) {
-                if (!isclvar(av[i])) {
-                        (void) setsval(lookup((uchar *)"FILENAME", symtab),
-                            av[i]);
-                        break;
-                }
-        }
         ARGC = &setsymtab((uchar *)"ARGC", (uchar *)"", (Awkfloat)ac,
             NUM, symtab)->fval;
         cp = setsymtab((uchar *)"ARGV", (uchar *)"", 0.0, ARR, symtab);
         ARGVtab = makesymtab(NSYMTAB);  /* could be (int) ARGC as well */
-        cp->sval = (uchar *) ARGVtab;
+        cp->sval = (uchar *)ARGVtab;
         for (i = 0; i < ac; i++) {
                 (void) sprintf((char *)temp, "%d", i);
                 if (is_number(*av)) {
                         (void) setsymtab(temp, *av, atof((const char *)*av),
                             STR|NUM, ARGVtab);

@@ -150,21 +155,23 @@
                 av++;
         }
 }
 
 void
-envinit(uchar *envp[])
+envinit(uchar **envp)           /* set up ENVIRON variable */
 {
         Cell *cp;
         uchar *p;
 
         cp = setsymtab((uchar *)"ENVIRON", (uchar *)"", 0.0, ARR, symtab);
         ENVtab = makesymtab(NSYMTAB);
-        cp->sval = (uchar *) ENVtab;
+        cp->sval = (uchar *)ENVtab;
         for (; *envp; envp++) {
                 if ((p = (uchar *)strchr((char *)*envp, '=')) == NULL)
                         continue;
+                if (p == *envp) /* no left hand side name in env string */
+                        continue;
                 *p++ = 0;       /* split into two strings at = */
                 if (is_number(p)) {
                         (void) setsymtab(*envp, p, atof((const char *)p),
                             STR|NUM, ENVtab);
                 } else {

@@ -174,53 +181,59 @@
                 p[-1] = '=';
         }
 }
 
 Array *
-makesymtab(int n)
+makesymtab(int n)       /* make a new symbol table */
 {
         Array *ap;
         Cell **tp;
 
         ap = (Array *)malloc(sizeof (Array));
         tp = (Cell **)calloc(n, sizeof (Cell *));
         if (ap == NULL || tp == NULL)
-                ERROR "out of space in makesymtab" FATAL;
+                FATAL("out of space in makesymtab");
         ap->nelem = 0;
         ap->size = n;
         ap->tab = tp;
         return (ap);
 }
 
 void
 freesymtab(Cell *ap)    /* free symbol table */
 {
-        Cell *cp, *next;
+        Cell *cp, *temp;
         Array *tp;
         int i;
 
         if (!isarr(ap))
                 return;
         /*LINTED align*/
         tp = (Array *)ap->sval;
         if (tp == NULL)
                 return;
         for (i = 0; i < tp->size; i++) {
-                for (cp = tp->tab[i]; cp != NULL; cp = next) {
-                        next = cp->cnext;
+                for (cp = tp->tab[i]; cp != NULL; cp = temp) {
                         xfree(cp->nval);
                         if (freeable(cp))
                                 xfree(cp->sval);
+                        /* avoids freeing then using */
+                        temp = cp->cnext;
                         free(cp);
+                        tp->nelem--;
                 }
+                tp->tab[i] = 0;
         }
+        if (tp->nelem != 0)
+                WARNING("can't happen: inconsistent element count freeing %s",
+                    ap->nval);
         free(tp->tab);
         free(tp);
 }
 
 void
-freeelem(Cell *ap, uchar *s)            /* free elem s from ap (i.e., ap["s"] */
+freeelem(Cell *ap, const uchar *s) /* free elem s from ap (i.e., ap["s"] */
 {
         Array *tp;
         Cell *p, *prev = NULL;
         int h;
 

@@ -241,45 +254,45 @@
                         return;
                 }
 }
 
 Cell *
-setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned int t, Array *tp)
+setsymtab(const uchar *n, const uchar *s, Awkfloat f, unsigned int t,
+    Array *tp)
 {
-        register int h;
-        register Cell *p;
+        int h;
+        Cell *p;
 
         if (n != NULL && (p = lookup(n, tp)) != NULL) {
-                dprintf(("setsymtab found %p: n=%s", (void *)p, p->nval));
-                dprintf((" s=\"%s\" f=%g t=%p\n",
-                    p->sval, p->fval, (void *)p->tval));
+                dprintf(("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
+                    (void *)p, p->nval, p->sval, p->fval, p->tval));
                 return (p);
         }
         p = (Cell *)malloc(sizeof (Cell));
         if (p == NULL)
-                ERROR "symbol table overflow at %s", n FATAL;
+                FATAL("out of space for symbol table at %s", n);
         p->nval = tostring(n);
         p->sval = s ? tostring(s) : tostring((uchar *)"");
         p->fval = f;
         p->tval = t;
-        p->csub = 0;
-
+        p->csub = CUNK;
+        p->ctype = OCELL;
         tp->nelem++;
         if (tp->nelem > FULLTAB * tp->size)
                 rehash(tp);
         h = hash(n, tp->size);
         p->cnext = tp->tab[h];
         tp->tab[h] = p;
-        dprintf(("setsymtab set %p: n=%s", (void *)p, p->nval));
-        dprintf((" s=\"%s\" f=%g t=%p\n", p->sval, p->fval, (void *)p->tval));
+        dprintf(("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
+            (void *)p, p->nval, p->sval, p->fval, p->tval));
         return (p);
 }
 
 int
-hash(uchar *s, int n)   /* form hash value for string s */
+hash(const uchar *s, int n)     /* form hash value for string s */
 {
-        register unsigned hashval;
+        unsigned hashval;
 
         for (hashval = 0; *s != '\0'; s++)
                 hashval = (*s + 31 * hashval);
         return (hashval % n);
 }

@@ -290,12 +303,12 @@
         int i, nh, nsz;
         Cell *cp, *op, **np;
 
         nsz = GROWTAB * tp->size;
         np = (Cell **)calloc(nsz, sizeof (Cell *));
-        if (np == NULL)
-                ERROR "out of space in rehash" FATAL;
+        if (np == NULL)         /* can't do it, but can keep running. */
+                return;         /* someone else will run out later. */
         for (i = 0; i < tp->size; i++) {
                 for (cp = tp->tab[i]; cp; cp = op) {
                         op = cp->cnext;
                         nh = hash(cp->nval, nsz);
                         cp->cnext = np[nh];

@@ -306,13 +319,13 @@
         tp->tab = np;
         tp->size = nsz;
 }
 
 Cell *
-lookup(uchar *s, Array *tp)     /* look for s in tp */
+lookup(const uchar *s, Array *tp)       /* look for s in tp */
 {
-        register Cell *p;
+        Cell *p;
         int h;
 
         h = hash(s, tp->size);
         for (p = tp->tab[h]; p != NULL; p = p->cnext) {
                 if (strcmp((char *)s, (char *)p->nval) == 0)

@@ -320,180 +333,197 @@
         }
         return (NULL);                  /* not found */
 }
 
 Awkfloat
-setfval(Cell *vp, Awkfloat f)
+setfval(Cell *vp, Awkfloat f)   /* set float val of a Cell */
 {
-        int     i;
+        int fldno;
 
         if ((vp->tval & (NUM | STR)) == 0)
                 funnyvar(vp, "assign to");
-        if (vp->tval & FLD) {
+        if (isfld(vp)) {
                 donerec = 0;    /* mark $0 invalid */
-                i = fldidx(vp);
-                if (i > *NF)
-                        newfld(i);
-                dprintf(("setting field %d to %g\n", i, f));
-        } else if (vp->tval & REC) {
+                fldno = atoi((char *)vp->nval);
+                if (fldno > *NF)
+                        newfld(fldno);
+                dprintf(("setting field %d to %g\n", fldno, f));
+        } else if (isrec(vp)) {
                 donefld = 0;    /* mark $1... invalid */
                 donerec = 1;
         }
+        if (freeable(vp))
+                xfree(vp->sval); /* free any previous string */
         vp->tval &= ~STR;       /* mark string invalid */
         vp->tval |= NUM;        /* mark number ok */
-        dprintf(("setfval %p: %s = %g, t=%p\n", (void *)vp,
-            vp->nval ? vp->nval : (unsigned char *)"NULL",
-            f, (void *)vp->tval));
+        if (f == -0)  /* who would have thought this possible? */
+                f = 0;
+        dprintf(("setfval %p: %s = %g, t=%o\n", (void *)vp,
+            vp->nval, f, vp->tval));
         return (vp->fval = f);
 }
 
 void
 funnyvar(Cell *vp, char *rw)
 {
-        if (vp->tval & ARR)
-                ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
+        if (isarr(vp))
+                FATAL("can't %s %s; it's an array name.", rw, vp->nval);
         if (vp->tval & FCN)
-                ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
-        ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
-            vp, vp->nval, vp->sval, vp->fval, vp->tval CONT;
+                FATAL("can't %s %s; it's a function.", rw, vp->nval);
+        WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
+            vp, vp->nval, vp->sval, vp->fval, vp->tval);
 }
 
 uchar *
-setsval(Cell *vp, uchar *s)
+setsval(Cell *vp, const uchar *s)       /* set string val of a Cell */
 {
-        int     i;
+        uchar *t;
+        int fldno;
 
+        dprintf(("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
+            (void*)vp, vp->nval, s, vp->tval, donerec, donefld));
         if ((vp->tval & (NUM | STR)) == 0)
                 funnyvar(vp, "assign to");
-        if (vp->tval & FLD) {
+        if (isfld(vp)) {
                 donerec = 0;    /* mark $0 invalid */
-                i = fldidx(vp);
-                if (i > *NF)
-                        newfld(i);
-                dprintf(("setting field %d to %s\n", i, s));
-        } else if (vp->tval & REC) {
+                fldno = atoi((const char *)vp->nval);
+                if (fldno > *NF)
+                        newfld(fldno);
+                dprintf(("setting field %d to %s (%p)\n", fldno, s, (void *)s));
+        } else if (isrec(vp)) {
                 donefld = 0;    /* mark $1... invalid */
                 donerec = 1;
         }
-        vp->tval &= ~NUM;
-        vp->tval |= STR;
+        t = tostring(s);        /* in case it's self-assign */
         if (freeable(vp))
                 xfree(vp->sval);
+        vp->tval &= ~NUM;
+        vp->tval |= STR;
         vp->tval &= ~DONTFREE;
-        dprintf(("setsval %p: %s = \"%s\", t=%p\n",
-            (void *)vp,
-            vp->nval ? (char *)vp->nval : "",
-            s,
-            (void *)(vp->tval ? (char *)vp->tval : "")));
-        return (vp->sval = tostring(s));
+        dprintf(("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
+            (void *)vp, vp->nval, t, (void *)t, vp->tval, donerec, donefld));
+        return (vp->sval = t);
 }
 
 Awkfloat
-r_getfval(Cell *vp)
+getfval(Cell *vp)       /* get float val of a Cell */
 {
         if ((vp->tval & (NUM | STR)) == 0)
                 funnyvar(vp, "read value of");
-        if ((vp->tval & FLD) && donefld == 0)
+        if (isfld(vp) && donefld == 0)
                 fldbld();
-        else if ((vp->tval & REC) && donerec == 0)
+        else if (isrec(vp) && donerec == 0)
                 recbld();
         if (!isnum(vp)) {       /* not a number */
                 vp->fval = atof((const char *)vp->sval);        /* best guess */
-                if (is_number(vp->sval) && !(vp->tval&CON))
+                if (is_number(vp->sval) && !(vp->tval & CON))
                         vp->tval |= NUM;        /* make NUM only sparingly */
         }
-        dprintf(("getfval %p: %s = %g, t=%p\n",
-            (void *)vp, vp->nval, vp->fval, (void *)vp->tval));
+        dprintf(("getfval %p: %s = %g, t=%o\n",
+            (void *)vp, vp->nval, vp->fval, vp->tval));
         return (vp->fval);
 }
 
-uchar *
-r_getsval(Cell *vp)
+static uchar *
+get_str_val(Cell *vp, uchar **fmt)      /* get string val of a Cell */
 {
-        uchar s[256];
+        uchar s[100];   /* BUG: unchecked */
+        double dtemp;
 
         if ((vp->tval & (NUM | STR)) == 0)
                 funnyvar(vp, "read value of");
-        if ((vp->tval & FLD) && donefld == 0)
+        if (isfld(vp) && donefld == 0)
                 fldbld();
-        else if ((vp->tval & REC) && donerec == 0)
+        else if (isrec(vp) && donerec == 0)
                 recbld();
-        if ((vp->tval & STR) == 0) {
-                if (!(vp->tval&DONTFREE))
+        if (isstr(vp) == 0) {
+                if (freeable(vp))
                         xfree(vp->sval);
-                if ((long long)vp->fval == vp->fval) {
+                /* it's integral */
+                if (modf((long long)vp->fval, &dtemp) == 0) {
                         (void) snprintf((char *)s, sizeof (s),
-                            "%.20g", vp->fval);
+                            "%.30g", vp->fval);
                 } else {
                         /*LINTED*/
                         (void) snprintf((char *)s, sizeof (s),
-                            (char *)*OFMT, vp->fval);
+                            (char *)*fmt, vp->fval);
                 }
                 vp->sval = tostring(s);
                 vp->tval &= ~DONTFREE;
                 vp->tval |= STR;
         }
-        dprintf(("getsval %p: %s = \"%s\", t=%p\n",
-            (void *)vp,
-            vp->nval ? (char *)vp->nval : "",
-            vp->sval ? (char *)vp->sval : "",
-            (void *)vp->tval));
+        dprintf(("getsval %p: %s = \"%s (%p)\", t=%o\n",
+            (void *)vp, vp->nval, vp->sval, (void *)vp->sval, vp->tval));
         return (vp->sval);
 }
 
 uchar *
-tostring(uchar *s)
+getsval(Cell *vp)       /* get string val of a Cell */
 {
-        register uchar *p;
+        return (get_str_val(vp, CONVFMT));
+}
+
+uchar *
+getpssval(Cell *vp)     /* get string val of a Cell for print */
+{
+        return (get_str_val(vp, OFMT));
+}
+
+uchar *
+tostring(const uchar *s)        /* make a copy of string s */
+{
+        uchar *p;
 
         p = (uchar *)malloc(strlen((char *)s)+1);
         if (p == NULL)
-                ERROR "out of space in tostring on %s", s FATAL;
+                FATAL("out of space in tostring on %s", s);
         (void) strcpy((char *)p, (char *)s);
         return (p);
 }
 
 uchar *
-qstring(uchar *s, int delim)    /* collect string up to delim */
+qstring(const uchar *is, int delim)     /* collect string up to delim */
 {
-        uchar *cbuf, *ret;
+        const uchar *os = is;
         int c, n;
-        size_t  cbufsz, cnt;
-
-        init_buf(&cbuf, &cbufsz, LINE_INCR);
+        uchar *s = (uchar *)is;
+        uchar *buf, *bp;
 
-        for (cnt = 0; (c = *s) != delim; s++) {
+        if ((buf = (uchar *)malloc(strlen((char *)is)+3)) == NULL)
+                FATAL("out of space in qstring(%s)", s);
+        for (bp = buf; (c = *s) != delim; s++) {
                 if (c == '\n') {
-                        ERROR "newline in string %.10s...", cbuf SYNTAX;
+                        SYNTAX("newline in string %.20s...", os);
                 } else if (c != '\\') {
-                        expand_buf(&cbuf, &cbufsz, cnt);
-                        cbuf[cnt++] = c;
+                        *bp++ = c;
                 } else {        /* \something */
-                        expand_buf(&cbuf, &cbufsz, cnt);
-                        switch (c = *++s) {
-                        case '\\':      cbuf[cnt++] = '\\'; break;
-                        case 'n':       cbuf[cnt++] = '\n'; break;
-                        case 't':       cbuf[cnt++] = '\t'; break;
-                        case 'b':       cbuf[cnt++] = '\b'; break;
-                        case 'f':       cbuf[cnt++] = '\f'; break;
-                        case 'r':       cbuf[cnt++] = '\r'; break;
+                        c = *++s;
+                        if (c == 0) {   /* \ at end */
+                                *bp++ = '\\';
+                                break;  /* for loop */
+                        }
+                        switch (c) {
+                        case '\\':      *bp++ = '\\'; break;
+                        case 'n':       *bp++ = '\n'; break;
+                        case 't':       *bp++ = '\t'; break;
+                        case 'b':       *bp++ = '\b'; break;
+                        case 'f':       *bp++ = '\f'; break;
+                        case 'r':       *bp++ = '\r'; break;
                         default:
                                 if (!isdigit(c)) {
-                                        cbuf[cnt++] = c;
+                                        *bp++ = c;
                                         break;
                                 }
                                 n = c - '0';
                                 if (isdigit(s[1])) {
                                         n = 8 * n + *++s - '0';
                                         if (isdigit(s[1]))
                                                 n = 8 * n + *++s - '0';
                                 }
-                                cbuf[cnt++] = n;
+                                *bp++ = n;
                                 break;
                         }
                 }
         }
-        cbuf[cnt] = '\0';
-        ret = tostring(cbuf);
-        free(cbuf);
-        return (ret);
+        *bp++ = 0;
+        return (buf);
 }