--- old/usr/src/cmd/awk/tran.c	2013-05-11 15:20:46.491556053 +0000
+++ new/usr/src/cmd/awk/tran.c	2013-05-11 15:20:46.504820115 +0000
@@ -24,16 +24,32 @@
  * 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"
 
@@ -47,6 +63,7 @@
 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 */
@@ -56,7 +73,7 @@
 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 */
@@ -66,31 +83,25 @@
 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,
@@ -99,6 +110,8 @@
 	    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);
@@ -120,25 +133,17 @@
 }
 
 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)) {
@@ -152,17 +157,19 @@
 }
 
 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),
@@ -176,7 +183,7 @@
 }
 
 Array *
-makesymtab(int n)
+makesymtab(int n)	/* make a new symbol table */
 {
 	Array *ap;
 	Cell **tp;
@@ -184,7 +191,7 @@
 	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;
@@ -194,7 +201,7 @@
 void
 freesymtab(Cell *ap)	/* free symbol table */
 {
-	Cell *cp, *next;
+	Cell *cp, *temp;
 	Array *tp;
 	int i;
 
@@ -205,20 +212,26 @@
 	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;
@@ -243,41 +256,41 @@
 }
 
 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);
@@ -292,8 +305,8 @@
 
 	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;
@@ -308,9 +321,9 @@
 }
 
 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);
@@ -322,163 +335,182 @@
 }
 
 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';
@@ -487,13 +519,11 @@
 					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);
 }
