--- old/usr/src/cmd/awk/Makefile	2013-05-11 15:20:42.052930400 +0000
+++ new/usr/src/cmd/awk/Makefile	2013-05-11 15:20:42.062364742 +0000
@@ -29,19 +29,13 @@
 
 PROG= nawk
 
-OBJ1= b.o lib.o main.o parse.o proctab.o run.o tran.o
-OBJ2= awk.g.o awk.lx.o
+OBJ1= b.o lex.o lib.o main.o parse.o proctab.o run.o tran.o
+OBJ2= awk.g.o
 OBJS= $(OBJ2) $(OBJ1)
 SRCS= $(OBJ1:%.o=%.c)
 
 include ../Makefile.cmd
 
-CERRWARN += -_gcc=-Wno-implicit-function-declaration
-CERRWARN += -_gcc=-Wno-unused-label
-CERRWARN += -_gcc=-Wno-parentheses
-CERRWARN += -_gcc=-Wno-unused-variable
-CERRWARN += -_gcc=-Wno-uninitialized
-
 #
 # Message catalog
 #
@@ -85,13 +79,13 @@
 	$(RM) $(OBJS) $(CLEANFILES)
 
 lint: awk.g.c lint_SRCS
+	$(LINT.c) awk.g.c $(LDLIBS)
+	$(LINT.c) maketab.c $(LDLIBS)
 
 awk.g.c + y.tab.h: awk.g.y
 
 awk.g.o: awk.g.c
 
-awk.lx.c: awk.lx.l
-
 proctab.o: proctab.c
 	$(COMPILE.c) proctab.c
 	$(POST_PROCESS_O)
--- old/usr/src/cmd/awk/awk.g.y	2013-05-11 15:20:42.459078744 +0000
+++ new/usr/src/cmd/awk/awk.g.y	2013-05-11 15:20:42.470468526 +0000
@@ -26,22 +26,42 @@
  * Use is subject to license terms.
  */
 
-/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
+/*
+ * 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.
+ */
 
 %{
-#ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 2.10	*/
 %}
 
 %{
 #include "awk.h"
 int yywrap(void) { return(1); }
-#ifndef	DEBUG
-#	define	PUTS(x)
-#endif
-Node	*beginloc = 0, *endloc = 0;
+
+Node	*beginloc = 0;
+Node	*endloc = 0;
 int	infunc	= 0;	/* = 1 if in arglist or body of func */
-uchar	*curfname = 0;
+int	inloop = 0;	/* = 1 if in while, for, do */
+uchar	*curfname = 0;	/* current function name */
 Node	*arglist = 0;	/* list of args for current function */
 static void	setfname(Cell *);
 static int	constnode(Node *);
@@ -61,25 +81,26 @@
 %token	<i>	NL ',' '{' '(' '|' ';' '/' ')' '}' '[' ']'
 %token	<i>	ARRAY
 %token	<i>	MATCH NOTMATCH MATCHOP
-%token	<i>	FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS
+%token	<i>	FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS EMPTYRE
 %token	<i>	AND BOR APPEND EQ GE GT LE LT NE IN
-%token	<i>	ARG BLTIN BREAK CLOSE CONTINUE DELETE DO EXIT FOR FUNC 
-%token	<i>	SUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT
+%token	<i>	ARG BLTIN BREAK CLOSE CONTINUE DELETE DO EXIT FOR FUNC
+%token	<i>	SUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NEXTFILE
 %token	<i>	ADD MINUS MULT DIVIDE MOD
 %token	<i>	ASSIGN ASGNOP ADDEQ SUBEQ MULTEQ DIVEQ MODEQ POWEQ
 %token	<i>	PRINT PRINTF SPRINTF
 %token	<p>	ELSE INTEST CONDEXPR
 %token	<i>	POSTINCR PREINCR POSTDECR PREDECR
-%token	<cp>	VAR IVAR VARNF CALL NUMBER STRING FIELD
+%token	<cp>	VAR IVAR VARNF CALL NUMBER STRING
 %token	<s>	REGEXPR
 
-%type	<p>	pas pattern ppattern plist pplist patlist prarg term
+%type	<p>	pas pattern ppattern plist pplist patlist prarg term re
 %type	<p>	pa_pat pa_stat pa_stats
 %type	<s>	reg_expr
 %type	<p>	simple_stmt opt_simple_stmt stmt stmtlist
 %type	<p>	var varname funcname varlist
-%type	<p>	for if while
-%type	<i>	pst opt_pst lbrace rparen comma nl opt_nl and bor
+%type	<p>	for if else while
+%type	<i>	do st
+%type	<i>	pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor
 %type	<i>	subop print
 
 %right	ASGNOP
@@ -89,7 +110,7 @@
 %left	AND
 %left	GETLINE
 %nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|'
-%left	ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FIELD FUNC 
+%left	ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC
 %left	GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER
 %left	PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR
 %left	REGEXPR VAR VARNF IVAR WHILE '('
@@ -107,7 +128,7 @@
 program:
 	  pas	{ if (errorflag==0)
 			winner = (Node *)stat3(PROGRAM, beginloc, $1, endloc); }
-	| error	{ yyclearin; bracecheck(); ERROR "bailing out" SYNTAX; }
+	| error	{ yyclearin; bracecheck(); SYNTAX("bailing out"); }
 	;
 
 and:
@@ -131,12 +152,12 @@
 	;
 
 for:
-	  FOR '(' opt_simple_stmt ';' pattern ';' opt_simple_stmt rparen stmt
-		{ $$ = stat4(FOR, $3, notnull($5), $7, $9); }
-	| FOR '(' opt_simple_stmt ';'  ';' opt_simple_stmt rparen stmt
-		{ $$ = stat4(FOR, $3, NIL, $6, $8); }
-	| FOR '(' varname IN varname rparen stmt
-		{ $$ = stat3(IN, $3, makearr($5), $7); }
+	  FOR '(' opt_simple_stmt ';' opt_nl pattern ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt
+		{ --inloop; $$ = stat4(FOR, $3, notnull($6), $9, $12); }
+	| FOR '(' opt_simple_stmt ';'  ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt
+		{ --inloop; $$ = stat4(FOR, $3, NIL, $7, $10); }
+	| FOR '(' varname IN varname rparen {inloop++;} stmt
+		{ --inloop; $$ = stat3(IN, $3, makearr($5), $8); }
 	;
 
 funcname:
@@ -184,8 +205,8 @@
 pa_stat:
 	  pa_pat			{ $$ = stat2(PASTAT, $1, stat2(PRINT, rectonode(), NIL)); }
 	| pa_pat lbrace stmtlist '}'	{ $$ = stat2(PASTAT, $1, $3); }
-	| pa_pat ',' pa_pat		{ $$ = pa2stat($1, $3, stat2(PRINT, rectonode(), NIL)); }
-	| pa_pat ',' pa_pat lbrace stmtlist '}'	{ $$ = pa2stat($1, $3, $5); }
+	| pa_pat ',' opt_nl pa_pat		{ $$ = pa2stat($1, $4, stat2(PRINT, rectonode(), NIL)); }
+	| pa_pat ',' opt_nl pa_pat lbrace stmtlist '}'	{ $$ = pa2stat($1, $4, $6); }
 	| lbrace stmtlist '}'		{ $$ = stat2(PASTAT, NIL, $2); }
 	| XBEGIN lbrace stmtlist '}'
 		{ beginloc = linkum(beginloc, $3); $$ = 0; }
@@ -202,7 +223,7 @@
 
 patlist:
 	  pattern
-	| patlist comma pattern	{ $$ = linkum($1, $3); }
+	| patlist comma pattern		{ $$ = linkum($1, $3); }
 	;
 
 ppattern:
@@ -213,8 +234,6 @@
 		{ $$ = op2(BOR, notnull($1), notnull($3)); }
 	| ppattern and ppattern %prec AND
 		{ $$ = op2(AND, notnull($1), notnull($3)); }
-	| NOT ppattern
-		{ $$ = op1(NOT, notnull($2)); }
 	| ppattern MATCHOP reg_expr	{ $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
 	| ppattern MATCHOP ppattern
 		{ if (constnode($3))
@@ -224,8 +243,7 @@
 	| ppattern IN varname		{ $$ = op2(INTEST, $1, makearr($3)); }
 	| '(' plist ')' IN varname	{ $$ = op2(INTEST, $2, makearr($5)); }
 	| ppattern term %prec CAT	{ $$ = op2(CAT, $1, $2); }
-	| reg_expr
-		{ $$ = op3(MATCH, NIL, rectonode(), (Node*)makedfa($1, 0)); }
+	| re
 	| term
 	;
 
@@ -237,8 +255,6 @@
 		{ $$ = op2(BOR, notnull($1), notnull($3)); }
 	| pattern and pattern %prec AND
 		{ $$ = op2(AND, notnull($1), notnull($3)); }
-	| NOT pattern
-		{ $$ = op1(NOT, op2(NE,$2,valtonode(lookup((uchar *)"$zero&null",symtab),CCON))); }
 	| pattern EQ pattern		{ $$ = op2($2, $1, $3); }
 	| pattern GE pattern		{ $$ = op2($2, $1, $3); }
 	| pattern GT pattern		{ $$ = op2($2, $1, $3); }
@@ -253,11 +269,14 @@
 			$$ = op3($2, (Node *)1, $1, $3); }
 	| pattern IN varname		{ $$ = op2(INTEST, $1, makearr($3)); }
 	| '(' plist ')' IN varname	{ $$ = op2(INTEST, $2, makearr($5)); }
-	| pattern '|' GETLINE var	{ $$ = op3(GETLINE, $4, (Node*)$2, $1); }
-	| pattern '|' GETLINE		{ $$ = op3(GETLINE, (Node*)0, (Node*)$2, $1); }
+	| pattern '|' GETLINE var	{
+			if (safe) SYNTAX("cmd | getline is unsafe");
+			else $$ = op3(GETLINE, $4, itonp($2), $1); }
+	| pattern '|' GETLINE		{
+			if (safe) SYNTAX("cmd | getline is unsafe");
+			else $$ = op3(GETLINE, (Node*)0, itonp($2), $1); }
 	| pattern term %prec CAT	{ $$ = op2(CAT, $1, $2); }
-	| reg_expr
-		{ $$ = op3(MATCH, NIL, rectonode(), (Node*)makedfa($1, 0)); }
+	| re
 	| term
 	;
 
@@ -288,6 +307,12 @@
 	  '}' | rbrace NL
 	;
 
+re:
+	   reg_expr
+		{ $$ = op3(MATCH, NIL, rectonode(), (Node*)makedfa($1, 0)); }
+	| NOT re	{ $$ = op1(NOT, notnull($2)); }
+	;
+
 reg_expr:
 	  '/' {startreg();} REGEXPR '/'		{ $$ = $3; }
 	;
@@ -297,26 +322,36 @@
 	;
 
 simple_stmt:
-	  print prarg '|' term		{ $$ = stat3($1, $2, (Node *) $3, $4); }
-	| print prarg APPEND term	{ $$ = stat3($1, $2, (Node *) $3, $4); }
-	| print prarg GT term		{ $$ = stat3($1, $2, (Node *) $3, $4); }
+	  print prarg '|' term		{
+			if (safe) SYNTAX("print | is unsafe");
+			else $$ = stat3($1, $2, itonp($3), $4); }
+	| print prarg APPEND term	{
+			if (safe) SYNTAX("print >> is unsafe");
+			else $$ = stat3($1, $2, itonp($3), $4); }
+	| print prarg GT term		{
+			if (safe) SYNTAX("print > is unsafe");
+			else $$ = stat3($1, $2, itonp($3), $4); }
 	| print prarg			{ $$ = stat3($1, $2, NIL, NIL); }
 	| DELETE varname '[' patlist ']' { $$ = stat2(DELETE, makearr($2), $4); }
-	| DELETE varname		{ yyclearin; ERROR "you can only delete array[element]" SYNTAX; $$ = stat1(DELETE, $2); }
+	| DELETE varname		{ $$ = stat2(DELETE, makearr($2), 0); }
 	| pattern			{ $$ = exptostat($1); }
-	| error				{ yyclearin; ERROR "illegal statement" SYNTAX; }
+	| error				{ yyclearin; SYNTAX("illegal statement"); }
 	;
 
 st:
-	  nl | ';' opt_nl
+	  nl
+	| ';' opt_nl
 	;
 
 stmt:
-	  BREAK st		{ $$ = stat1(BREAK, NIL); }
-	| CLOSE pattern st	{ $$ = stat1(CLOSE, $2); }
-	| CONTINUE st		{ $$ = stat1(CONTINUE, NIL); }
-	| do stmt WHILE '(' pattern ')' st
-		{ $$ = stat2(DO, $2, notnull($5)); }
+	  BREAK st		{
+			if (!inloop) SYNTAX("break illegal outside of loops");
+			$$ = stat1(BREAK, NIL); }
+	| CONTINUE st		{
+			if (!inloop) SYNTAX("continue illegal outside of loops");
+			 $$ = stat1(CONTINUE, NIL); }
+	| do {inloop++;} stmt {--inloop;} WHILE '(' pattern ')' st
+		{ $$ = stat2(DO, $3, notnull($7)); }
 	| EXIT pattern st	{ $$ = stat1(EXIT, $2); }
 	| EXIT st		{ $$ = stat1(EXIT, NIL); }
 	| for
@@ -324,12 +359,15 @@
 	| if stmt		{ $$ = stat3(IF, $1, $2, NIL); }
 	| lbrace stmtlist rbrace { $$ = $2; }
 	| NEXT st	{ if (infunc)
-				ERROR "next is illegal inside a function" SYNTAX;
+				SYNTAX("next is illegal inside a function");
 			  $$ = stat1(NEXT, NIL); }
+	| NEXTFILE st	{ if (infunc)
+				SYNTAX("nextfile is illegal inside a function");
+			  $$ = stat1(NEXTFILE, NIL); }
 	| RETURN pattern st	{ $$ = stat1(RETURN, $2); }
 	| RETURN st		{ $$ = stat1(RETURN, NIL); }
 	| simple_stmt st
-	| while stmt		{ $$ = stat2(WHILE, $1, $2); }
+	| while {inloop++;} stmt		{ --inloop; $$ = stat2(WHILE, $1, $3); }
 	| ';' opt_nl		{ $$ = 0; }
 	;
 
@@ -343,7 +381,8 @@
 	;
 
 term:
-	  term '+' term			{ $$ = op2(ADD, $1, $3); }
+	  term '/' ASGNOP term		{ $$ = op2(DIVEQ, $1, $4); }
+	| term '+' term			{ $$ = op2(ADD, $1, $3); }
 	| term '-' term			{ $$ = op2(MINUS, $1, $3); }
 	| term '*' term			{ $$ = op2(MULT, $1, $3); }
 	| term '/' term			{ $$ = op2(DIVIDE, $1, $3); }
@@ -351,23 +390,26 @@
 	| term POWER term		{ $$ = op2(POWER, $1, $3); }
 	| '-' term %prec UMINUS		{ $$ = op1(UMINUS, $2); }
 	| '+' term %prec UMINUS		{ $$ = $2; }
-	| BLTIN '(' ')'			{ $$ = op2(BLTIN, (Node *) $1, rectonode()); }
-	| BLTIN '(' patlist ')'		{ $$ = op2(BLTIN, (Node *) $1, $3); }
-	| BLTIN				{ $$ = op2(BLTIN, (Node *) $1, rectonode()); }
-	| CALL '(' ')'			{ $$ = op2(CALL, valtonode($1,CVAR), NIL); }
-	| CALL '(' patlist ')'		{ $$ = op2(CALL, valtonode($1,CVAR), $3); }
+	| NOT term %prec UMINUS		{ $$ = op1(NOT, notnull($2)); }
+	| BLTIN '(' ')'			{ $$ = op2(BLTIN, itonp($1), rectonode()); }
+	| BLTIN '(' patlist ')'		{ $$ = op2(BLTIN, itonp($1), $3); }
+	| BLTIN				{ $$ = op2(BLTIN, itonp($1), rectonode()); }
+	| CALL '(' ')'			{ $$ = op2(CALL, celltonode($1,CVAR), NIL); }
+	| CALL '(' patlist ')'		{ $$ = op2(CALL, celltonode($1,CVAR), $3); }
+	| CLOSE term			{ $$ = op1(CLOSE, $2); }
 	| DECR var			{ $$ = op1(PREDECR, $2); }
 	| INCR var			{ $$ = op1(PREINCR, $2); }
 	| var DECR			{ $$ = op1(POSTDECR, $1); }
 	| var INCR			{ $$ = op1(POSTINCR, $1); }
-	| GETLINE var LT term		{ $$ = op3(GETLINE, $2, (Node *)$3, $4); }
-	| GETLINE LT term		{ $$ = op3(GETLINE, NIL, (Node *)$2, $3); }
+	| GETLINE var LT term		{ $$ = op3(GETLINE, $2, itonp($3), $4); }
+	| GETLINE LT term		{ $$ = op3(GETLINE, NIL, itonp($2), $3); }
 	| GETLINE var			{ $$ = op3(GETLINE, $2, NIL, NIL); }
 	| GETLINE			{ $$ = op3(GETLINE, NIL, NIL, NIL); }
 	| INDEX '(' pattern comma pattern ')'
 		{ $$ = op2(INDEX, $3, $5); }
 	| INDEX '(' pattern comma reg_expr ')'
-		{ ERROR "index() doesn't permit regular expressions" SYNTAX;
+		{ SYNTAX("index() doesn't permit regular expressions");
+		  /* LINTED align */
 		  $$ = op2(INDEX, $3, (Node*)$5); }
 	| '(' pattern ')'		{ $$ = $2; }
 	| MATCHFCN '(' pattern comma reg_expr ')'
@@ -377,7 +419,7 @@
 			$$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa(strnode($5), 1));
 		  else
 			$$ = op3(MATCHFCN, (Node *)1, $3, $5); }
-	| NUMBER			{ $$ = valtonode($1, CCON); }
+	| NUMBER			{ $$ = celltonode($1, CCON); }
 	| SPLIT '(' pattern comma varname comma pattern ')'     /* string */
 		{ $$ = op4(SPLIT, $3, makearr($5), $7, (Node*)STRING); }
 	| SPLIT '(' pattern comma varname comma reg_expr ')'    /* const /regexp/ */
@@ -385,7 +427,7 @@
 	| SPLIT '(' pattern comma varname ')'
 		{ $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); }  /* default */
 	| SPRINTF '(' patlist ')'	{ $$ = op1($1, $3); }
-	| STRING	 		{ $$ = valtonode($1, CCON); }
+	| STRING	 		{ $$ = celltonode($1, CCON); }
 	| subop '(' reg_expr comma pattern ')'
 		{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); }
 	| subop '(' pattern comma pattern ')'
@@ -410,20 +452,21 @@
 var:
 	  varname
 	| varname '[' patlist ']'	{ $$ = op2(ARRAY, makearr($1), $3); }
-	| FIELD				{ $$ = valtonode($1, CFLD); }
-	| IVAR				{ $$ = op1(INDIRECT, valtonode($1, CVAR)); }
+	| IVAR				{ $$ = op1(INDIRECT, celltonode($1, CVAR)); }
 	| INDIRECT term	 		{ $$ = op1(INDIRECT, $2); }
 	;	
 
 varlist:
 	  /* nothing */		{ arglist = $$ = 0; }
-	| VAR			{ arglist = $$ = valtonode($1,CVAR); }
-	| varlist comma VAR	{ arglist = $$ = linkum($1,valtonode($3,CVAR)); }
+	| VAR			{ arglist = $$ = celltonode($1,CVAR); }
+	| varlist comma VAR	{
+			checkdup($1, $3);
+			arglist = $$ = linkum($1,celltonode($3,CVAR)); }
 	;
 
 varname:
-	  VAR			{ $$ = valtonode($1, CVAR); }
-	| ARG 			{ $$ = op1(ARG, (Node *) $1); }
+	  VAR			{ $$ = celltonode($1, CVAR); }
+	| ARG 			{ $$ = op1(ARG, itonp($1)); }
 	| VARNF			{ $$ = op1(VARNF, (Node *) $1); }
 	;
 
@@ -438,9 +481,9 @@
 setfname(Cell *p)
 {
 	if (isarr(p))
-		ERROR "%s is an array, not a function", p->nval SYNTAX;
-	else if (isfunc(p))
-		ERROR "you can't define function %s more than once", p->nval SYNTAX;
+		SYNTAX("%s is an array, not a function", p->nval);
+	else if (isfcn(p))
+		SYNTAX("you can't define function %s more than once", p->nval);
 	curfname = p->nval;
 }
 
@@ -448,13 +491,13 @@
 static int
 constnode(Node *p)
 {
-	return p->ntype == NVALUE && ((Cell *) (p->narg[0]))->csub == CCON;
+	return (isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON);
 }
 
 static uchar *
 strnode(Node *p)
 {
-	return ((Cell *)(p->narg[0]))->sval;
+	return (((Cell *)(p->narg[0]))->sval);
 }
 
 static Node *
@@ -463,8 +506,21 @@
 	switch (n->nobj) {
 	case LE: case LT: case EQ: case NE: case GT: case GE:
 	case BOR: case AND: case NOT:
-		return n;
+		return (n);
 	default:
-		return op2(NE, n, nullnode);
+		return (op2(NE, n, nullnode));
+	}
+}
+
+static void
+checkdup(Node *vl, Cell *cp)	/* check if name already in list */
+{
+	uchar *s = cp->nval;
+
+	for (; vl; vl = vl->nnext) {
+		if (strcmp((char *)s, (char *)((Cell *)(vl->narg[0]))->nval) == 0) {
+			SYNTAX("duplicate argument %s", s);
+			break;
+		}
 	}
 }
--- old/usr/src/cmd/awk/awk.h	2013-05-11 15:20:42.909278564 +0000
+++ new/usr/src/cmd/awk/awk.h	2013-05-11 15:20:42.920110534 +0000
@@ -23,13 +23,35 @@
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
+/*
+ * 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.
+ */
 
 #ifndef AWK_H
 #define	AWK_H
 
 #include <sys/types.h>
+#include <assert.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -40,7 +62,7 @@
 typedef double	Awkfloat;
 typedef	unsigned char uchar;
 
-#define	xfree(a)	{ if ((a) != NULL) { free(a); a = NULL; } }
+#define	xfree(a)	{ if ((a) != NULL) { free((void *)(a)); (a) = NULL; } }
 
 #define	DEBUG
 #ifdef	DEBUG
@@ -50,26 +72,10 @@
 #define	dprintf(x)
 #endif
 
-extern	char	errbuf[200];
-extern	void	error(int, char *);
-#define	ERROR	(void) snprintf(errbuf, sizeof (errbuf),
-/*CSTYLED*/
-#define	FATAL	), error(1, errbuf)
-/*CSTYLED*/
-#define	WARNING	), error(0, errbuf)
-/*CSTYLED*/
-#define	SYNTAX	), yyerror(errbuf)
-/*CSTYLED*/
-#define	CONT	)
-
 extern int	compile_time;	/* 1 if compiling, 0 if running */
+extern int	safe;		/* 0 => unsafe, 1 => safe */
 
-#define	FLD_INCR	64
-#define	LINE_INCR	256
-
-/* ensure that there is extra 1 byte in the buffer */
-#define	expand_buf(p, n, r)	\
-	if (*(n) == 0 || (r) >= (*(n) - 1)) r_expand_buf(p, n, r)
+#define	RECSIZE	(8 * 1024)	/* sets limit on records, fields, etc., etc. */
 
 extern uchar	**FS;
 extern uchar	**RS;
@@ -101,12 +107,12 @@
 	uchar	*nval;		/* name, for variables only */
 	uchar	*sval;		/* string value */
 	Awkfloat fval;		/* value as number */
-	unsigned tval;
+	int	tval;
 		/* type info: STR|NUM|ARR|FCN|FLD|CON|DONTFREE */
 	struct Cell *cnext;	/* ptr to next if chained */
 } Cell;
 
-typedef struct {		/* symbol table array */
+typedef struct Array {		/* symbol table array */
 	int	nelem;		/* elements in table right now */
 	int	size;		/* size of tab */
 	Cell	**tab;		/* hash table pointers */
@@ -114,8 +120,9 @@
 
 #define	NSYMTAB	50	/* initial size of a symbol table */
 extern Array	*symtab, *makesymtab(int);
-extern Cell	*setsymtab(uchar *, uchar *, Awkfloat, unsigned int, Array *);
-extern Cell	*lookup(uchar *, Array *);
+extern Cell	*setsymtab(const uchar *, const uchar *, Awkfloat,
+    unsigned int, Array *);
+extern Cell	*lookup(const uchar *, Array *);
 
 extern Cell	*recloc;	/* location of input record */
 extern Cell	*nrloc;		/* NR */
@@ -134,16 +141,13 @@
 #define	FLD	0100	/* this is a field $1, $2, ... */
 #define	REC	0200	/* this is $0 */
 
-#define	freeable(p)	(!((p)->tval & DONTFREE))
 
 extern Awkfloat setfval(Cell *, Awkfloat), getfval(Cell *), r_getfval(Cell *);
-extern uchar	*setsval(Cell *, uchar *), *getsval(Cell *), *r_getsval(Cell *);
-extern uchar	*tostring(uchar *), *tokname(int), *qstring(uchar *, int);
-
-#define	getfval(p)	\
-	(((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
-#define	getsval(p)	\
-	(((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
+extern	uchar	*setsval(Cell *, const uchar *);
+extern	uchar	*getsval(Cell *);
+extern	uchar	*tostring(const uchar *);
+extern	uchar	*tokname(int);
+extern	uchar	*qstring(const uchar *, int);
 
 /* function types */
 #define	FLENGTH	1
@@ -159,6 +163,7 @@
 #define	FATAN	11
 #define	FTOUPPER 12
 #define	FTOLOWER 13
+#define	FFLUSH	14
 
 /* Node:  parse tree is made of nodes, with Cell's at bottom */
 
@@ -190,6 +195,7 @@
 #define	CNAME	3
 #define	CVAR	2
 #define	CFLD	1
+#define	CUNK	0
 
 /* bool subtypes */
 #define	BTRUE	11
@@ -201,6 +207,7 @@
 #define	JBREAK	23
 #define	JCONT	24
 #define	JRET	25
+#define	JNEXTFILE	26
 
 /* node types */
 #define	NVALUE	1
@@ -212,16 +219,21 @@
 extern	Cell	*nullproc(Node **, int);
 extern	int	pairstack[], paircnt;
 
-extern	Node	*stat1(int, Node *), *stat2(int, Node *, Node *);
+extern	int	pgetc(void);
+extern	Node	*stat1(int, Node *);
+extern	Node	*stat2(int, Node *, Node *);
 extern	Node	*stat3(int, Node *, Node *, Node *);
 extern	Node	*stat4(int, Node *, Node *, Node *, Node *);
 extern	Node	*pa2stat(Node *, Node *, Node *);
-extern	Node	*op1(int, Node *), *op2(int, Node *, Node *);
+extern	Node	*op1(int, Node *);
+extern	Node	*op2(int, Node *, Node *);
 extern	Node	*op3(int, Node *, Node *, Node *);
 extern	Node	*op4(int, Node *, Node *, Node *, Node *);
-extern	Node	*linkum(Node *, Node *), *valtonode(Cell *, int);
+extern	Node	*linkum(Node *, Node *);
+extern	Node	*celltonode(Cell *, int);
 extern	Node	*rectonode(void), *exptostat(Node *);
 extern	Node	*makearr(Node *);
+extern	Node	*itonp(int);
 
 #define	notlegal(n)	\
 	(n <= FIRSTTOKEN || n >= LASTTOKEN || proctab[n-FIRSTTOKEN] == nullproc)
@@ -231,47 +243,64 @@
 #define	isexit(n)	((n)->csub == JEXIT)
 #define	isbreak(n)	((n)->csub == JBREAK)
 #define	iscont(n)	((n)->csub == JCONT)
-#define	isnext(n)	((n)->csub == JNEXT)
+#define	isnext(n)	((n)->csub == JNEXT || (n)->csub == JNEXTFILE)
 #define	isret(n)	((n)->csub == JRET)
+#define	isrec(n)	((n)->tval & REC)
+#define	isfld(n)	((n)->tval & FLD)
 #define	isstr(n)	((n)->tval & STR)
 #define	isnum(n)	((n)->tval & NUM)
 #define	isarr(n)	((n)->tval & ARR)
-#define	isfunc(n)	((n)->tval & FCN)
+#define	isfcn(n)	((n)->tval & FCN)
 #define	istrue(n)	((n)->csub == BTRUE)
 #define	istemp(n)	((n)->csub == CTEMP)
+#define	isargument(n)	((n)->nobj == ARG)
+/* #define	freeable(p)	(!((p)->tval & DONTFREE)) */
+#define	freeable(p)	(((p)->tval & (STR|DONTFREE)) == STR)
 
-#define	NCHARS	(256+1)
+#define	NCHARS	(256+3)		/* 256 handles 8-bit chars; 128 does 7-bit */
+				/* watch out in match(), etc. */
 #define	NSTATES	32
 
 typedef struct rrow {
-	int	ltype;
-	int	lval;
+	long	ltype;	/* long avoids pointer warnings on 64-bit */
+	union {
+		int i;
+		Node *np;
+		uchar *up;
+	} lval;		/* because Al stores a pointer in it! */
 	int	*lfollow;
 } rrow;
 
 typedef struct fa {
+	uchar	gototab[NSTATES][NCHARS];
+	uchar	out[NSTATES];
 	uchar	*restr;
+	int	*posns[NSTATES];
 	int	anchor;
 	int	use;
-	uchar	gototab[NSTATES][NCHARS];
-	int	*posns[NSTATES];
-	uchar	out[NSTATES];
 	int	initstat;
 	int	curstat;
 	int	accept;
 	int	reset;
-	struct	rrow re[1];
+	struct	rrow re[1]; /* variable: actual size set by calling malloc */
 } fa;
 
 /* b.c */
-extern	fa	*makedfa(uchar *, int);
-extern	int	nematch(fa *, uchar *);
-extern	int	match(fa *, uchar *);
-extern	int	pmatch(fa *, uchar *);
+extern	fa	*makedfa(const uchar *, int);
+extern	int	nematch(fa *, const uchar *);
+extern	int	match(fa *, const uchar *);
+extern	int	pmatch(fa *, const uchar *);
+
+/* lex.c */
+extern	void	unput(int);
+extern	void	unputstr(const char *);
+extern	void	startreg(void);
 
 /* lib.c */
-extern	int	isclvar(uchar *);
-extern	int	is_number(uchar *);
+extern	void	recinit(unsigned int);
+extern	void	growfldtab(int);
+extern	int	isclvar(const uchar *);
+extern	int	is_number(const uchar *);
 extern	void	setclvar(uchar *);
 extern	int	readrec(uchar **, size_t *, FILE *);
 extern	void	bracecheck(void);
@@ -279,16 +308,18 @@
 extern	void	yyerror(char *);
 extern	void	fldbld(void);
 extern	void	recbld(void);
-extern	int	getrec(uchar **, size_t *);
+extern	int	getrec(uchar **, size_t *, int);
 extern	Cell	*fieldadr(int);
 extern	void	newfld(int);
 extern	Cell	*getfld(int);
 extern	int	fldidx(Cell *);
-extern	double	errcheck(double, char *);
+extern	void	SYNTAX(const char *, ...);
+extern	void	FATAL(const char *, ...) __attribute__((__noreturn__));
+extern	void	WARNING(const char *, ...);
+extern	void	error(void);
+extern	double	errcheck(double, const char *);
 extern	void	fpecatch(int);
-extern	void	init_buf(uchar **, size_t *, size_t);
-extern	void	adjust_buf(uchar **, size_t);
-extern	void	r_expand_buf(uchar **, size_t *, size_t);
+extern	void	nextfile(void);
 
 extern	int	donefld;
 extern	int	donerec;
@@ -301,18 +332,20 @@
 extern	uchar	*lexprog;
 extern	int	compile_time;
 extern	char	radixpoint;
+extern	uchar	*cursource(void);
 
 /* tran.c */
 extern	void	syminit(void);
 extern	void	arginit(int, uchar **);
 extern	void	envinit(uchar **);
 extern	void	freesymtab(Cell *);
-extern	void	freeelem(Cell *, uchar *);
+extern	void	freeelem(Cell *, const uchar *);
 extern	void	funnyvar(Cell *, char *);
-extern	int	hash(uchar *, int);
+extern	int	hash(const uchar *, int);
 extern	Awkfloat *ARGC;
 
 /* run.c */
+extern	int	adjbuf(uchar **, size_t *, int, int, uchar **, const char *);
 extern	void	run(Node *);
 
 extern	int	paircnt;
@@ -325,6 +358,11 @@
 extern	FILE	*yyin;
 extern	off_t	lineno;
 
+/* parse.c */
+extern	int	ptoi(void *);
+extern	int	isarg(const uchar *);
+extern	void	defn(Cell *, Node *, Node *);
+
 /* proc */
 extern Cell *nullproc(Node **, int);
 extern Cell *program(Node **, int);
@@ -336,7 +374,7 @@
 extern Cell *sub(Node **, int);
 extern Cell *gsub(Node **, int);
 extern Cell *sindex(Node **, int);
-extern Cell *a_sprintf(Node **, int);
+extern Cell *awksprintf(Node **, int);
 extern Cell *arith(Node **, int);
 extern Cell *incrdecr(Node **, int);
 extern Cell *cat(Node **, int);
@@ -344,10 +382,10 @@
 extern Cell *dopa2(Node **, int);
 extern Cell *matchop(Node **, int);
 extern Cell *intest(Node **, int);
-extern Cell *aprintf(Node **, int);
-extern Cell *print(Node **, int);
+extern Cell *awkprintf(Node **, int);
+extern Cell *printstat(Node **, int);
 extern Cell *closefile(Node **, int);
-extern Cell *delete(Node **, int);
+extern Cell *awkdelete(Node **, int);
 extern Cell *split(Node **, int);
 extern Cell *assign(Node **, int);
 extern Cell *condexpr(Node **, int);
@@ -361,6 +399,6 @@
 extern Cell *call(Node **, int);
 extern Cell *arg(Node **, int);
 extern Cell *getnf(Node **, int);
-extern Cell *getaline(Node **, int);
+extern Cell *awkgetline(Node **, int);
 
 #endif /* AWK_H */
--- old/usr/src/cmd/awk/awk.lx.l	2013-05-11 15:20:43.397432541 +0000
+++ /dev/null	2013-05-11 15:20:43.000000000 +0000
@@ -1,306 +0,0 @@
-%{
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2005 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"
-%}
-
-%Start A str sc reg comment
-
-%{
-
-#include	<sys/types.h>
-#include	"awk.h"
-#include	"y.tab.h"
-
-#undef	input	/* defeat lex */
-#undef	unput
-
-static void unput(int);
-static void unputstr(char *);
-
-extern YYSTYPE	yylval;
-extern int	infunc;
-
-off_t	lineno	= 1;
-int	bracecnt = 0;
-int	brackcnt  = 0;
-int	parencnt = 0;
-#define DEBUG
-#ifdef	DEBUG
-#	define	RET(x)	{if(dbg)printf("lex %s [%s]\n", tokname(x), yytext); return(x); }
-#else
-#	define	RET(x)	return(x)
-#endif
-
-/*
- * The standards (SUSV2) requires that Record size be atleast LINE_MAX.
- * LINE_MAX is a standard variable defined in limits.h.
- * Though nawk is not standards compliant, we let RECSIZE
- * grow with LINE_MAX instead of the magic number 1024.
- */
-#define	CBUFLEN	(3 * LINE_MAX)
-
-#define	CADD	cbuf[clen++] = yytext[0]; \
-		if (clen >= CBUFLEN-1) { \
-			ERROR "string/reg expr %.10s... too long", cbuf SYNTAX; \
-			BEGIN A; \
-		}
-
-static uchar	cbuf[CBUFLEN];
-static uchar	*s;
-static int	clen, cflag;
-%}
-
-A	[a-zA-Z_]
-B	[a-zA-Z0-9_]
-D	[0-9]
-O	[0-7]
-H	[0-9a-fA-F]
-WS	[ \t]
-
-%%
-	switch (yybgin-yysvec-1) {	/* witchcraft */
-	case 0:
-		BEGIN A;
-		break;
-	case sc:
-		BEGIN A;
-		RET('}');
-	}
-
-<A>\n		{ lineno++; RET(NL); }
-<A>#.*		{ ; }	/* strip comments */
-<A>{WS}+	{ ; }
-<A>;		{ RET(';'); }
-
-<A>"\\"\n	{ lineno++; }
-<A>BEGIN	{ RET(XBEGIN); }
-<A>END		{ RET(XEND); }
-<A>func(tion)?	{ if (infunc) ERROR "illegal nested function" SYNTAX; RET(FUNC); }
-<A>return	{ if (!infunc) ERROR "return not in function" SYNTAX; RET(RETURN); }
-<A>"&&"		{ RET(AND); }
-<A>"||"		{ RET(BOR); }
-<A>"!"		{ RET(NOT); }
-<A>"!="		{ yylval.i = NE; RET(NE); }
-<A>"~"		{ yylval.i = MATCH; RET(MATCHOP); }
-<A>"!~"		{ yylval.i = NOTMATCH; RET(MATCHOP); }
-<A>"<"		{ yylval.i = LT; RET(LT); }
-<A>"<="		{ yylval.i = LE; RET(LE); }
-<A>"=="		{ yylval.i = EQ; RET(EQ); }
-<A>">="		{ yylval.i = GE; RET(GE); }
-<A>">"		{ yylval.i = GT; RET(GT); }
-<A>">>"		{ yylval.i = APPEND; RET(APPEND); }
-<A>"++"		{ yylval.i = INCR; RET(INCR); }
-<A>"--"		{ yylval.i = DECR; RET(DECR); }
-<A>"+="		{ yylval.i = ADDEQ; RET(ASGNOP); }
-<A>"-="		{ yylval.i = SUBEQ; RET(ASGNOP); }
-<A>"*="		{ yylval.i = MULTEQ; RET(ASGNOP); }
-<A>"/="		{ yylval.i = DIVEQ; RET(ASGNOP); }
-<A>"%="		{ yylval.i = MODEQ; RET(ASGNOP); }
-<A>"^="		{ yylval.i = POWEQ; RET(ASGNOP); }
-<A>"**="	{ yylval.i = POWEQ; RET(ASGNOP); }
-<A>"="		{ yylval.i = ASSIGN; RET(ASGNOP); }
-<A>"**"		{ RET(POWER); }
-<A>"^"		{ RET(POWER); }
-
-<A>"$"{D}+	{ yylval.cp = fieldadr(atoi(yytext+1)); RET(FIELD); }
-<A>"$NF"	{ unputstr("(NF)"); return(INDIRECT); }
-<A>"$"{A}{B}*	{ int c, n;
-		  c = input(); unput(c);
-		  if (c == '(' || c == '[' || infunc && (n=isarg(yytext+1)) >= 0) {
-			unputstr(yytext+1);
-			return(INDIRECT);
-		  } else {
-			yylval.cp = setsymtab((uchar *)yytext+1,
-				(uchar *)"",0.0,STR|NUM,symtab);
-			RET(IVAR);
-		  }
-		}
-<A>"$"		{ RET(INDIRECT); }
-<A>NF		{ yylval.cp = setsymtab((uchar *)yytext, (uchar *)"", 0.0, NUM, symtab); RET(VARNF); }
-
-<A>({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)?	{
-		  yylval.cp = setsymtab((uchar *)yytext, tostring((uchar *)yytext), atof(yytext), CON|NUM, symtab);
-		  RET(NUMBER); }
-
-<A>while	{ RET(WHILE); }
-<A>for		{ RET(FOR); }
-<A>do		{ RET(DO); }
-<A>if		{ RET(IF); }
-<A>else		{ RET(ELSE); }
-<A>next		{ RET(NEXT); }
-<A>exit		{ RET(EXIT); }
-<A>break	{ RET(BREAK); }
-<A>continue	{ RET(CONTINUE); }
-<A>print	{ yylval.i = PRINT; RET(PRINT); }
-<A>printf	{ yylval.i = PRINTF; RET(PRINTF); }
-<A>sprintf	{ yylval.i = SPRINTF; RET(SPRINTF); }
-<A>split	{ yylval.i = SPLIT; RET(SPLIT); }
-<A>substr	{ RET(SUBSTR); }
-<A>sub		{ yylval.i = SUB; RET(SUB); }
-<A>gsub		{ yylval.i = GSUB; RET(GSUB); }
-<A>index	{ RET(INDEX); }
-<A>match	{ RET(MATCHFCN); }
-<A>in		{ RET(IN); }
-<A>getline	{ RET(GETLINE); }
-<A>close	{ RET(CLOSE); }
-<A>delete	{ RET(DELETE); }
-<A>length	{ yylval.i = FLENGTH; RET(BLTIN); }
-<A>log		{ yylval.i = FLOG; RET(BLTIN); }
-<A>int		{ yylval.i = FINT; RET(BLTIN); }
-<A>exp		{ yylval.i = FEXP; RET(BLTIN); }
-<A>sqrt		{ yylval.i = FSQRT; RET(BLTIN); }
-<A>sin		{ yylval.i = FSIN; RET(BLTIN); }
-<A>cos		{ yylval.i = FCOS; RET(BLTIN); }
-<A>atan2	{ yylval.i = FATAN; RET(BLTIN); }
-<A>system	{ yylval.i = FSYSTEM; RET(BLTIN); }
-<A>rand		{ yylval.i = FRAND; RET(BLTIN); }
-<A>srand	{ yylval.i = FSRAND; RET(BLTIN); }
-<A>toupper	{ yylval.i = FTOUPPER; RET(BLTIN); }
-<A>tolower	{ yylval.i = FTOLOWER; RET(BLTIN); }
-
-<A>{A}{B}*	{ int n, c;
-		  c = input(); unput(c);	/* look for '(' */
-		  if (c != '(' && infunc && (n=isarg(yytext)) >= 0) {
-			yylval.i = n;
-			RET(ARG);
-		  } else {
-			yylval.cp = setsymtab((uchar *)yytext,
-				(uchar *)"",0.0,STR|NUM,symtab);
-			if (c == '(') {
-				RET(CALL);
-			} else {
-				RET(VAR);
-			}
-		  }
-		}
-<A>\"		{ BEGIN str; clen = 0; }
-
-<A>"}"		{ if (--bracecnt < 0) ERROR "extra }" SYNTAX; BEGIN sc; RET(';'); }
-<A>"]"		{ if (--brackcnt < 0) ERROR "extra ]" SYNTAX; RET(']'); }
-<A>")"		{ if (--parencnt < 0) ERROR "extra )" SYNTAX; RET(')'); }
-
-<A>.		{ if (yytext[0] == '{') bracecnt++;
-		  else if (yytext[0] == '[') brackcnt++;
-		  else if (yytext[0] == '(') parencnt++;
-		  RET(yylval.i = yytext[0]); /* everything else */ }
-
-<reg>\\.	{ cbuf[clen++] = '\\'; cbuf[clen++] = yytext[1]; }
-<reg>\n		{ ERROR "newline in regular expression %.10s...", cbuf SYNTAX; lineno++; BEGIN A; }
-<reg>"/"	{ BEGIN A;
-		  cbuf[clen] = 0;
-		  yylval.s = tostring(cbuf);
-		  unput('/');
-		  RET(REGEXPR); }
-<reg>.		{ CADD; }
-
-<str>\"		{ BEGIN A;
-		  cbuf[clen] = 0; s = tostring(cbuf);
-		  cbuf[clen] = ' '; cbuf[++clen] = 0;
-		  yylval.cp = setsymtab(cbuf, s, 0.0, CON|STR, symtab);
-		  RET(STRING); }
-<str>\n		{ ERROR "newline in string %.10s...", cbuf SYNTAX; lineno++; BEGIN A; }
-<str>"\\\""	{ cbuf[clen++] = '"'; }
-<str>"\\"n	{ cbuf[clen++] = '\n'; }
-<str>"\\"t	{ cbuf[clen++] = '\t'; }
-<str>"\\"f	{ cbuf[clen++] = '\f'; }
-<str>"\\"r	{ cbuf[clen++] = '\r'; }
-<str>"\\"b	{ cbuf[clen++] = '\b'; }
-<str>"\\"v	{ cbuf[clen++] = '\v'; }	/* these ANSIisms may not be known by */
-<str>"\\"a	{ cbuf[clen++] = '\007'; }	/* your compiler. hence 007 for bell */
-<str>"\\\\"	{ cbuf[clen++] = '\\'; }
-<str>"\\"({O}{O}{O}|{O}{O}|{O}) { int n;
-		  sscanf(yytext+1, "%o", &n); cbuf[clen++] = n; }
-<str>"\\"x({H}+) { int n;	/* ANSI permits any number! */
-		  sscanf(yytext+2, "%x", &n); cbuf[clen++] = n; }
-<str>"\\".	{ cbuf[clen++] = yytext[1]; }
-<str>.		{ CADD; }
-
-%%
-
-void
-startreg()
-{
-	BEGIN reg;
-	clen = 0;
-}
-
-/* input() and unput() are transcriptions of the standard lex
-   macros for input and output with additions for error message
-   printing.  God help us all if someone changes how lex works.
-*/
-
-uchar	ebuf[300];
-uchar	*ep = ebuf;
-
-int
-input(void)
-{
-	register int c;
-	extern uchar *lexprog;
-
-	if (yysptr > yysbuf)
-		c = U(*--yysptr);
-	else if (lexprog != NULL)	/* awk '...' */
-		c = *lexprog++;
-	else				/* awk -f ... */
-		c = pgetc();
-	if (c == '\n')
-		yylineno++;
-	else if (c == EOF)
-		c = 0;
-	if (ep >= ebuf + sizeof ebuf)
-		ep = ebuf;
-	return *ep++ = c;
-}
-
-static void
-unput(int c)
-{
-	yytchar = c;
-	if (yytchar == '\n')
-		yylineno--;
-	*yysptr++ = yytchar;
-	if (--ep < ebuf)
-		ep = ebuf + sizeof(ebuf) - 1;
-}
-
-
-static void
-unputstr(char *s)
-{
-	int i;
-
-	for (i = strlen(s)-1; i >= 0; i--)
-		unput(s[i]);
-}
--- old/usr/src/cmd/awk/b.c	2013-05-11 15:20:43.546414060 +0000
+++ new/usr/src/cmd/awk/b.c	2013-05-11 15:20:43.561137460 +0000
@@ -25,26 +25,47 @@
  * 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 "awk.h"
 #include "y.tab.h"
 
-#define	HAT	(NCHARS-1)	/* matches ^ in regular expr */
+#define	HAT	(NCHARS+2)	/* matches ^ in regular expr */
 				/* NCHARS is 2**n */
-#define	MAXLIN (3 * LINE_MAX)
+#define	MAXLIN	22
 
-#define	type(v)		(v)->nobj
+#define	type(v)		(v)->nobj	/* badly overloaded here */
+#define	info(v)		(v)->ntype	/* badly overloaded here */
 #define	left(v)		(v)->narg[0]
 #define	right(v)	(v)->narg[1]
 #define	parent(v)	(v)->nnext
 
 #define	LEAF	case CCL: case NCCL: case CHAR: case DOT: case FINAL: case ALL:
+#define	ELEAF	case EMPTYRE:		/* empty string in regexp */
 #define	UNARY	case STAR: case PLUS: case QUEST:
 
 /*
@@ -56,15 +77,15 @@
  *	parent contains pointer to parent
  */
 
-int	setvec[MAXLIN];
-int	tmpset[MAXLIN];
-Node	*point[MAXLIN];
+int	*setvec;
+int	*tmpset;
+int	maxsetvec = 0;
 
 int	rtok;		/* next token in current re */
 int	rlxval;
-uchar	*rlxstr;
-uchar	*prestr;	/* current position in current re */
-uchar	*lastre;	/* origin of last re */
+static	uchar	*rlxstr;
+static	uchar	*prestr;	/* current position in current re */
+static	uchar	*lastre;	/* origin of last re */
 
 static	int setcnt;
 static	int poscnt;
@@ -76,57 +97,72 @@
 fa	*fatab[NFA];
 int	nfatab	= 0;	/* entries in fatab */
 
-static fa	*mkdfa(uchar *, int);
+static fa	*mkdfa(const uchar *, int);
 static int	makeinit(fa *, int);
 static void	penter(Node *);
 static void	freetr(Node *);
-static void	overflo(char *);
+static void	overflo(const char *);
 static void	cfoll(fa *, Node *);
 static void	follow(Node *);
-static Node	*reparse(uchar *);
+static Node	*reparse(const uchar *);
 static int	relex(void);
 static void	freefa(fa *);
 static int	cgoto(fa *, int, int);
+static Node	*regexp(void);
+static Node	*primary(void);
+static Node	*concat(Node *);
+static Node	*alt(Node *);
+static Node	*unary(Node *);
 
 fa *
-makedfa(uchar *s, int anchor)	/* returns dfa for reg expr s */
+makedfa(const uchar *s, int anchor)	/* returns dfa for reg expr s */
 {
 	int i, use, nuse;
 	fa *pfa;
+	static int now = 1;
+
+	if (setvec == 0) {	/* first time through any RE */
+		maxsetvec = MAXLIN;
+		setvec = (int *)malloc(maxsetvec * sizeof (int));
+		tmpset = (int *)malloc(maxsetvec * sizeof (int));
+		if (setvec == 0 || tmpset == 0)
+			overflo("out of space initializing makedfa");
+	}
 
 	if (compile_time)	/* a constant for sure */
 		return (mkdfa(s, anchor));
 	for (i = 0; i < nfatab; i++) {	/* is it there already? */
 		if (fatab[i]->anchor == anchor &&
-		    strcmp((char *)fatab[i]->restr, (char *)s) == 0) {
-			fatab[i]->use++;
+		    strcmp((const char *)fatab[i]->restr, (char *)s) == 0) {
+			fatab[i]->use = now++;
 			return (fatab[i]);
 		}
 	}
 	pfa = mkdfa(s, anchor);
 	if (nfatab < NFA) {	/* room for another */
 		fatab[nfatab] = pfa;
-		fatab[nfatab]->use = 1;
+		fatab[nfatab]->use = now++;
 		nfatab++;
 		return (pfa);
 	}
 	use = fatab[0]->use;	/* replace least-recently used */
 	nuse = 0;
-	for (i = 1; i < nfatab; i++)
+	for (i = 1; i < nfatab; i++) {
 		if (fatab[i]->use < use) {
 			use = fatab[i]->use;
 			nuse = i;
 		}
+	}
 	freefa(fatab[nuse]);
 	fatab[nuse] = pfa;
-	pfa->use = 1;
+	pfa->use = now++;
 	return (pfa);
 }
 
 fa *
-mkdfa(uchar *s, int anchor)	/* does the real work of making a dfa */
-	/* anchor = 1 for anchored matches, else 0 */
-{
+mkdfa(const uchar *s, int anchor)
+{				/* does the real work of making a dfa */
+				/* anchor = 1 for anchored matches, else 0 */
 	Node *p, *p1;
 	fa *f;
 
@@ -139,7 +175,7 @@
 	poscnt = 0;
 	penter(p1);	/* enter parent pointers and leaf indices */
 	if ((f = (fa *)calloc(1, sizeof (fa) + poscnt * sizeof (rrow))) == NULL)
-		overflo("no room for fa");
+		overflo("out of space for fa");
 	/* penter has computed number of positions in re */
 	f->accept = poscnt-1;
 	cfoll(f, p1);	/* set up follow sets */
@@ -160,7 +196,7 @@
 static int
 makeinit(fa *f, int anchor)
 {
-	register int i, k;
+	int i, k;
 
 	f->curstat = 2;
 	f->out[2] = 0;
@@ -194,9 +230,10 @@
 penter(Node *p)	/* set up parent pointers and leaf indices */
 {
 	switch (type(p)) {
+	ELEAF
 	LEAF
-		left(p) = (Node *) poscnt;
-		point[poscnt++] = p;
+		info(p) = poscnt;
+		poscnt++;
 		break;
 	UNARY
 		penter(left(p));
@@ -209,8 +246,8 @@
 		parent(left(p)) = p;
 		parent(right(p)) = p;
 		break;
-	default:
-		ERROR "unknown type %d in penter", type(p) FATAL;
+	default:	/* can't happen */
+		FATAL("can't happen: unknown type %d in penter", type(p));
 		break;
 	}
 }
@@ -219,6 +256,7 @@
 freetr(Node *p)	/* free parse tree */
 {
 	switch (type(p)) {
+	ELEAF
 	LEAF
 		xfree(p);
 		break;
@@ -232,92 +270,158 @@
 		freetr(right(p));
 		xfree(p);
 		break;
-	default:
-		ERROR "unknown type %d in freetr", type(p) FATAL;
+	default:	/* can't happen */
+		FATAL("can't happen: unknown type %d in freetr", type(p));
 		break;
 	}
 }
 
+/*
+ * in the parsing of regular expressions, metacharacters like . have
+ * to be seen literally;  \056 is not a metacharacter.
+ */
+int
+hexstr(uchar **pp)	/* find and eval hex string at pp, return new p */
+{			/* only pick up one 8-bit byte (2 chars) */
+	uchar *p;
+	int n = 0;
+	int i;
+
+	for (i = 0, p = (uchar *)*pp; i < 2 && isxdigit(*p); i++, p++) {
+		if (isdigit(*p))
+			n = 16 * n + *p - '0';
+		else if (*p >= 'a' && *p <= 'f')
+			n = 16 * n + *p - 'a' + 10;
+		else if (*p >= 'A' && *p <= 'F')
+			n = 16 * n + *p - 'A' + 10;
+	}
+	*pp = (uchar *)p;
+	return (n);
+}
+
+/* multiple use of arg */
+#define	isoctdigit(c)	((c) >= '0' && (c) <= '7')
+
+int
+quoted(uchar **pp)	/* pick up next thing after a \\ */
+{			/* and increment *pp */
+
+	uchar *p = *pp;
+	int c;
+
+	if ((c = *p++) == 't')
+		c = '\t';
+	else if (c == 'n')
+		c = '\n';
+	else if (c == 'f')
+		c = '\f';
+	else if (c == 'r')
+		c = '\r';
+	else if (c == 'b')
+		c = '\b';
+	else if (c == '\\')
+		c = '\\';
+	else if (c == 'x') {	/* hexadecimal goo follows */
+		c = hexstr(&p);	/* this adds a null if number is invalid */
+	} else if (isoctdigit(c)) {	/* \d \dd \ddd */
+		int n = c - '0';
+		if (isoctdigit(*p)) {
+			n = 8 * n + *p++ - '0';
+			if (isoctdigit(*p))
+				n = 8 * n + *p++ - '0';
+		}
+		c = n;
+	} /* else */
+		/* c = c; */
+	*pp = p;
+	return (c);
+}
+
 uchar *
-cclenter(uchar *p)
+cclenter(const uchar *argp)		/* add a character class */
 {
-	register int i, c;
-	uchar *op, *chars, *ret;
-	size_t	bsize;
+	int i, c, c2;
+	uchar  *p = (uchar *)argp;
+	uchar *op, *bp;
+	static uchar *buf = NULL;
+	size_t	bufsz = 100;
 
-	init_buf(&chars, &bsize, LINE_INCR);
 	op = p;
-	i = 0;
-	while ((c = *p++) != 0) {
+	if (buf == 0 && (buf = (uchar *)malloc(bufsz)) == NULL)
+		FATAL("out of space for character class [%.10s...] 1", p);
+	bp = buf;
+	for (i = 0; (c = *p++) != 0; ) {
 		if (c == '\\') {
-			if ((c = *p++) == 't')
-				c = '\t';
-			else if (c == 'n')
-				c = '\n';
-			else if (c == 'f')
-				c = '\f';
-			else if (c == 'r')
-				c = '\r';
-			else if (c == 'b')
-				c = '\b';
-			else if (c == '\\')
-				c = '\\';
-			else if (isdigit(c)) {
-				int n = c - '0';
-				if (isdigit(*p)) {
-					n = 8 * n + *p++ - '0';
-					if (isdigit(*p))
-						n = 8 * n + *p++ - '0';
-				}
-				c = n;
-			} /* else */
-				/* c = c; */
-		} else if (c == '-' && i > 0 && chars[i-1] != 0) {
+			c = quoted(&p);
+		} else if (c == '-' && i > 0 && bp[-1] != 0) {
 			if (*p != 0) {
-				c = chars[i-1];
-				while ((uchar)c < *p) {	/* fails if *p is \\ */
-					expand_buf(&chars, &bsize, i);
-					chars[i++] = ++c;
+				c = bp[-1];
+				c2 = *p++;
+				if (c2 == '\\')
+					c2 = quoted(&p);
+				if (c > c2) {   /* empty; ignore */
+					bp--;
+					i--;
+					continue;
+				}
+				while (c < c2) {
+					if (adjbuf(&buf, &bufsz,
+					    bp - buf + 2, 100, &bp,
+					    "cclenter1") == 0)
+						FATAL(
+			"out of space for character class [%.10s...] 2", p);
+					*bp++ = ++c;
+					i++;
 				}
-				p++;
 				continue;
 			}
 		}
-		expand_buf(&chars, &bsize, i);
-		chars[i++] = c;
+		if (!adjbuf(&buf, &bufsz, bp-buf+2, 100, &bp, "cclenter2"))
+			FATAL(
+		"out of space for character class [%.10s...] 3", p);
+		*bp++ = c;
+		i++;
 	}
-	chars[i++] = '\0';
-	dprintf(("cclenter: in = |%s|, out = |%s|\n", op, chars));
+	*bp = 0;
+	dprintf(("cclenter: in = |%s|, out = |%s|\n", op, buf));
 	xfree(op);
-	ret = tostring(chars);
-	free(chars);
-	return (ret);
+	return (tostring(buf));
 }
 
 static void
-overflo(char *s)
+overflo(const char *s)
 {
-	ERROR "regular expression too big: %s", gettext((char *)s) FATAL;
+	FATAL("regular expression too big: %.30s...", gettext((char *)s));
 }
 
 /* enter follow set of each leaf of vertex v into lfollow[leaf] */
 static void
 cfoll(fa *f, Node *v)
 {
-	register int i;
-	register int *p;
+	int i;
+	int *p;
 
 	switch (type(v)) {
+	ELEAF
 	LEAF
-		f->re[(int)left(v)].ltype = type(v);
-		f->re[(int)left(v)].lval = (int)right(v);
+		f->re[info(v)].ltype = type(v);
+		f->re[info(v)].lval.np = right(v);
+		while (f->accept >= maxsetvec) {	/* guessing here! */
+			maxsetvec *= 4;
+			setvec = (int *)realloc(setvec, maxsetvec *
+			    sizeof (int));
+			tmpset = (int *)realloc(tmpset, maxsetvec *
+			    sizeof (int));
+			if (setvec == 0 || tmpset == 0)
+				overflo("out of space in cfoll()");
+		}
 		for (i = 0; i <= f->accept; i++)
 			setvec[i] = 0;
 		setcnt = 0;
 		follow(v);	/* computes setvec and setcnt */
 		if ((p = (int *)calloc(1, (setcnt+1) * sizeof (int))) == NULL)
-			overflo("follow set overflow");
-		f->re[(int)left(v)].lfollow = p;
+			overflo("out of space building follow set");
+		f->re[info(v)].lfollow = p;
 		*p = setcnt;
 		for (i = f->accept; i >= 0; i--) {
 			if (setvec[i] == 1)
@@ -332,8 +436,8 @@
 		cfoll(f, left(v));
 		cfoll(f, right(v));
 		break;
-	default:
-		ERROR "unknown type %d in cfoll", type(v) FATAL;
+	default:	/* can't happen */
+		FATAL("can't happen: unknown type %d in cfoll", type(v));
 	}
 }
 
@@ -344,12 +448,29 @@
 static int
 first(Node *p)
 {
-	register int b;
+	int b, lp;
 
 	switch (type(p)) {
+	ELEAF
 	LEAF
-		if (setvec[(int)left(p)] != 1) {
-			setvec[(int)left(p)] = 1;
+		/* look for high-water mark of subscripts */
+		lp = info(p);
+		/* guessing here! */
+		while (setcnt >= maxsetvec || lp >= maxsetvec) {
+			maxsetvec *= 4;
+			setvec = (int *)realloc(setvec, maxsetvec *
+			    sizeof (int));
+			tmpset = (int *)realloc(tmpset, maxsetvec *
+			    sizeof (int));
+			if (setvec == 0 || tmpset == 0)
+				overflo("out of space in first()");
+		}
+		if (type(p) == EMPTYRE) {
+			setvec[lp] = 0;
+			return (0);
+		}
+		if (setvec[lp] != 1) {
+			setvec[lp] = 1;
 			setcnt++;
 		}
 		if (type(p) == CCL && (*(uchar *)right(p)) == '\0')
@@ -374,7 +495,9 @@
 			return (0);
 		return (1);
 	}
-	ERROR "unknown type %d in first", type(p) FATAL;
+	/* can't happen */
+	FATAL("can't happen: unknown type %d in first", type(p));
+	/*NOTREACHED*/
 	return (-1);
 }
 
@@ -408,15 +531,14 @@
 		} else		/* v is right child */
 			follow(p);
 		return;
-	default:
-		ERROR "unknown type %d in follow", type(p) FATAL;
-		break;
 	}
 }
 
 static int
-member(uchar c, uchar *s)	/* is c in s? */
+member(int c, const uchar *sarg)	/* is c in s? */
 {
+	uchar *s = (uchar *)sarg;
+
 	while (*s)
 		if (c == *s++)
 			return (1);
@@ -425,14 +547,16 @@
 
 
 int
-match(fa *f, uchar *p)
+match(fa *f, const uchar *p0)	/* shortest match ? */
 {
-	register int s, ns;
+	int s, ns;
+	uchar *p = (uchar *)p0;
 
 	s = f->reset ? makeinit(f, 0) : f->initstat;
 	if (f->out[s])
 		return (1);
 	do {
+		/* assert(*p < NCHARS); */
 		if ((ns = f->gototab[s][*p]) != 0)
 			s = ns;
 		else
@@ -444,12 +568,14 @@
 }
 
 int
-pmatch(fa *f, uchar *p)
+pmatch(fa *f, const uchar *p0)		/* longest match, for sub */
 {
-	register int s, ns;
-	register uchar *q;
+	int s, ns;
+	uchar *p = (uchar *)p0;
+	uchar *q;
 	int i, k;
 
+	/* s = f->reset ? makeinit(f,1) : f->initstat; */
 	if (f->reset) {
 		f->initstat = s = makeinit(f, 1);
 	} else {
@@ -462,6 +588,7 @@
 		do {
 			if (f->out[s])		/* final state */
 				patlen = q-p;
+			/* assert(*q < NCHARS); */
 			if ((ns = f->gototab[s][*q]) != 0)
 				s = ns;
 			else
@@ -480,7 +607,7 @@
 			patbeg = p;
 			return (1);
 		}
-	nextin:
+nextin:
 		s = 2;
 		if (f->reset) {
 			for (i = 2; i <= f->curstat; i++)
@@ -502,12 +629,14 @@
 }
 
 int
-nematch(fa *f, uchar *p)
+nematch(fa *f, const uchar *p0)		/* non-empty match, for sub */
 {
-	register int s, ns;
-	register uchar *q;
+	int s, ns;
+	uchar *p = (uchar *)p0;
+	uchar *q;
 	int i, k;
 
+	/* s = f->reset ? makeinit(f,1) : f->initstat; */
 	if (f->reset) {
 		f->initstat = s = makeinit(f, 1);
 	} else {
@@ -518,7 +647,8 @@
 		q = p;
 		do {
 			if (f->out[s])		/* final state */
-				patlen = q-p;
+				patlen = q - p;
+			/* assert(*q < NCHARS); */
 			if ((ns = f->gototab[s][*q]) != 0)
 				s = ns;
 			else
@@ -537,7 +667,7 @@
 			patbeg = p;
 			return (1);
 		}
-	nnextin:
+nnextin:
 		s = 2;
 		if (f->reset) {
 			for (i = 2; i <= f->curstat; i++)
@@ -559,34 +689,32 @@
 	return (0);
 }
 
-static Node *regexp(void), *primary(void), *concat(Node *);
-static Node *alt(Node *), *unary(Node *);
-
 static Node *
-reparse(uchar *p)
+reparse(const uchar *p)
 {
 	/* parses regular expression pointed to by p */
 	/* uses relex() to scan regular expression */
 	Node *np;
 
 	dprintf(("reparse <%s>\n", p));
-	lastre = prestr = p;	/* prestr points to string to be parsed */
+	/* prestr points to string to be parsed */
+	lastre = prestr = (uchar *)p;
 	rtok = relex();
-	if (rtok == '\0')
-		ERROR "empty regular expression" FATAL;
-	np = regexp();
+	/* GNU compatibility: an empty regexp matches anything */
 	if (rtok == '\0') {
-		return (np);
-	} else {
-		ERROR "syntax error in regular expression %s at %s",
-		    lastre, prestr FATAL;
+		/* FATAL("empty regular expression"); previous */
+		return (op2(EMPTYRE, NIL, NIL));
 	}
-	/*NOTREACHED*/
-	return (NULL);
+	np = regexp();
+	if (rtok != '\0') {
+		FATAL("syntax error in regular expression %s at %s",
+		    lastre, prestr);
+	}
+	return (np);
 }
 
 static Node *
-regexp(void)
+regexp(void)	/* top-level parse of reg expr */
 {
 	return (alt(concat(primary())));
 }
@@ -598,12 +726,15 @@
 
 	switch (rtok) {
 	case CHAR:
-		np = op2(CHAR, NIL, (Node *)rlxval);
+		np = op2(CHAR, NIL, itonp(rlxval));
 		rtok = relex();
 		return (unary(np));
 	case ALL:
 		rtok = relex();
 		return (unary(op2(ALL, NIL, NIL)));
+	case EMPTYRE:
+		rtok = relex();
+		return (unary(op2(ALL, NIL, NIL)));
 	case DOT:
 		rtok = relex();
 		return (unary(op2(DOT, NIL, NIL)));
@@ -619,7 +750,7 @@
 		return (unary(np));
 	case '^':
 		rtok = relex();
-		return (unary(op2(CHAR, NIL, (Node *)HAT)));
+		return (unary(op2(CHAR, NIL, itonp(HAT))));
 	case '$':
 		rtok = relex();
 		return (unary(op2(CHAR, NIL, NIL)));
@@ -636,12 +767,12 @@
 			rtok = relex();
 			return (unary(np));
 		} else {
-			ERROR "syntax error in regular expression %s at %s",
-			    lastre, prestr FATAL;
+			FATAL("syntax error in regular expression %s at %s",
+			    lastre, prestr);
 		}
 	default:
-		ERROR "illegal primary in regular expression %s at %s",
-		    lastre, prestr FATAL;
+		FATAL("illegal primary in regular expression %s at %s",
+		    lastre, prestr);
 	}
 	/*NOTREACHED*/
 	return (NULL);
@@ -651,7 +782,8 @@
 concat(Node *np)
 {
 	switch (rtok) {
-	case CHAR: case DOT: case ALL: case CCL: case NCCL: case '$': case '(':
+	case CHAR: case DOT: case ALL: case EMPTYRE: case CCL: case NCCL:
+	case '$': case '(':
 		return (concat(op2(CAT, np, primary())));
 	default:
 		return (np);
@@ -686,12 +818,72 @@
 	}
 }
 
+/*
+ * Character class definitions conformant to the POSIX locale as
+ * defined in IEEE P1003.1 draft 7 of June 2001, assuming the source
+ * and operating character sets are both ASCII (ISO646) or supersets
+ * thereof.
+ *
+ * Note that to avoid overflowing the temporary buffer used in
+ * relex(), the expanded character class (prior to range expansion)
+ * must be less than twice the size of their full name.
+ */
+
+/*
+ * Because isblank doesn't show up in any of the header files on any
+ * system i use, it's defined here.  if some other locale has a richer
+ * definition of "blank", define HAS_ISBLANK and provide your own
+ * version.
+ * the parentheses here are an attempt to find a path through the maze
+ * of macro definition and/or function and/or version provided.  thanks
+ * to nelson beebe for the suggestion; let's see if it works everywhere.
+ */
+
+/* #define HAS_ISBLANK */
+#ifndef	HAS_ISBLANK
+
+int
+(xisblank)(int c)
+{
+	return (c == ' ' || c == '\t');
+}
+
+#endif
+
+struct charclass {
+	const char *cc_name;
+	int cc_namelen;
+	int (*cc_func)(int);
+} charclasses[] = {
+	{ "alnum",	5,	isalnum },
+	{ "alpha",	5,	isalpha },
+#ifndef	HAS_ISBLANK
+	{ "blank",	5,	isspace }, /* was isblank */
+#else
+	{ "blank",	5,	isblank },
+#endif
+	{ "cntrl",	5,	iscntrl },
+	{ "digit",	5,	isdigit },
+	{ "graph",	5,	isgraph },
+	{ "lower",	5,	islower },
+	{ "print",	5,	isprint },
+	{ "punct",	5,	ispunct },
+	{ "space",	5,	isspace },
+	{ "upper",	5,	isupper },
+	{ "xdigit",	6,	isxdigit },
+	{ NULL,		0,	NULL },
+};
+
 static int
 relex(void)		/* lexical analyzer for reparse */
 {
-	register int c;
-	uchar *cbuf;
-	int clen, cflag;
+	int c, n;
+	int cflag;
+	uchar *buf = 0;
+	size_t bufsz = 100;
+	uchar *bp;
+	struct charclass *cc;
+	int i;
 
 	switch (c = *prestr++) {
 	case '|': return OR;
@@ -706,64 +898,72 @@
 	case ')':
 		return (c);
 	case '\\':
-		if ((c = *prestr++) == 't')
-			c = '\t';
-		else if (c == 'n')
-			c = '\n';
-		else if (c == 'f')
-			c = '\f';
-		else if (c == 'r')
-			c = '\r';
-		else if (c == 'b')
-			c = '\b';
-		else if (c == '\\')
-			c = '\\';
-		else if (isdigit(c)) {
-			int n = c - '0';
-			if (isdigit(*prestr)) {
-				n = 8 * n + *prestr++ - '0';
-				if (isdigit(*prestr))
-					n = 8 * n + *prestr++ - '0';
-			}
-			c = n;
-		} /* else it's now in c */
-		rlxval = c;
+		rlxval = quoted(&prestr);
 		return (CHAR);
 	default:
 		rlxval = c;
 		return (CHAR);
 	case '[':
-		clen = 0;
+		if (buf == 0 && (buf = (uchar *)malloc(bufsz)) == NULL)
+			FATAL("out of space in reg expr %.10s..", lastre);
+		bp = buf;
 		if (*prestr == '^') {
 			cflag = 1;
 			prestr++;
 		} else
 			cflag = 0;
-		init_buf(&cbuf, NULL, strlen((char *)prestr) * 2 + 1);
+		n = 2 * strlen((const char *) prestr)+1;
+		if (!adjbuf(&buf, &bufsz, n, n, &bp, "relex1"))
+			FATAL("out of space for reg expr %.10s...", lastre);
 		for (;;) {
 			if ((c = *prestr++) == '\\') {
-				cbuf[clen++] = '\\';
+				*bp++ = '\\';
 				if ((c = *prestr++) == '\0') {
-					ERROR
-			"nonterminated character class %s", lastre FATAL;
+					FATAL(
+			"nonterminated character class %s", lastre);
 				}
-				cbuf[clen++] = c;
+				*bp++ = c;
+			} else if (c == '[' && *prestr == ':') {
+				/*
+				 * POSIX char class names, Dag-Erling
+				 * Smorgrav, des@ofug.org
+				 */
+				for (cc = charclasses; cc->cc_name; cc++)
+					if (strncmp((const char *) prestr + 1,
+					    (const char *) cc->cc_name,
+					    cc->cc_namelen) == 0)
+						break;
+				if (cc->cc_name != NULL &&
+				    prestr[1 + cc->cc_namelen] == ':' &&
+				    prestr[2 + cc->cc_namelen] == ']') {
+					prestr += cc->cc_namelen + 3;
+					for (i = 0; i < NCHARS; i++) {
+						if (!adjbuf(&buf, &bufsz,
+						    bp - buf + 1, 100, &bp,
+						    "relex2"))
+							FATAL(
+				"out of space for reg expr %.10s...", lastre);
+						if (cc->cc_func(i)) {
+							*bp++ = i;
+							n++;
+						}
+					}
+				} else
+					*bp++ = c;
+			} else if (c == '\0') {
+				FATAL("nonterminated character class %.20s",
+				    lastre);
+			} else if (bp == buf) { /* 1st char is special */
+				*bp++ = c;
 			} else if (c == ']') {
-				cbuf[clen] = 0;
-				rlxstr = tostring(cbuf);
-				free(cbuf);
+				*bp++ = 0;
+				rlxstr = tostring(buf);
 				if (cflag == 0)
 					return (CCL);
 				else
 					return (NCCL);
-			} else if (c == '\n') {
-				ERROR "newline in character class %s...",
-				    lastre FATAL;
-			} else if (c == '\0') {
-				ERROR "nonterminated character class %s",
-				    lastre FATAL;
 			} else
-				cbuf[clen++] = c;
+				*bp++ = c;
 		}
 		/*NOTREACHED*/
 	}
@@ -773,9 +973,17 @@
 static int
 cgoto(fa *f, int s, int c)
 {
-	register int i, j, k;
-	register int *p, *q;
+	int i, j, k;
+	int *p, *q;
 
+	assert(c == HAT || c < NCHARS);
+	while (f->accept >= maxsetvec) {	/* guessing here! */
+		maxsetvec *= 4;
+		setvec = (int *)realloc(setvec, maxsetvec * sizeof (int));
+		tmpset = (int *)realloc(tmpset, maxsetvec * sizeof (int));
+		if (setvec == 0 || tmpset == 0)
+			overflo("out of space in cgoto()");
+	}
 	for (i = 0; i <= f->accept; i++)
 		setvec[i] = 0;
 	setcnt = 0;
@@ -783,16 +991,28 @@
 	p = f->posns[s];
 	for (i = 1; i <= *p; i++) {
 		if ((k = f->re[p[i]].ltype) != FINAL) {
-			if (k == CHAR && c == f->re[p[i]].lval ||
-			    k == DOT && c != 0 && c != HAT ||
-			    k == ALL && c != 0 ||
-			    k == CCL &&
-			    member(c, (uchar *)f->re[p[i]].lval) ||
-			    k == NCCL &&
-			    !member(c, (uchar *)f->re[p[i]].lval) &&
-			    c != 0 && c != HAT) {
+			if ((k == CHAR && c == ptoi(f->re[p[i]].lval.np)) ||
+			    (k == DOT && c != 0 && c != HAT) ||
+			    (k == ALL && c != 0) ||
+			    (k == EMPTYRE && c != 0) ||
+			    (k == CCL &&
+			    member(c, (uchar *)f->re[p[i]].lval.up)) ||
+			    ((k == NCCL &&
+			    !member(c, (uchar *)f->re[p[i]].lval.up)) &&
+			    c != 0 && c != HAT)) {
 				q = f->re[p[i]].lfollow;
 				for (j = 1; j <= *q; j++) {
+					if (q[j] >= maxsetvec) {
+						maxsetvec *= 4;
+						setvec = (int *)realloc(setvec,
+						    maxsetvec * sizeof (int));
+						tmpset = (int *)realloc(tmpset,
+						    maxsetvec * sizeof (int));
+						if (setvec == 0 ||
+						    tmpset == 0)
+							overflo(
+						"cgoto overflow");
+					}
 					if (setvec[q[j]] == 0) {
 						setcnt++;
 						setvec[q[j]] = 1;
@@ -823,7 +1043,7 @@
 	}
 
 	/* add tmpset to current set of states */
-	if (f->curstat >= NSTATES-1) {
+	if (f->curstat >= NSTATES - 1) {
 		f->curstat = 2;
 		f->reset = 1;
 		for (i = 2; i < NSTATES; i++)
@@ -848,17 +1068,19 @@
 }
 
 static void
-freefa(fa *f)
+freefa(fa *f)	/* free a finite automaton */
 {
-
-	register int i;
+	int i;
 
 	if (f == NULL)
 		return;
 	for (i = 0; i <= f->curstat; i++)
 		xfree(f->posns[i]);
-	for (i = 0; i <= f->accept; i++)
+	for (i = 0; i <= f->accept; i++) {
 		xfree(f->re[i].lfollow);
+		if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL)
+			xfree((f->re[i].lval.np));
+	}
 	xfree(f->restr);
 	xfree(f);
 }
--- /dev/null	2013-05-11 15:20:44.000000000 +0000
+++ new/usr/src/cmd/awk/lex.c	2013-05-11 15:20:44.006492191 +0000
@@ -0,0 +1,611 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "awk.h"
+#include "y.tab.h"
+
+extern YYSTYPE	yylval;
+extern int	infunc;
+
+off_t	lineno	= 1;
+int	bracecnt = 0;
+int	brackcnt  = 0;
+int	parencnt = 0;
+
+typedef struct Keyword {
+	const char *word;
+	int	sub;
+	int	type;
+} Keyword;
+
+Keyword keywords[] = {	/* keep sorted: binary searched */
+	{ "BEGIN",	XBEGIN,		XBEGIN },
+	{ "END",	XEND,		XEND },
+	{ "NF",		VARNF,		VARNF },
+	{ "atan2",	FATAN,		BLTIN },
+	{ "break",	BREAK,		BREAK },
+	{ "close",	CLOSE,		CLOSE },
+	{ "continue",	CONTINUE,	CONTINUE },
+	{ "cos",	FCOS,		BLTIN },
+	{ "delete",	DELETE,		DELETE },
+	{ "do",		DO,		DO },
+	{ "else",	ELSE,		ELSE },
+	{ "exit",	EXIT,		EXIT },
+	{ "exp",	FEXP,		BLTIN },
+	{ "fflush",	FFLUSH,		BLTIN },
+	{ "for",	FOR,		FOR },
+	{ "func",	FUNC,		FUNC },
+	{ "function",	FUNC,		FUNC },
+	{ "getline",	GETLINE,	GETLINE },
+	{ "gsub",	GSUB,		GSUB },
+	{ "if",		IF,		IF },
+	{ "in",		IN,		IN },
+	{ "index",	INDEX,		INDEX },
+	{ "int",	FINT,		BLTIN },
+	{ "length",	FLENGTH,	BLTIN },
+	{ "log",	FLOG,		BLTIN },
+	{ "match",	MATCHFCN,	MATCHFCN },
+	{ "next",	NEXT,		NEXT },
+	{ "nextfile",	NEXTFILE,	NEXTFILE },
+	{ "print",	PRINT,		PRINT },
+	{ "printf",	PRINTF,		PRINTF },
+	{ "rand",	FRAND,		BLTIN },
+	{ "return",	RETURN,		RETURN },
+	{ "sin",	FSIN,		BLTIN },
+	{ "split",	SPLIT,		SPLIT },
+	{ "sprintf",	SPRINTF,	SPRINTF },
+	{ "sqrt",	FSQRT,		BLTIN },
+	{ "srand",	FSRAND,		BLTIN },
+	{ "sub",	SUB,		SUB },
+	{ "substr",	SUBSTR,		SUBSTR },
+	{ "system",	FSYSTEM,	BLTIN },
+	{ "tolower",	FTOLOWER,	BLTIN },
+	{ "toupper",	FTOUPPER,	BLTIN },
+	{ "while",	WHILE,		WHILE },
+};
+
+#define	RET(x)	{ if (dbg) (void) printf("lex %s\n", tokname(x)); return (x); }
+
+static int
+peek(void)
+{
+	int c = input();
+	unput(c);
+	return (c);
+}
+
+static int
+gettok(uchar **pbuf, int *psz)	/* get next input token */
+{
+	int c, retc;
+	uchar *buf = *pbuf;
+	size_t sz = *psz;
+	uchar *bp = buf;
+
+	c = input();
+	if (c == 0)
+		return (0);
+	buf[0] = c;
+	buf[1] = 0;
+	if (!isalnum(c) && c != '.' && c != '_')
+		return (c);
+
+	*bp++ = c;
+	if (isalpha(c) || c == '_') {	/* it's a varname */
+		for (; (c = input()) != 0; ) {
+			if (bp-buf >= sz)
+				if (!adjbuf(&buf, &sz, bp - buf + 2, 100,
+				    &bp, "gettok"))
+					FATAL(
+				"out of space for name %.10s...", buf);
+			if (isalnum(c) || c == '_')
+				*bp++ = c;
+			else {
+				*bp = 0;
+				unput(c);
+				break;
+			}
+		}
+		*bp = 0;
+		retc = 'a';	/* alphanumeric */
+	} else {	/* maybe it's a number, but could be . */
+		char *rem;
+		/* read input until can't be a number */
+		for (; (c = input()) != 0; ) {
+			if (bp-buf >= sz)
+				if (!adjbuf(&buf, &sz, bp - buf + 2, 100,
+				    &bp, "gettok"))
+					FATAL(
+				"out of space for number %.10s...", buf);
+			if (isdigit(c) || c == 'e' || c == 'E' ||
+			    c == '.' || c == '+' || c == '-')
+				*bp++ = c;
+			else {
+				unput(c);
+				break;
+			}
+		}
+		*bp = 0;
+		(void) strtod((char *)buf, &rem);	/* parse the number */
+		/* it wasn't a valid number at all */
+		if (rem == (char *)buf) {
+			buf[1] = 0;	/* return one character as token */
+			retc = buf[0];	/* character is its own type */
+			unputstr(rem+1); /* put rest back for later */
+		} else {	/* some prefix was a number */
+			unputstr(rem);	/* put rest back for later */
+			rem[0] = 0;	/* truncate buf after number part */
+			retc = '0';	/* type is number */
+		}
+	}
+	*pbuf = buf;
+	*psz = sz;
+	return (retc);
+}
+
+int	word(char *);
+int	string(void);
+int	regexpr(void);
+int	sc	= 0;	/* 1 => return a } right now */
+int	reg	= 0;	/* 1 => return a REGEXPR now */
+
+int
+yylex(void)
+{
+	int c;
+	static uchar *buf = 0;
+	static int bufsize = 5; /* BUG: setting this small causes core dump! */
+
+	if (buf == 0 && (buf = (uchar *)malloc(bufsize)) == NULL)
+		FATAL("out of space in yylex");
+	if (sc) {
+		sc = 0;
+		RET('}');
+	}
+	if (reg) {
+		reg = 0;
+		return (regexpr());
+	}
+	for (;;) {
+		c = gettok(&buf, &bufsize);
+		if (c == 0)
+			return (0);
+		if (isalpha(c) || c == '_')
+			return (word((char *)buf));
+		if (isdigit(c)) {
+			yylval.cp = setsymtab(buf, tostring(buf),
+			    atof((char *)buf), CON|NUM, symtab);
+			/* should this also have STR set? */
+			RET(NUMBER);
+		}
+
+		yylval.i = c;
+		switch (c) {
+		case '\n':	/* {EOL} */
+			RET(NL);
+		case '\r':	/* assume \n is coming */
+		case ' ':	/* {WS}+ */
+		case '\t':
+			break;
+		case '#':	/* #.* strip comments */
+			while ((c = input()) != '\n' && c != 0)
+				;
+			unput(c);
+			break;
+		case ';':
+			RET(';');
+		case '\\':
+			if (peek() == '\n') {
+				(void) input();
+			} else if (peek() == '\r') {
+				(void) input();
+				(void) input();	/* \n */
+				lineno++;
+			} else {
+				RET(c);
+			}
+			break;
+		case '&':
+			if (peek() == '&') {
+				(void) input(); RET(AND);
+			} else
+				RET('&');
+		case '|':
+			if (peek() == '|') {
+				(void) input(); RET(BOR);
+			} else
+				RET('|');
+		case '!':
+			if (peek() == '=') {
+				(void) input(); yylval.i = NE; RET(NE);
+			} else if (peek() == '~') {
+				(void) input(); yylval.i = NOTMATCH;
+				RET(MATCHOP);
+			} else
+				RET(NOT);
+		case '~':
+			yylval.i = MATCH;
+			RET(MATCHOP);
+		case '<':
+			if (peek() == '=') {
+				(void) input(); yylval.i = LE; RET(LE);
+			} else {
+				yylval.i = LT; RET(LT);
+			}
+		case '=':
+			if (peek() == '=') {
+				(void) input(); yylval.i = EQ; RET(EQ);
+			} else {
+				yylval.i = ASSIGN; RET(ASGNOP);
+			}
+		case '>':
+			if (peek() == '=') {
+				(void) input(); yylval.i = GE; RET(GE);
+			} else if (peek() == '>') {
+				(void) input(); yylval.i = APPEND; RET(APPEND);
+			} else {
+				yylval.i = GT; RET(GT);
+			}
+		case '+':
+			if (peek() == '+') {
+				(void) input(); yylval.i = INCR; RET(INCR);
+			} else if (peek() == '=') {
+				(void) input(); yylval.i = ADDEQ; RET(ASGNOP);
+			} else
+				RET('+');
+		case '-':
+			if (peek() == '-') {
+				(void) input(); yylval.i = DECR; RET(DECR);
+			} else if (peek() == '=') {
+				(void) input(); yylval.i = SUBEQ; RET(ASGNOP);
+			} else
+				RET('-');
+		case '*':
+			if (peek() == '=') {	/* *= */
+				(void) input(); yylval.i = MULTEQ; RET(ASGNOP);
+			} else if (peek() == '*') {	/* ** or **= */
+				(void) input();	/* eat 2nd * */
+				if (peek() == '=') {
+					(void) input(); yylval.i = POWEQ;
+					RET(ASGNOP);
+				} else {
+					RET(POWER);
+				}
+			} else
+				RET('*');
+		case '/':
+			RET('/');
+		case '%':
+			if (peek() == '=') {
+				(void) input(); yylval.i = MODEQ; RET(ASGNOP);
+			} else
+				RET('%');
+		case '^':
+			if (peek() == '=') {
+				(void) input(); yylval.i = POWEQ; RET(ASGNOP);
+			} else
+				RET(POWER);
+
+		case '$':
+			/* BUG: awkward, if not wrong */
+			c = gettok(&buf, &bufsize);
+			if (isalpha(c)) {
+				/* very special */
+				if (strcmp((char *)buf, "NF") == 0) {
+					unputstr("(NF)");
+					RET(INDIRECT);
+				}
+				c = peek();
+				if (c == '(' || c == '[' ||
+				    (infunc && isarg(buf) >= 0)) {
+					unputstr((char *)buf);
+					RET(INDIRECT);
+				}
+				yylval.cp = setsymtab(buf, (uchar *)"", 0.0,
+				    STR | NUM, symtab);
+				RET(IVAR);
+			} else if (c == 0) {	/*  */
+				SYNTAX("unexpected end of input after $");
+				RET(';');
+			} else {
+				unputstr((char *)buf);
+				RET(INDIRECT);
+			}
+
+		case '}':
+			if (--bracecnt < 0)
+				SYNTAX("extra }");
+			sc = 1;
+			RET(';');
+		case ']':
+			if (--brackcnt < 0)
+				SYNTAX("extra ]");
+			RET(']');
+		case ')':
+			if (--parencnt < 0)
+				SYNTAX("extra )");
+			RET(')');
+		case '{':
+			bracecnt++;
+			RET('{');
+		case '[':
+			brackcnt++;
+			RET('[');
+		case '(':
+			parencnt++;
+			RET('(');
+
+		case '"':
+			/* BUG: should be like tran.c ? */
+			return (string());
+
+		default:
+			RET(c);
+		}
+	}
+}
+
+int
+string(void)
+{
+	int c, n;
+	uchar *s, *bp;
+	static uchar *buf = NULL;
+	static size_t bufsz = 500;
+
+	if (buf == 0 && (buf = (uchar *)malloc(bufsz)) == NULL)
+		FATAL("out of space for strings");
+	for (bp = buf; (c = input()) != '"'; ) {
+		if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
+			FATAL("out of space for string %.10s...", buf);
+		switch (c) {
+		case '\n':
+		case '\r':
+		case 0:
+			SYNTAX("non-terminated string %.10s...", buf);
+			lineno++;
+			if (c == 0)	/* hopeless */
+				FATAL("giving up");
+			break;
+		case '\\':
+			c = input();
+			switch (c) {
+			case '"': *bp++ = '"'; break;
+			case 'n': *bp++ = '\n'; break;
+			case 't': *bp++ = '\t'; break;
+			case 'f': *bp++ = '\f'; break;
+			case 'r': *bp++ = '\r'; break;
+			case 'b': *bp++ = '\b'; break;
+			case 'v': *bp++ = '\v'; break;
+			case 'a': *bp++ = '\007'; break;
+			case '\\': *bp++ = '\\'; break;
+
+			case '0': case '1': case '2': /* octal: \d \dd \ddd */
+			case '3': case '4': case '5': case '6': case '7':
+				n = c - '0';
+				if ((c = peek()) >= '0' && c < '8') {
+					n = 8 * n + input() - '0';
+					if ((c = peek()) >= '0' && c < '8')
+						n = 8 * n + input() - '0';
+				}
+				*bp++ = n;
+				break;
+
+			case 'x': {	/* hex  \x0-9a-fA-F + */
+				char xbuf[100], *px;
+		for (px = xbuf; (c = input()) != 0 && px - xbuf < 100 - 2; ) {
+					if (isdigit(c) ||
+					    (c >= 'a' && c <= 'f') ||
+					    (c >= 'A' && c <= 'F'))
+						*px++ = c;
+					else
+						break;
+				}
+				*px = 0;
+				unput(c);
+				(void) sscanf(xbuf, "%x", (unsigned int *)&n);
+				*bp++ = n;
+				break;
+			}
+
+			default:
+				*bp++ = c;
+				break;
+			}
+			break;
+		default:
+			*bp++ = c;
+			break;
+		}
+	}
+	*bp = 0;
+	s = tostring(buf);
+	*bp++ = ' '; *bp++ = 0;
+	yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
+	RET(STRING);
+}
+
+
+int
+binsearch(char *w, Keyword *kp, int n)
+{
+	int cond, low, mid, high;
+
+	low = 0;
+	high = n - 1;
+	while (low <= high) {
+		mid = (low + high) / 2;
+		if ((cond = strcmp(w, kp[mid].word)) < 0)
+			high = mid - 1;
+		else if (cond > 0)
+			low = mid + 1;
+		else
+			return (mid);
+	}
+	return (-1);
+}
+
+int
+word(char *w)
+{
+	Keyword *kp;
+	int c, n;
+
+	n = binsearch(w, keywords, sizeof (keywords) / sizeof (keywords[0]));
+	/*
+	 * BUG: this ought to be inside the if;
+	 * in theory could fault (daniel barrett)
+	 */
+	kp = keywords + n;
+	if (n != -1) {	/* found in table */
+		yylval.i = kp->sub;
+		switch (kp->type) {	/* special handling */
+		case BLTIN:
+			if (kp->sub == FSYSTEM && safe)
+				SYNTAX("system is unsafe");
+			RET(kp->type);
+		case FUNC:
+			if (infunc)
+				SYNTAX("illegal nested function");
+			RET(kp->type);
+		case RETURN:
+			if (!infunc)
+				SYNTAX("return not in function");
+			RET(kp->type);
+		case VARNF:
+			yylval.cp = setsymtab((uchar *)"NF", (uchar *)"", 0.0,
+			    NUM, symtab);
+			RET(VARNF);
+		default:
+			RET(kp->type);
+		}
+	}
+	c = peek();	/* look for '(' */
+	if (c != '(' && infunc && (n = isarg((uchar *)w)) >= 0) {
+		yylval.i = n;
+		RET(ARG);
+	} else {
+		yylval.cp = setsymtab((uchar *)w, (uchar *)"", 0.0,
+		    STR | NUM | DONTFREE, symtab);
+		if (c == '(') {
+			RET(CALL);
+		} else {
+			RET(VAR);
+		}
+	}
+}
+
+void
+startreg(void)	/* next call to yylex will return a regular expression */
+{
+	reg = 1;
+}
+
+int
+regexpr(void)
+{
+	int c;
+	static uchar *buf = NULL;
+	static size_t bufsz = 500;
+	uchar *bp;
+
+	if (buf == 0 && (buf = (uchar *)malloc(bufsz)) == NULL)
+		FATAL("out of space for rex expr");
+	bp = buf;
+	for (; (c = input()) != '/' && c != 0; ) {
+		if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
+			FATAL("out of space for reg expr %.10s...", buf);
+		if (c == '\n') {
+			SYNTAX("newline in regular expression %.10s...", buf);
+			unput('\n');
+			break;
+		} else if (c == '\\') {
+			*bp++ = '\\';
+			*bp++ = input();
+		} else {
+			*bp++ = c;
+		}
+	}
+	*bp = 0;
+	if (c == 0)
+		SYNTAX("non-terminated regular expression %.10s...", buf);
+	yylval.s = tostring(buf);
+	unput('/');
+	RET(REGEXPR);
+}
+
+/* low-level lexical stuff, sort of inherited from lex */
+
+char	ebuf[300];
+char	*ep = ebuf;
+char	yysbuf[100];	/* pushback buffer */
+char	*yysptr = yysbuf;
+FILE	*yyin = 0;
+
+int
+input(void)	/* get next lexical input character */
+{
+	int c;
+	extern uchar *lexprog;
+
+	if (yysptr > yysbuf)
+		c = (uchar)*--yysptr;
+	else if (lexprog != NULL) {	/* awk '...' */
+		if ((c = (uchar)*lexprog) != 0)
+			lexprog++;
+	} else				/* awk -f ... */
+		c = pgetc();
+	if (c == '\n')
+		lineno++;
+	else if (c == EOF)
+		c = 0;
+	if (ep >= ebuf + sizeof (ebuf))
+		ep = ebuf;
+	return (*ep++ = c);
+}
+
+void
+unput(int c)	/* put lexical character back on input */
+{
+	if (c == '\n')
+		lineno--;
+	if (yysptr >= yysbuf + sizeof (yysbuf))
+		FATAL("pushed back too much: %.20s...", yysbuf);
+	*yysptr++ = c;
+	if (--ep < ebuf)
+		ep = ebuf + sizeof (ebuf) - 1;
+}
+
+void
+unputstr(const char *s)	/* put a string back on input */
+{
+	int i;
+
+	for (i = strlen(s)-1; i >= 0; i--)
+		unput(s[i]);
+}
--- old/usr/src/cmd/awk/lib.c	2013-05-11 15:20:44.184563151 +0000
+++ new/usr/src/cmd/awk/lib.c	2013-05-11 15:20:44.192954240 +0000
@@ -24,34 +24,55 @@
  * 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.
+ */
 
 #include <errno.h>
+#include <stdarg.h>
+#include <math.h>
 #include "awk.h"
 #include "y.tab.h"
 
 uchar	*record;
-size_t	record_size;
+size_t	record_size = RECSIZE;
+
+Cell	**fldtab;	/* pointers to Cells */
+char	inputFS[100] = " ";
+
+#define	MAXFLD	2
+int	nfields = MAXFLD;	/* last allocated slot for $i */
 
 int	donefld;	/* 1 = implies rec broken into fields */
 int	donerec;	/* 1 = record is valid (no flds have changed) */
 
-static struct fldtab_chunk {
-	struct fldtab_chunk	*next;
-	Cell			fields[FLD_INCR];
-} *fldtab_head, *fldtab_tail;
-
-static	size_t	fldtab_maxidx;
+int	lastfld = 0;	/* last used field */
 
 static FILE	*infile	= NULL;
 static uchar	*file	= (uchar*) "";
 static uchar	*fields;
-static size_t	fields_size = LINE_INCR;
+static size_t	fields_size = RECSIZE;
 
-static int	maxfld	= 0;	/* last used field */
 static int	argno	= 1;	/* current input argument number */
 
 static	uchar	*getargv(int);
@@ -60,6 +81,42 @@
 static	void	bcheck2(int, int, int);
 static	void	eprint(void);
 static	void	bclass(int);
+static	void	makefields(int, int);
+
+
+static Cell dollar0 = { OCELL, CFLD, NULL, (uchar *)"", 0.0, REC|STR|DONTFREE };
+static Cell dollar1 = { OCELL, CFLD, NULL, (uchar *)"", 0.0, FLD|STR|DONTFREE };
+
+void
+recinit(unsigned int n)
+{
+	if ((record = (uchar *)malloc(n)) == NULL ||
+	    (fields = (uchar *)malloc(n+1)) == NULL ||
+	    (fldtab = (Cell **)malloc((nfields + 1) *
+	    sizeof (Cell *))) == NULL ||
+	    (fldtab[0] = (Cell *)malloc(sizeof (Cell))) == NULL)
+		FATAL("out of space for $0 and fields");
+	*fldtab[0] = dollar0;
+	fldtab[0]->sval = record;
+	fldtab[0]->nval = tostring((uchar *)"0");
+	makefields(1, nfields);
+}
+
+static void
+makefields(int n1, int n2)	/* create $n1..$n2 inclusive */
+{
+	char temp[50];
+	int i;
+
+	for (i = n1; i <= n2; i++) {
+		fldtab[i] = (Cell *)malloc(sizeof (struct Cell));
+		if (fldtab[i] == NULL)
+			FATAL("out of space in makefields %d", i);
+		*fldtab[i] = dollar1;
+		(void) sprintf(temp, "%d", i);
+		fldtab[i]->nval = tostring((uchar *)temp);
+	}
+}
 
 static void
 initgetrec(void)
@@ -68,22 +125,31 @@
 	uchar *p;
 
 	for (i = 1; i < *ARGC; i++) {
-		if (!isclvar(p = getargv(i)))	/* find 1st real filename */
+		p = getargv(i);	/* find 1st real filename */
+		if (p == NULL || *p == '\0') {	/* deleted or zapped */
+			argno++;
+			continue;
+		}
+		if (!isclvar(p)) {
+			(void) setsval(lookup((uchar *)"FILENAME", symtab), p);
 			return;
+		}
 		setclvar(p);	/* a commandline assignment before filename */
 		argno++;
 	}
 	infile = stdin;		/* no filenames, so use stdin */
-	/* *FILENAME = file = (uchar*) "-"; */
 }
 
+static int firsttime = 1;
+
 int
-getrec(uchar **bufp, size_t *bufsizep)
-{
+getrec(uchar **pbuf, size_t *pbufsize, int isrecord)
+{				/* get next input record */
+				/* note: cares whether buf == record */
 	int c;
-	static int firsttime = 1;
-	uchar_t	*buf, *nbuf;
-	size_t	len;
+	uchar_t	*buf = *pbuf;
+	uchar saveb0;
+	size_t bufsize = *pbufsize, savebufsize = bufsize;
 
 	if (firsttime) {
 		firsttime = 0;
@@ -91,13 +157,18 @@
 	}
 	dprintf(("RS=<%s>, FS=<%s>, ARGC=%f, FILENAME=%s\n",
 	    *RS, *FS, *ARGC, *FILENAME));
-	donefld = 0;
-	donerec = 1;
+	if (isrecord) {
+		donefld = 0;
+		donerec = 1;
+	}
+	saveb0 = buf[0];
+	buf[0] = 0;
 	while (argno < *ARGC || infile == stdin) {
 		dprintf(("argno=%d, file=|%s|\n", argno, file));
 		if (infile == NULL) {	/* have to open a new file */
 			file = getargv(argno);
-			if (*file == '\0') {	/* it's been zapped */
+			/* deleted or zapped */
+			if (file == NULL || *file == '\0') {
 				argno++;
 				continue;
 			}
@@ -111,30 +182,26 @@
 			if (*file == '-' && *(file+1) == '\0')
 				infile = stdin;
 			else if ((infile = fopen((char *)file, "r")) == NULL)
-				ERROR "can't open file %s", file FATAL;
+				FATAL("can't open file %s", file);
 			(void) setfval(fnrloc, 0.0);
 		}
-		c = readrec(&nbuf, &len, infile);
-		expand_buf(bufp, bufsizep, len);
-		buf = *bufp;
-		(void) memcpy(buf, nbuf, len);
-		buf[len] = '\0';
-		free(nbuf);
-
+		c = readrec(&buf, &bufsize, infile);
 		if (c != 0 || buf[0] != '\0') {	/* normal record */
-			if (bufp == &record) {
-				if (!(recloc->tval & DONTFREE))
-					xfree(recloc->sval);
-				recloc->sval = record;
-				recloc->tval = REC | STR | DONTFREE;
-				if (is_number(recloc->sval)) {
-					recloc->fval =
-					    atof((const char *)recloc->sval);
-					recloc->tval |= NUM;
+			if (isrecord) {
+				if (freeable(fldtab[0]))
+					xfree(fldtab[0]->sval);
+				fldtab[0]->sval = buf;	/* buf == record */
+				fldtab[0]->tval = REC | STR | DONTFREE;
+				if (is_number(fldtab[0]->sval)) {
+					fldtab[0]->fval =
+					    atof((const char *)fldtab[0]->sval);
+					fldtab[0]->tval |= NUM;
 				}
 			}
 			(void) setfval(nrloc, nrloc->fval+1);
 			(void) setfval(fnrloc, fnrloc->fval+1);
+			*pbuf = buf;
+			*pbufsize = bufsize;
 			return (1);
 		}
 		/* EOF arrived on this file; set up next */
@@ -143,18 +210,40 @@
 		infile = NULL;
 		argno++;
 	}
+	buf[0] = saveb0;
+	*pbuf = buf;
+	*pbufsize = savebufsize;
 	return (0);	/* true end of file */
 }
 
+void
+nextfile(void)
+{
+	if (infile != NULL && infile != stdin)
+		(void) fclose(infile);
+	infile = NULL;
+	argno++;
+}
+
+/*
+ * read one record into buf
+ */
 int
-readrec(uchar **bufp, size_t *sizep, FILE *inf)	/* read one record into buf */
+readrec(uchar **pbuf, size_t *pbufsize, FILE *inf)
 {
 	int sep, c;
-	uchar	*buf;
-	int	count;
-	size_t	bufsize;
+	uchar *rr, *buf = *pbuf;
+	size_t bufsize = *pbufsize;
+
+	if (strlen((char *)*FS) >= sizeof (inputFS))
+		FATAL("field separator %.10s... is too long", *FS);
+	/*
+	 * fflush(stdout); avoids some buffering problem
+	 * but makes it 25% slower
+	 */
 
-	init_buf(&buf, &bufsize, LINE_INCR);
+	/* for subsequent field splitting */
+	(void) strcpy(inputFS, (char *)*FS);
 	if ((sep = **RS) == 0) {
 		sep = '\n';
 		/* skip leading \n's */
@@ -163,37 +252,45 @@
 		if (c != EOF)
 			(void) ungetc(c, inf);
 	}
-	count = 0;
-	for (;;) {
-		while ((c = getc(inf)) != sep && c != EOF) {
-			expand_buf(&buf, &bufsize, count);
-			buf[count++] = c;
+	for (rr = buf; ; ) {
+		for (; (c = getc(inf)) != sep && c != EOF; ) {
+			if (rr-buf+1 > bufsize)
+				if (!adjbuf(&buf, &bufsize, 1+rr-buf,
+				    record_size, &rr, "readrec 1"))
+					FATAL(
+				"input record `%.30s...' too long", buf);
+			*rr++ = c;
 		}
 		if (**RS == sep || c == EOF)
 			break;
 		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
 			break;
-		expand_buf(&buf, &bufsize, count + 1);
-		buf[count++] = '\n';
-		buf[count++] = c;
-	}
-	buf[count] = '\0';
+		if (!adjbuf(&buf, &bufsize, 2+rr-buf, record_size, &rr,
+		    "readrec 2"))
+			FATAL("input record `%.30s...' too long", buf);
+		*rr++ = '\n';
+		*rr++ = c;
+	}
+	if (!adjbuf(&buf, &bufsize, 1+rr-buf, record_size, &rr, "readrec 3"))
+		FATAL("input record `%.30s...' too long", buf);
+	*rr = 0;
 	dprintf(("readrec saw <%s>, returns %d\n",
-	    buf, c == EOF && count == 0 ? 0 : 1));
-	*bufp = buf;
-	*sizep = count;
-	return (c == EOF && count == 0 ? 0 : 1);
+	    buf, c == EOF && rr == buf ? 0 : 1));
+	*pbuf = buf;
+	*pbufsize = bufsize;
+	return (c == EOF && rr == buf ? 0 : 1);
 }
 
-/* get ARGV[n] */
 static uchar *
-getargv(int n)
+getargv(int n)		/* get ARGV[n] */
 {
 	Cell *x;
-	uchar *s, temp[11];
+	uchar *s, temp[50];
 	extern Array *ARGVtab;
 
 	(void) sprintf((char *)temp, "%d", n);
+	if (lookup(temp, ARGVtab) == NULL)
+		return (NULL);
 	x = setsymtab(temp, (uchar *)"", 0.0, STR, ARGVtab);
 	s = getsval(x);
 	dprintf(("getargv(%d) returns |%s|\n", n, s));
@@ -217,50 +314,50 @@
 		q->tval |= NUM;
 	}
 	dprintf(("command line set %s to |%s|\n", s, p));
-	free(p);
 }
 
 void
-fldbld(void)
+fldbld(void)	/* create fields from current record */
 {
+	/* this relies on having fields[] the same length as $0 */
+	/* the fields are all stored in this one array with \0's */
+	/* possibly with a final trailing \0 not associated with any field */
 	uchar *r, *fr, sep;
 	Cell *p;
-	int i;
-	size_t	len;
+	int i, j;
+	size_t n;
 
 	if (donefld)
 		return;
-	if (!(recloc->tval & STR))
-		(void) getsval(recloc);
-	r = recloc->sval;	/* was record! */
-
-	/* make sure fields is always allocated */
-	adjust_buf(&fields, fields_size);
-
-	/*
-	 * make sure fields has enough size. We don't expand the buffer
-	 * in the middle of the loop, since p->sval has already pointed
-	 * the address in the fields.
-	 */
-	len = strlen((char *)r) + 1;
-	expand_buf(&fields, &fields_size, len);
+	if (!isstr(fldtab[0]))
+		(void) getsval(fldtab[0]);
+	r = fldtab[0]->sval;
+	n = strlen((char *)r);
+	if (n > fields_size) {
+		xfree(fields);
+		/* possibly 2 final \0s */
+		if ((fields = (uchar *)malloc(n + 2)) == NULL)
+			FATAL("out of space for fields in fldbld %d", n);
+		fields_size = n;
+	}
 	fr = fields;
-
 	i = 0;	/* number of fields accumulated here */
-	if (strlen((char *)*FS) > 1) {	/* it's a regular expression */
-		i = refldbld(r, *FS);
-	} else if ((sep = **FS) == ' ') {
+	(void) strcpy(inputFS, (char *)*FS);
+	if (strlen(inputFS) > 1) {	/* it's a regular expression */
+		i = refldbld(r, (uchar *)inputFS);
+	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
 		for (i = 0; ; ) {
 			while (*r == ' ' || *r == '\t' || *r == '\n')
 				r++;
 			if (*r == 0)
 				break;
 			i++;
-			p = getfld(i);
-			if (!(p->tval & DONTFREE))
-				xfree(p->sval);
-			p->sval = fr;
-			p->tval = FLD | STR | DONTFREE;
+			if (i > nfields)
+				growfldtab(i);
+			if (freeable(fldtab[i]))
+				xfree(fldtab[i]->sval);
+			fldtab[i]->sval = fr;
+			fldtab[i]->tval = FLD | STR | DONTFREE;
 			do
 				*fr++ = *r++;
 			while (*r != ' ' && *r != '\t' && *r != '\n' &&
@@ -269,16 +366,39 @@
 			*fr++ = 0;
 		}
 		*fr = 0;
+	} else if ((sep = *inputFS) == 0) {	/* new: FS="" => 1 char/field */
+		for (i = 0; *r != 0; r++) {
+			uchar buf[2];
+			i++;
+			if (i > nfields)
+				growfldtab(i);
+			if (freeable(fldtab[i]))
+				xfree(fldtab[i]->sval);
+			buf[0] = *r;
+			buf[1] = 0;
+			fldtab[i]->sval = tostring(buf);
+			fldtab[i]->tval = FLD | STR;
+		}
+		*fr = 0;
 	} else if (*r != 0) {	/* if 0, it's a null field */
+		/*
+		 * subtlecase : if length(FS) == 1 && length(RS > 0)
+		 * \n is NOT a field separator (cf awk book 61,84).
+		 * this variable is tested in the inner while loop.
+		 */
+		int rtest = '\n';  /* normal case */
+		if (strlen((char *)*RS) > 0)
+			rtest = '\0';
 		for (;;) {
 			i++;
-			p = getfld(i);
-			if (!(p->tval & DONTFREE))
-				xfree(p->sval);
-			p->sval = fr;
-			p->tval = FLD | STR | DONTFREE;
-			/* \n always a separator */
-			while (*r != sep && *r != '\n' && *r != '\0')
+			if (i > nfields)
+				growfldtab(i);
+			if (freeable(fldtab[i]))
+				xfree(fldtab[i]->sval);
+			fldtab[i]->sval = fr;
+			fldtab[i]->tval = FLD | STR | DONTFREE;
+			/* \n is always a separator */
+			while (*r != sep && *r != rtest && *r != '\0')
 				*fr++ = *r++;
 			*fr++ = 0;
 			if (*r++ == 0)
@@ -286,163 +406,119 @@
 		}
 		*fr = 0;
 	}
+	if (i > nfields)
+		FATAL("record `%.30s...' has too many fields; can't happen", r);
 	/* clean out junk from previous record */
-	cleanfld(i, maxfld);
-	maxfld = i;
+	cleanfld(i + 1, lastfld);
+	lastfld = i;
 	donefld = 1;
-	for (i = 1; i <= maxfld; i++) {
-		p = getfld(i);
+	for (j = 1; j <= lastfld; j++) {
+		p = fldtab[j];
 		if (is_number(p->sval)) {
 			p->fval = atof((const char *)p->sval);
 			p->tval |= NUM;
 		}
 	}
-
-	(void) setfval(nfloc, (Awkfloat) maxfld);
+	(void) setfval(nfloc, (Awkfloat)lastfld);
 	if (dbg) {
-		for (i = 0; i <= maxfld; i++) {
-			p = getfld(i);
-			(void) printf("field %d: |%s|\n", i, p->sval);
+		for (j = 0; j <= lastfld; j++) {
+			p = fldtab[j];
+			(void) printf("field %d (%s): |%s|\n", j, p->nval,
+			    p->sval);
 		}
 	}
 }
 
 static void
 cleanfld(int n1, int n2)	/* clean out fields n1..n2 inclusive */
-{
-	static uchar *nullstat = (uchar *) "";
+{				/* nvals remain intact */
+	static uchar *nullstat = (uchar *)"";
 	Cell *p;
-	int	i;
+	int i;
 
-	for (i = n2; i > n1; i--) {
-		p = getfld(i);
-		if (!(p->tval & DONTFREE))
+	for (i = n1; i <= n2; i++) {
+		p = fldtab[i];
+		if (freeable(p))
 			xfree(p->sval);
-		p->tval = FLD | STR | DONTFREE;
 		p->sval = nullstat;
+		p->tval = FLD | STR | DONTFREE;
 	}
 }
 
 void
-newfld(int n)	/* add field n (after end) */
+newfld(int n)	/* add field n after end of existing lastfld */
 {
-	if (n < 0)
-		ERROR "accessing invalid field", record FATAL;
-	(void) getfld(n);
-	cleanfld(maxfld, n);
-	maxfld = n;
-	(void) setfval(nfloc, (Awkfloat) n);
-}
-
-/*
- * allocate field table. We don't reallocate the table since there
- * might be somewhere recording the address of the table.
- */
-static void
-morefld(void)
-{
-	int	i;
-	struct fldtab_chunk *fldcp;
-	Cell	*newfld;
-
-	if ((fldcp = calloc(sizeof (struct fldtab_chunk), 1)) == NULL)
-		ERROR "out of space in morefld" FATAL;
-
-	newfld = &fldcp->fields[0];
-	for (i = 0; i < FLD_INCR; i++) {
-		newfld[i].ctype = OCELL;
-		newfld[i].csub = CFLD;
-		newfld[i].nval = NULL;
-		newfld[i].sval = (uchar *)"";
-		newfld[i].fval = 0.0;
-		newfld[i].tval = FLD|STR|DONTFREE;
-		newfld[i].cnext = NULL;
-	}
-	/*
-	 * link this field chunk
-	 */
-	if (fldtab_head == NULL)
-		fldtab_head = fldcp;
-	else
-		fldtab_tail->next = fldcp;
-	fldtab_tail = fldcp;
-	fldcp->next = NULL;
-
-	fldtab_maxidx += FLD_INCR;
+	if (n > nfields)
+		growfldtab(n);
+	cleanfld(lastfld + 1, n);
+	lastfld = n;
+	(void) setfval(nfloc, (Awkfloat)n);
 }
 
 Cell *
-getfld(int idx)
+fieldadr(int n)		/* get nth field */
 {
-	struct fldtab_chunk *fldcp;
-	int	cbase;
-
-	if (idx < 0)
-		ERROR "trying to access field %d", idx FATAL;
-	while (idx >= fldtab_maxidx)
-		morefld();
-	cbase = 0;
-	for (fldcp = fldtab_head; fldcp != NULL; fldcp = fldcp->next) {
-		if (idx < (cbase + FLD_INCR))
-			return (&fldcp->fields[idx - cbase]);
-		cbase += FLD_INCR;
-	}
-	/* should never happen */
-	ERROR "trying to access invalid field %d", idx FATAL;
-	return (NULL);
+	if (n < 0)
+		FATAL("trying to access out of range field %d", n);
+	if (n > nfields)	/* fields after NF are empty */
+		growfldtab(n);	/* but does not increase NF */
+	return (fldtab[n]);
 }
 
-int
-fldidx(Cell *vp)
-{
-	struct fldtab_chunk *fldcp;
-	Cell	*tbl;
-	int	cbase;
-
-	cbase = 0;
-	for (fldcp = fldtab_head; fldcp != NULL; fldcp = fldcp->next) {
-		tbl = &fldcp->fields[0];
-		if (vp >= tbl && vp < (tbl + FLD_INCR))
-			return (cbase + (vp - tbl));
-		cbase += FLD_INCR;
-	}
-	/* should never happen */
-	ERROR "trying to access unknown field" FATAL;
-	return (0);
+void
+growfldtab(int n)	/* make new fields up to at least $n */
+{
+	int nf = 2 * nfields;
+	size_t s;
+
+	if (n > nf)
+		nf = n;
+	/* freebsd: how much do we need? */
+	s = (nf + 1) * (sizeof (struct Cell *));
+	if (s / sizeof (struct Cell *) - 1 == nf)	/* didn't overflow */
+		fldtab = (Cell **) realloc(fldtab, s);
+	else	/* overflow sizeof int */
+		xfree(fldtab);  /* make it null */
+	if (fldtab == NULL)
+		FATAL("out of space creating %d fields", nf);
+	makefields(nfields + 1, nf);
+	nfields = nf;
 }
 
 static int
 refldbld(uchar *rec, uchar *fs)	/* build fields from reg expr in FS */
 {
+	/* this relies on having fields[] the same length as $0 */
+	/* the fields are all stored in this one array with \0's */
 	uchar *fr;
 	int i, tempstat;
 	fa *pfa;
-	Cell	*p;
-	size_t	len;
+	size_t n;
 
-	/* make sure fields is allocated */
-	adjust_buf(&fields, fields_size);
+	n = strlen((char *)rec);
+	if (n > fields_size) {
+		xfree(fields);
+		if ((fields = (uchar *)malloc(n + 1)) == NULL)
+			FATAL("out of space for fields in refldbld %d", n);
+		fields_size = n;
+	}
 	fr = fields;
 	*fr = '\0';
 	if (*rec == '\0')
 		return (0);
-
-	len = strlen((char *)rec) + 1;
-	expand_buf(&fields, &fields_size, len);
-	fr = fields;
-
 	pfa = makedfa(fs, 1);
 	dprintf(("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs));
 	tempstat = pfa->initstat;
 	for (i = 1; ; i++) {
-		p = getfld(i);
-		if (!(p->tval & DONTFREE))
-			xfree(p->sval);
-		p->tval = FLD | STR | DONTFREE;
-		p->sval = fr;
+		if (i > nfields)
+			growfldtab(i);
+		if (freeable(fldtab[i]))
+			xfree(fldtab[i]->sval);
+		fldtab[i]->tval = FLD | STR | DONTFREE;
+		fldtab[i]->sval = fr;
 		dprintf(("refldbld: i=%d\n", i));
 		if (nematch(pfa, rec)) {
-			pfa->initstat = 2;
+			pfa->initstat = 2;	/* horrible coupling to b.c */
 			dprintf(("match %s (%d chars)\n", patbeg, patlen));
 			(void) strncpy((char *)fr, (char *)rec, patbeg-rec);
 			fr += patbeg - rec + 1;
@@ -459,71 +535,83 @@
 }
 
 void
-recbld(void)
+recbld(void)		/* create $0 from $1..$NF if necessary */
 {
 	int i;
-	uchar *p;
-	size_t cnt, len, olen;
+	uchar *r, *p;
 
 	if (donerec == 1)
 		return;
-	cnt = 0;
-	olen = strlen((char *)*OFS);
+	r = record;
 	for (i = 1; i <= *NF; i++) {
-		p = getsval(getfld(i));
-		len = strlen((char *)p);
-		expand_buf(&record, &record_size, cnt + len + olen);
-		(void) memcpy(&record[cnt], p, len);
-		cnt += len;
+		p = getsval(fldtab[i]);
+		if (!adjbuf(&record, &record_size, 1 + strlen((char *)p) + r -
+		    record, record_size, &r, "recbld 1"))
+			FATAL("created $0 `%.30s...' too long", record);
+		while ((*r = *p++) != 0)
+			r++;
 		if (i < *NF) {
-			(void) memcpy(&record[cnt], *OFS, olen);
-			cnt += olen;
+			if (!adjbuf(&record, &record_size, 2 +
+			    strlen((char *)*OFS) + r - record, record_size,
+			    &r, "recbld 2"))
+				FATAL("created $0 `%.30s...' too long", record);
+			for (p = *OFS; (*r = *p++) != 0; )
+				r++;
 		}
 	}
-	record[cnt] = '\0';
-	dprintf(("in recbld FS=%o, recloc=%p\n", **FS, (void *)recloc));
-	if (!(recloc->tval & DONTFREE))
-		xfree(recloc->sval);
-	recloc->tval = REC | STR | DONTFREE;
-	recloc->sval = record;
-	dprintf(("in recbld FS=%o, recloc=%p\n", **FS, (void *)recloc));
+	if (!adjbuf(&record, &record_size, 2 + r - record, record_size, &r,
+	    "recbld 3"))
+		FATAL("built giant record `%.30s...'", record);
+	*r = '\0';
+	dprintf(("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS,
+	    (void *)fldtab[0]));
+
+	if (freeable(fldtab[0]))
+		xfree(fldtab[0]->sval);
+	fldtab[0]->tval = REC | STR | DONTFREE;
+	fldtab[0]->sval = record;
+
+	dprintf(("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS,
+	    (void *)fldtab[0]));
 	dprintf(("recbld = |%s|\n", record));
 	donerec = 1;
 }
 
-Cell *
-fieldadr(int n)
-{
-	if (n < 0)
-		ERROR "trying to access field %d", n FATAL;
-	return (getfld(n));
-}
-
 int	errorflag	= 0;
-char	errbuf[200];
 
 void
 yyerror(char *s)
 {
+	SYNTAX("%s", s);
+}
+
+void
+SYNTAX(const char *fmt, ...)
+{
 	extern uchar *cmdname, *curfname;
 	static int been_here = 0;
+	va_list varg;
 
 	if (been_here++ > 2)
 		return;
-	(void) fprintf(stderr, "%s: %s", cmdname, s);
+	(void) fprintf(stderr, "%s: ", cmdname);
+	va_start(varg, fmt);
+	(void) vfprintf(stderr, fmt, varg);
+	va_end(varg);
 	(void) fprintf(stderr, gettext(" at source line %lld"), lineno);
 	if (curfname != NULL)
 		(void) fprintf(stderr, gettext(" in function %s"), curfname);
+	if (compile_time == 1 && cursource() != NULL)
+		(void) fprintf(stderr, gettext(" source file %s"), cursource());
 	(void) fprintf(stderr, "\n");
 	errorflag = 2;
 	eprint();
 }
 
-/*ARGSUSED*/
 void
-fpecatch(int sig)
+fpecatch(int n)
 {
-	ERROR "floating point exception" FATAL;
+	FATAL("floating point exception %d", n);
 }
 
 extern int bracecnt, brackcnt, parencnt;
@@ -558,35 +646,61 @@
 }
 
 void
-error(int f, char *s)
+FATAL(const char *fmt, ...)
 {
-	extern Node *curnode;
 	extern uchar *cmdname;
+	va_list varg;
 
 	(void) fflush(stdout);
 	(void) fprintf(stderr, "%s: ", cmdname);
-	(void) fprintf(stderr, "%s", s);
+	va_start(varg, fmt);
+	(void) vfprintf(stderr, fmt, varg);
+	va_end(varg);
+	error();
+	if (dbg > 1)	/* core dump if serious debugging on */
+		abort();
+	exit(2);
+}
+
+void
+WARNING(const char *fmt, ...)
+{
+	extern uchar *cmdname;
+	va_list varg;
+
+	(void) fflush(stdout);
+	(void) fprintf(stderr, "%s: ", cmdname);
+	va_start(varg, fmt);
+	(void) vfprintf(stderr, fmt, varg);
+	va_end(varg);
+	error();
+}
+
+void
+error(void)
+{
+	extern Node *curnode;
+
 	(void) fprintf(stderr, "\n");
 	if (compile_time != 2 && NR && *NR > 0) {
 		(void) fprintf(stderr,
-		    gettext(" input record number %g"), *FNR);
+		    gettext(" input record number %g"), (int) (*FNR));
 		if (strcmp((char *)*FILENAME, "-") != 0)
 			(void) fprintf(stderr, gettext(", file %s"), *FILENAME);
 		(void) fprintf(stderr, "\n");
 	}
 	if (compile_time != 2 && curnode)
-		(void) fprintf(stderr, gettext(" source line number %lld\n"),
+		(void) fprintf(stderr, gettext(" source line number %d"),
 		    curnode->lineno);
 	else if (compile_time != 2 && lineno) {
 		(void) fprintf(stderr,
-		    gettext(" source line number %lld\n"), lineno);
+		    gettext(" source line number %d"), lineno);
 	}
+	if (compile_time == 1 && cursource() != NULL)
+		(void) fprintf(stderr,
+		    gettext(" source file %s"), cursource());
+	(void) fprintf(stderr, "\n");
 	eprint();
-	if (f) {
-		if (dbg)
-			abort();
-		exit(2);
-	}
 }
 
 static void
@@ -595,7 +709,7 @@
 	uchar *p, *q;
 	int c;
 	static int been_here = 0;
-	extern uchar ebuf[300], *ep;
+	extern uchar ebuf[], *ep;
 
 	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
 		return;
@@ -640,156 +754,52 @@
 }
 
 double
-errcheck(double x, char *s)
+errcheck(double x, const char *s)
 {
-	extern int errno;
-
 	if (errno == EDOM) {
 		errno = 0;
-		ERROR "%s argument out of domain", s WARNING;
+		WARNING("%s argument out of domain", s);
 		x = 1;
 	} else if (errno == ERANGE) {
 		errno = 0;
-		ERROR "%s result out of range", s WARNING;
+		WARNING("%s result out of range", s);
 		x = 1;
 	}
 	return (x);
 }
 
-void
-PUTS(uchar *s)
-{
-	dprintf(("%s\n", s));
-}
-
 int
-isclvar(uchar *s)	/* is s of form var=something? */
+isclvar(const uchar *s)	/* is s of form var=something? */
 {
-	if (s != NULL) {
+	const uchar *os = s;
 
-		/* Must begin with an underscore or alphabetic character */
-		if (isalpha(*s) || (*s == '_')) {
-
-			for (s++; *s; s++) {
-				/*
-				 * followed by a sequence of underscores,
-				 * digits, and alphabetics
-				 */
-				if (!(isalnum(*s) || *s == '_')) {
-					break;
-				}
-			}
-			return (*s == '=' && *(s + 1) != '=');
-		}
+	if (!isalpha(*s) && *s != '_')
+		return (0);
+	for (; *s; s++) {
+		if (!(isalnum(*s) || *s == '_'))
+			break;
 	}
 
-	return (0);
+	return (*s == '=' && s > os && *(s+1) != '=');
 }
 
-#define	MAXEXPON	38	/* maximum exponent for fp number */
+/* strtod is supposed to be a proper test of what's a valid number */
+/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
+/* wrong: violates 4.10.1.4 of ansi C standard */
 
 int
-is_number(uchar *s)
+is_number(const uchar *s)
 {
-	int d1, d2;
-	int point;
-	uchar *es;
-	extern char	radixpoint;
-
-	d1 = d2 = point = 0;
-	while (*s == ' ' || *s == '\t' || *s == '\n')
-		s++;
-	if (*s == '\0')
-		return (0);	/* empty stuff isn't number */
-	if (*s == '+' || *s == '-')
-		s++;
-	if (!isdigit(*s) && *s != radixpoint)
-		return (0);
-	if (isdigit(*s)) {
-		do {
-			d1++;
-			s++;
-		} while (isdigit(*s));
-	}
-	if (d1 >= MAXEXPON)
-		return (0);	/* too many digits to convert */
-	if (*s == radixpoint) {
-		point++;
-		s++;
-	}
-	if (isdigit(*s)) {
-		d2++;
-		do {
-			s++;
-		} while (isdigit(*s));
-	}
-	if (!(d1 || point && d2))
+	double r;
+	char *ep;
+	errno = 0;
+	r = strtod((const char *)s, &ep);
+	if (ep == (char *)s || r == HUGE_VAL || errno == ERANGE)
 		return (0);
-	if (*s == 'e' || *s == 'E') {
-		s++;
-		if (*s == '+' || *s == '-')
-			s++;
-		if (!isdigit(*s))
-			return (0);
-		es = s;
-		do {
-			s++;
-		} while (isdigit(*s));
-		if (s - es > 2) {
-			return (0);
-		} else if (s - es == 2 &&
-		    (int)(10 * (*es-'0') + *(es+1)-'0') >= MAXEXPON) {
-			return (0);
-		}
-	}
-	while (*s == ' ' || *s == '\t' || *s == '\n')
-		s++;
-	if (*s == '\0')
+	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
+		ep++;
+	if (*ep == '\0')
 		return (1);
 	else
 		return (0);
 }
-
-void
-init_buf(uchar **optr, size_t *sizep, size_t amt)
-{
-	uchar	*nptr = NULL;
-
-	if ((nptr = malloc(amt)) == NULL)
-		ERROR "out of space in init_buf" FATAL;
-	/* initial buffer should have NULL terminated */
-	*nptr = '\0';
-	if (sizep != NULL)
-		*sizep = amt;
-	*optr = nptr;
-}
-
-void
-r_expand_buf(uchar **optr, size_t *sizep, size_t req)
-{
-	uchar	*nptr;
-	size_t	amt, size = *sizep;
-
-	if (size != 0 && req < (size - 1))
-		return;
-	amt = req + 1 - size;
-	amt = (amt / LINE_INCR + 1) * LINE_INCR;
-
-	if ((nptr = realloc(*optr, size + amt)) == NULL)
-		ERROR "out of space in expand_buf" FATAL;
-	/* initial buffer should have NULL terminated */
-	if (size == 0)
-		*nptr = '\0';
-	*sizep += amt;
-	*optr = nptr;
-}
-
-void
-adjust_buf(uchar **optr, size_t size)
-{
-	uchar	*nptr;
-
-	if ((nptr = realloc(*optr, size)) == NULL)
-		ERROR "out of space in adjust_buf" FATAL;
-	*optr = nptr;
-}
--- old/usr/src/cmd/awk/main.c	2013-05-11 15:20:44.574219840 +0000
+++ new/usr/src/cmd/awk/main.c	2013-05-11 15:20:44.584751594 +0000
@@ -24,14 +24,32 @@
  * Use is subject to license terms.
  */
 
-/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
+/*
+ * 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.
+ */
 
-#include <stdio.h>
-#include <ctype.h>
 #include <signal.h>
 #include <locale.h>
-#include <libintl.h>
 #include <stdarg.h>
 #include <errno.h>
 #include <values.h>
@@ -39,23 +57,28 @@
 #include "awk.h"
 #include "y.tab.h"
 
-char	*version = "version Oct 11, 1989";
+char	*version = "version 20121220";
 
 int	dbg	= 0;
+Awkfloat	srand_seed = 1;
 uchar	*cmdname;	/* gets argv[0] for error messages */
 uchar	*lexprog;	/* points to program argument if it exists */
 int	compile_time = 2;	/* for error printing: */
 				/* 2 = cmdline, 1 = compile, 0 = running */
 char	radixpoint = '.';
 
-static uchar	**pfile = NULL;	/* program filenames from -f's */
+#define	MAX_PFILE	20	/* max number of -f's */
+
+static uchar	*pfile[MAX_PFILE];	/* program filenames from -f's */
 static int	npfile = 0;	/* number of filenames */
 static int	curpfile = 0;	/* current filename */
 
+int	safe = 0;	/* 1 => "safe" mode */
+
 int
 main(int argc, char *argv[], char *envp[])
 {
-	uchar *fs = NULL;
+	const uchar *fs = NULL;
 	char	*nl_radix;
 	/*
 	 * At this point, numbers are still scanned as in
@@ -76,25 +99,43 @@
 		exit(1);
 	}
 	(void) signal(SIGFPE, fpecatch);
+
+	srand_seed = 1;
+	srand((unsigned int)srand_seed);
+
 	yyin = NULL;
-	syminit();
+	symtab = makesymtab(NSYMTAB/NSYMTAB);
 	while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
-		if (strcmp(argv[1], "--") == 0) {
+		if (strcmp(argv[1], "-version") == 0 ||
+		    strcmp(argv[1], "--version") == 0) {
+			(void) printf("awk %s\n", version);
+			exit(0);
+			break;
+		}
+		if (strncmp(argv[1], "--", 2) == 0) {
 			/* explicit end of args */
 			argc--;
 			argv++;
 			break;
 		}
 		switch (argv[1][1]) {
+		case 's':
+			if (strcmp(argv[1], "-safe") == 0)
+				safe = 1;
+			break;
 		case 'f':	/* next argument is program filename */
-			argc--;
-			argv++;
-			if (argc <= 1)
-				ERROR "no program filename" FATAL;
-			pfile = realloc(pfile, sizeof (uchar *) * (npfile + 1));
-			if (pfile == NULL)
-				ERROR "out of space in main" FATAL;
-			pfile[npfile++] = (uchar *)argv[1];
+			if (argv[1][2] != 0) {	/* arg is -fsomething */
+				if (npfile >= MAX_PFILE - 1)
+					FATAL("too many -f options");
+				pfile[npfile++] = (uchar *)&argv[1][2];
+			} else {		/* arg is -f something */
+				argc--; argv++;
+				if (argc <= 1)
+					FATAL("no program filename");
+				if (npfile >= MAX_PFILE - 1)
+					FATAL("too many -f options");
+				pfile[npfile++] = (uchar *)argv[1];
+			}
 			break;
 		case 'F':	/* set field separator */
 			if (argv[1][2] != 0) {	/* arg is -Fsomething */
@@ -105,22 +146,33 @@
 					fs = (uchar *)&argv[1][2];
 			} else {		/* arg is -F something */
 				argc--; argv++;
-				if (argc > 1) {
-					/* wart: t=>\t */
-					if (argv[1][0] == 't' &&
-					    argv[1][1] == 0)
-						fs = (uchar *) "\t";
-					else if (argv[1][0] != 0)
-						fs = (uchar *)&argv[1][0];
-				}
+				/* wart: t=>\t */
+				if (argc > 1 && argv[1][0] == 't' &&
+				    argv[1][1] == 0)
+					fs = (uchar *) "\t";
+				else if (argc > 1 && argv[1][0] != 0)
+					fs = (uchar *)&argv[1][0];
 			}
 			if (fs == NULL || *fs == '\0')
-				ERROR "field separator FS is empty" WARNING;
+				WARNING("field separator FS is empty");
 			break;
 		case 'v':	/* -v a=1 to be done NOW.  one -v for each */
-			if (argv[1][2] == '\0' && --argc > 1 &&
-			    isclvar((uchar *)(++argv)[1]))
-				setclvar((uchar *)argv[1]);
+			if (argv[1][2] != 0) {	/* arg is -vsomething */
+				if (isclvar((uchar *)&argv[1][2]))
+					setclvar((uchar *)&argv[1][2]);
+				else
+					FATAL(
+				"invalid -v option argument: %s", &argv[1][2]);
+			} else {	/* arg is -v something */
+				argc--; argv++;
+				if (argc <= 1)
+					FATAL("no variable name");
+				if (isclvar((uchar *)argv[1]))
+					setclvar((uchar *)argv[1]);
+				else
+					FATAL(
+				"invalid -v option argument: %s", argv[1]);
+			}
 			break;
 		case 'd':
 			dbg = atoi(&argv[1][2]);
@@ -129,7 +181,7 @@
 			(void) printf("awk %s\n", version);
 			break;
 		default:
-			ERROR "unknown option %s ignored", argv[1] WARNING;
+			WARNING("unknown option %s ignored", argv[1]);
 			break;
 		}
 		argc--;
@@ -140,18 +192,21 @@
 		if (argc <= 1) {
 			if (dbg)
 				exit(0);
-			ERROR "no program given" FATAL;
+			FATAL("no program given");
 		}
 		dprintf(("program = |%s|\n", argv[1]));
 		lexprog = (uchar *)argv[1];
 		argc--;
 		argv++;
 	}
+	recinit(record_size);
+	syminit();
 	compile_time = 1;
 	argv[0] = (char *)cmdname;	/* put prog name at front of arglist */
 	dprintf(("argc=%d, argv[0]=%s\n", argc, argv[0]));
 	arginit(argc, (uchar **)argv);
-	envinit((uchar **)envp);
+	if (!safe)
+		envinit((uchar **)envp);
 	(void) yyparse();
 	if (fs)
 		*FS = qstring(fs, '\0');
@@ -173,7 +228,7 @@
 }
 
 int
-pgetc(void)		/* get program character */
+pgetc(void)		/* get 1 character from awk program */
 {
 	int c;
 
@@ -181,17 +236,27 @@
 		if (yyin == NULL) {
 			if (curpfile >= npfile)
 				return (EOF);
-			yyin = (strcmp((char *)pfile[curpfile], "-") == 0) ?
-			    stdin : fopen((char *)pfile[curpfile], "r");
-			if (yyin == NULL) {
-				ERROR "can't open file %s",
-				    pfile[curpfile] FATAL;
-			}
+			if (strcmp((char *)pfile[curpfile], "-") == 0)
+				yyin = stdin;
+			else if ((yyin = fopen(
+			    (char *)pfile[curpfile], "r")) == NULL)
+				FATAL("can't open file %s", pfile[curpfile]);
+			lineno = 1;
 		}
 		if ((c = getc(yyin)) != EOF)
 			return (c);
-		(void) fclose(yyin);
+		if (yyin != stdin)
+			(void) fclose(yyin);
 		yyin = NULL;
 		curpfile++;
 	}
 }
+
+uchar *
+cursource(void)		/* current source file name */
+{
+	if (npfile > 0)
+		return (pfile[curpfile]);
+	else
+		return (NULL);
+}
--- old/usr/src/cmd/awk/maketab.c	2013-05-11 15:20:44.964672484 +0000
+++ new/usr/src/cmd/awk/maketab.c	2013-05-11 15:20:44.974368198 +0000
@@ -23,20 +23,36 @@
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <libintl.h>
+/*
+ * 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.
+ */
 #include "awk.h"
 #include "y.tab.h"
 
 struct xx {
 	int token;
-	char *name;
-	char *pname;
+	const char *name;
+	const char *pname;
 } proc[] = {
 	{ PROGRAM, "program", NULL },
 	{ BOR, "boolop", " || " },
@@ -54,7 +70,7 @@
 	{ SUB, "sub", "sub" },
 	{ GSUB, "gsub", "gsub" },
 	{ INDEX, "sindex", "sindex" },
-	{ SPRINTF, "a_sprintf", "sprintf " },
+	{ SPRINTF, "awksprintf", "sprintf " },
 	{ ADD, "arith", " + " },
 	{ MINUS, "arith", " - " },
 	{ MULT, "arith", " * " },
@@ -73,10 +89,10 @@
 	{ NOTMATCH, "matchop", " !~ " },
 	{ MATCHFCN, "matchop", "matchop" },
 	{ INTEST, "intest", "intest" },
-	{ PRINTF, "aprintf", "printf" },
-	{ PRINT, "print", "print" },
+	{ PRINTF, "awkprintf", "printf" },
+	{ PRINT, "printstat", "print" },
 	{ CLOSE, "closefile", "closefile" },
-	{ DELETE, "delete", "delete" },
+	{ DELETE, "awkdelete", "awkdelete" },
 	{ SPLIT, "split", "split" },
 	{ ASSIGN, "assign", " = " },
 	{ ADDEQ, "assign", " += " },
@@ -92,6 +108,7 @@
 	{ DO, "dostat", "do" },
 	{ IN, "instat", "instat" },
 	{ NEXT, "jump", "next" },
+	{ NEXTFILE, "jump", "nextfile" },
 	{ EXIT, "jump", "exit" },
 	{ BREAK, "jump", "break" },
 	{ CONTINUE, "jump", "continue" },
@@ -100,67 +117,71 @@
 	{ CALL, "call", "call" },
 	{ ARG, "arg", "arg" },
 	{ VARNF, "getnf", "NF" },
-	{ GETLINE, "getaline", "getline" },
+	{ GETLINE, "awkgetline", "getline" },
 	{ 0, "", "" },
 };
 
-#define	SIZE	LASTTOKEN - FIRSTTOKEN + 1
-char *table[SIZE];
+#define	SIZE	(LASTTOKEN - FIRSTTOKEN + 1)
+const char *table[SIZE];
 char *names[SIZE];
 
+/* ARGSUSED */
 int
-main()
+main(int argc, char *argv[])
 {
-	struct xx *p;
+	const struct xx *p;
 	int i, n, tok;
 	char c;
 	FILE *fp;
-	char buf[100], name[100], def[100];
+	char buf[200], name[200], def[200];
 
-	printf("#include \"awk.h\"\n");
-	printf("#include \"y.tab.h\"\n\n");
+	(void) printf("#include <stdio.h>\n");
+	(void) printf("#include \"awk.h\"\n");
+	(void) printf("#include \"y.tab.h\"\n\n");
+	for (i = SIZE; --i >= 0; )
+		names[i] = "";
 
 	if ((fp = fopen("y.tab.h", "r")) == NULL) {
-		fprintf(stderr, gettext("maketab can't open y.tab.h!\n"));
+		(void) fprintf(stderr,
+		    gettext("maketab can't open y.tab.h!\n"));
 		exit(1);
 	}
-	printf("static uchar *printname[%d] = {\n", SIZE);
+	(void) printf("static uchar *printname[%d] = {\n", SIZE);
 	i = 0;
 	while (fgets(buf, sizeof (buf), fp) != NULL) {
+		/* LINTED E_SEC_SCANF_UNBOUNDED_COPY */
 		n = sscanf(buf, "%1c %s %s %d", &c, def, name, &tok);
 		/* not a valid #define? */
-		if (c != '#' || n != 4 && strcmp(def, "define") != 0)
+		if (c != '#' || (n != 4 && strcmp(def, "define") != 0))
+			continue;
+		if (tok < FIRSTTOKEN || tok > LASTTOKEN)
 			continue;
-		if (tok < FIRSTTOKEN || tok > LASTTOKEN) {
-			fprintf(stderr, gettext("maketab funny token %d %s\n"),
-			    tok, buf);
-			exit(1);
-		}
-		names[tok-FIRSTTOKEN] = malloc(strlen(name)+1);
-		strcpy(names[tok-FIRSTTOKEN], name);
-		printf("\t(uchar *) \"%s\",\t/* %d */\n", name, tok);
+		names[tok-FIRSTTOKEN] = (char *)malloc(strlen(name)+1);
+		(void) strcpy(names[tok-FIRSTTOKEN], name);
+		(void) printf("\t(uchar *) \"%s\",\t/* %d */\n", name, tok);
 		i++;
 	}
-	printf("};\n\n");
+	(void) printf("};\n\n");
 
 	for (p = proc; p->token != 0; p++)
 		table[p->token-FIRSTTOKEN] = p->name;
-	printf("\nCell *(*proctab[%d])() = {\n", SIZE);
+	(void) printf("\nCell *(*proctab[%d])(Node **, int) = {\n", SIZE);
 	for (i = 0; i < SIZE; i++)
 		if (table[i] == 0)
-			printf("\tnullproc,\t/* %s */\n", names[i]);
+			(void) printf("\tnullproc,\t/* %s */\n", names[i]);
 		else
-			printf("\t%s,\t/* %s */\n", table[i], names[i]);
-	printf("};\n\n");
+			(void) printf("\t%s,\t/* %s */\n", table[i], names[i]);
+	(void) printf("};\n\n");
 
-	printf("uchar *\ntokname(int n)\n");	/* print a tokname() function */
-	printf("{\n");
-	printf("	static char buf[100];\n\n");
-	printf("	if (n < FIRSTTOKEN || n > LASTTOKEN) {\n");
-	printf("		(void) sprintf(buf, \"token %%d\", n);\n");
-	printf("		return ((uchar *)buf);\n");
-	printf("	}\n");
-	printf("	return printname[n-257];\n");
-	printf("}\n");
-	exit(0);
+	/* print a tokname() function */
+	(void) printf("uchar *\ntokname(int n)\n");
+	(void) printf("{\n");
+	(void) printf("	static char buf[100];\n\n");
+	(void) printf("	if (n < FIRSTTOKEN || n > LASTTOKEN) {\n");
+	(void) printf("		(void) sprintf(buf, \"token %%d\", n);\n");
+	(void) printf("		return ((uchar *)buf);\n");
+	(void) printf("	}\n");
+	(void) printf("	return printname[n-FIRSTTOKEN];\n");
+	(void) printf("}\n");
+	return (0);
 }
--- old/usr/src/cmd/awk/parse.c	2013-05-11 15:20:45.381070123 +0000
+++ new/usr/src/cmd/awk/parse.c	2013-05-11 15:20:45.401790992 +0000
@@ -25,10 +25,29 @@
  * 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 "awk.h"
@@ -37,11 +56,11 @@
 Node *
 nodealloc(int n)
 {
-	register Node *x;
+	Node *x;
 
 	x = (Node *)malloc(sizeof (Node) + (n - 1) * sizeof (Node *));
 	if (x == NULL)
-		ERROR "out of space in nodealloc" FATAL;
+		FATAL("out of space in nodealloc");
 	x->nnext = NULL;
 	x->lineno = lineno;
 	return (x);
@@ -57,7 +76,7 @@
 Node *
 node1(int a, Node *b)
 {
-	register Node *x;
+	Node *x;
 
 	x = nodealloc(1);
 	x->nobj = a;
@@ -68,7 +87,7 @@
 Node *
 node2(int a, Node *b, Node *c)
 {
-	register Node *x;
+	Node *x;
 
 	x = nodealloc(2);
 	x->nobj = a;
@@ -80,7 +99,7 @@
 Node *
 node3(int a, Node *b, Node *c, Node *d)
 {
-	register Node *x;
+	Node *x;
 
 	x = nodealloc(3);
 	x->nobj = a;
@@ -93,7 +112,7 @@
 Node *
 node4(int a, Node *b, Node *c, Node *d, Node *e)
 {
-	register Node *x;
+	Node *x;
 	x = nodealloc(4);
 	x->nobj = a;
 	x->narg[0] = b;
@@ -104,89 +123,89 @@
 }
 
 Node *
-stat3(int a, Node *b, Node *c, Node *d)
+stat1(int a, Node *b)
 {
-	register Node *x;
+	Node *x;
 
-	x = node3(a, b, c, d);
+	x = node1(a, b);
 	x->ntype = NSTAT;
 	return (x);
 }
 
 Node *
-op2(int a, Node *b, Node *c)
+stat2(int a, Node *b, Node *c)
 {
-	register Node *x;
+	Node *x;
 
 	x = node2(a, b, c);
-	x->ntype = NEXPR;
+	x->ntype = NSTAT;
 	return (x);
 }
 
 Node *
-op1(int a, Node *b)
+stat3(int a, Node *b, Node *c, Node *d)
 {
-	register Node *x;
+	Node *x;
 
-	x = node1(a, b);
-	x->ntype = NEXPR;
+	x = node3(a, b, c, d);
+	x->ntype = NSTAT;
 	return (x);
 }
 
 Node *
-stat1(int a, Node *b)
+stat4(int a, Node *b, Node *c, Node *d, Node *e)
 {
-	register Node *x;
+	Node *x;
 
-	x = node1(a, b);
+	x = node4(a, b, c, d, e);
 	x->ntype = NSTAT;
 	return (x);
 }
 
 Node *
-op3(int a, Node *b, Node *c, Node *d)
+op1(int a, Node *b)
 {
-	register Node *x;
+	Node *x;
 
-	x = node3(a, b, c, d);
+	x = node1(a, b);
 	x->ntype = NEXPR;
 	return (x);
 }
 
 Node *
-op4(int a, Node *b, Node *c, Node *d, Node *e)
+op2(int a, Node *b, Node *c)
 {
-	register Node *x;
+	Node *x;
 
-	x = node4(a, b, c, d, e);
+	x = node2(a, b, c);
 	x->ntype = NEXPR;
 	return (x);
 }
 
 Node *
-stat2(int a, Node *b, Node *c)
+op3(int a, Node *b, Node *c, Node *d)
 {
-	register Node *x;
+	Node *x;
 
-	x = node2(a, b, c);
-	x->ntype = NSTAT;
+	x = node3(a, b, c, d);
+	x->ntype = NEXPR;
 	return (x);
 }
 
 Node *
-stat4(int a, Node *b, Node *c, Node *d, Node *e)
+op4(int a, Node *b, Node *c, Node *d, Node *e)
 {
-	register Node *x;
+	Node *x;
 
 	x = node4(a, b, c, d, e);
-	x->ntype = NSTAT;
+	x->ntype = NEXPR;
 	return (x);
 }
 
-Node *
-valtonode(Cell *a, int b)
+Node
+*celltonode(Cell *a, int b)
 {
-	register Node *x;
+	Node *x;
 
 	a->ctype = OCELL;
 	a->csub = b;
@@ -195,11 +214,11 @@
 	return (x);
 }
 
-Node *
-rectonode(void)
+Node
+*rectonode(void)	/* make $0 into a Node */
 {
-	/* return valtonode(lookup("$0", symtab), CFLD); */
-	return (valtonode(recloc, CFLD));
+	extern Cell *literal0;
+	return (op1(INDIRECT, celltonode(literal0, CUNK)));
 }
 
 Node *
@@ -209,8 +228,8 @@
 
 	if (isvalue(p)) {
 		cp = (Cell *)(p->narg[0]);
-		if (isfunc(cp))
-			ERROR "%s is a function, not an array", cp->nval SYNTAX;
+		if (isfcn(cp))
+			SYNTAX("%s is a function, not an array", cp->nval);
 		else if (!isarr(cp)) {
 			xfree(cp->sval);
 			cp->sval = (uchar *)makesymtab(NSYMTAB);
@@ -220,13 +239,21 @@
 	return (p);
 }
 
+/*
+ * The One True Awk sets PA2NUM to 50, which is not enough for webrev(1).
+ */
+#define	PA2NUM	250	/* max number of pat,pat patterns allowed */
+int	paircnt;		/* number of them in use */
+int	pairstack[PA2NUM];	/* state of each pat,pat */
+
 Node *
-pa2stat(Node *a, Node *b, Node *c)
+pa2stat(Node *a, Node *b, Node *c)	/* pat, pat {...} */
 {
-	register Node *x;
+	Node *x;
 
-	x = node4(PASTAT2, a, b, c, (Node *)paircnt);
-	paircnt++;
+	x = node4(PASTAT2, a, b, c, itonp(paircnt));
+	if (paircnt++ >= PA2NUM)
+		SYNTAX("limited to %d pat,pat statements", PA2NUM);
 	x->ntype = NSTAT;
 	return (x);
 }
@@ -234,7 +261,7 @@
 Node *
 linkum(Node *a, Node *b)
 {
-	register Node *c;
+	Node *c;
 
 	if (errorflag)	/* don't link things that are wrong */
 		return (a);
@@ -250,15 +277,21 @@
 
 void
 defn(Cell *v, Node *vl, Node *st)	/* turn on FCN bit in definition */
-{
+{					/*   body of function, arglist */
 	Node *p;
 	int n;
 
 	if (isarr(v)) {
-		ERROR "`%s' is an array name and a function name",
-		    v->nval SYNTAX;
+		SYNTAX("`%s' is an array name and a function name",
+		    v->nval);
+		return;
+	}
+	if (isarg(v->nval) != -1) {
+		SYNTAX("`%s' is both function name and argument name",
+		    v->nval);
 		return;
 	}
+
 	v->tval = FCN;
 	v->sval = (uchar *)st;
 	n = 0;	/* count arguments */
@@ -269,8 +302,8 @@
 }
 
 int
-isarg(uchar *s)	/* is s in argument list for current function? */
-{
+isarg(const uchar *s)	/* is s in argument list for current function? */
+{		/* return -1 if not, otherwise arg # */
 	extern Node *arglist;
 	Node *p = arglist;
 	int n;
@@ -283,3 +316,15 @@
 	}
 	return (-1);
 }
+
+int
+ptoi(void *p)		/* convert pointer to integer */
+{
+	return ((int)(long)p);  /* swearing that p fits, of course */
+}
+
+Node
+*itonp(int i)		/* and vice versa */
+{
+	return ((Node *)(long)i);
+}
--- old/usr/src/cmd/awk/run.c	2013-05-11 15:20:45.824142601 +0000
+++ new/usr/src/cmd/awk/run.c	2013-05-11 15:20:45.848298484 +0000
@@ -23,155 +23,212 @@
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
-
-#define	tempfree(x, s)	if (istemp(x)) tfree(x, s)
+/*
+ * 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	execute(p) r_execute(p)
+#define	tempfree(x)	if (istemp(x)) tfree(x);
 
 #define	DEBUG
-#include	"awk.h"
-#include	<math.h>
-#include	"y.tab.h"
-#include	<stdio.h>
-#include	<ctype.h>
-#include	<setjmp.h>
-#include	<time.h>
-
-#ifndef	FOPEN_MAX
-#define	FOPEN_MAX	15	/* max number of open files, from ANSI std. */
-#endif
-
+#include <setjmp.h>
+#include <math.h>
+#include <time.h>
+#include "awk.h"
+#include "y.tab.h"
+
+static	Cell	*execute(Node *);
+static	Cell	*gettemp(void);
+static	Cell	*copycell(Cell *);
+static	FILE	*openfile(int, const uchar *);
+static	FILE	*redirect(int, Node *);
+static	const char *filename(FILE *);
+static	void	flush_all(void);
 
 static jmp_buf env;
+extern	Awkfloat	srand_seed;
 
-static	Cell	*r_execute(Node *);
-static	Cell	*gettemp(char *), *copycell(Cell *);
-static	FILE	*openfile(int, uchar *), *redirect(int, Node *);
-
-int	paircnt;
-Node	*winner = NULL;
-
-static Cell	*tmps;
+Node	*winner = NULL;	/* root of parse tree */
 
+static Cell	*tmps;	/* free temporary cells for execution */
 static Cell	truecell	= { OBOOL, BTRUE, 0, 0, 1.0, NUM };
-Cell	*true	= &truecell;
+Cell	*True	= &truecell;
 static Cell	falsecell	= { OBOOL, BFALSE, 0, 0, 0.0, NUM };
-Cell	*false	= &falsecell;
+Cell	*False	= &falsecell;
 static Cell	breakcell	= { OJUMP, JBREAK, 0, 0, 0.0, NUM };
 Cell	*jbreak	= &breakcell;
 static Cell	contcell	= { OJUMP, JCONT, 0, 0, 0.0, NUM };
 Cell	*jcont	= &contcell;
 static Cell	nextcell	= { OJUMP, JNEXT, 0, 0, 0.0, NUM };
 Cell	*jnext	= &nextcell;
+static Cell	nextfilecell	= { OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
+Cell	*jnextfile	= &nextfilecell;
 static Cell	exitcell	= { OJUMP, JEXIT, 0, 0, 0.0, NUM };
 Cell	*jexit	= &exitcell;
 static Cell	retcell		= { OJUMP, JRET, 0, 0, 0.0, NUM };
 Cell	*jret	= &retcell;
-static Cell	tempcell	= { OCELL, CTEMP, 0, 0, 0.0, NUM };
+static Cell	tempcell	= { OCELL, CTEMP, 0, (uchar *)"", 0.0, NUM|
+    STR|DONTFREE};
 
 Node	*curnode = NULL;	/* the node being executed, for debugging */
 
-static	void	tfree(Cell *, char *);
+static	void	tfree(Cell *);
 static	void	closeall(void);
 static	double	ipow(double, int);
+static	void	stdinit(void);
+
+/*
+ * buffer memory management
+ *
+ * pbuf:    address of pointer to buffer being managed
+ * psiz:    address of buffer size variable
+ * minlen:  minimum length of buffer needed
+ * quantum: buffer size quantum
+ * pbptr:   address of movable pointer into buffer, or 0 if none
+ * whatrtn: name of the calling routine if failure should cause fatal error
+ *
+ * return   0 for realloc failure, !=0 for success
+ */
+int adjbuf(uchar **pbuf, size_t *psiz, int minlen, int quantum, uchar **pbptr,
+    const char *whatrtn)
+{
+	if (minlen > *psiz) {
+		uchar *tbuf;
+		int rminlen = quantum ? minlen % quantum : 0;
+		int boff = pbptr ? *pbptr - *pbuf : 0;
+		/* round up to next multiple of quantum */
+		if (rminlen)
+			minlen += quantum - rminlen;
+		tbuf = (uchar *)realloc(*pbuf, minlen);
+		dprintf(("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn,
+		    *psiz, minlen, (void *)*pbuf, (void *)tbuf));
+		if (tbuf == NULL) {
+			if (whatrtn)
+				FATAL("out of memory in %s", whatrtn);
+			return (0);
+		}
+		*pbuf = (uchar *)tbuf;
+		*psiz = minlen;
+		if (pbptr)
+			*pbptr = tbuf + boff;
+	}
+	return (1);
+}
 
 void
-run(Node *a)
+run(Node *a)		/* execution of parse tree starts here */
 {
+	stdinit();
 	(void) execute(a);
 	closeall();
 }
 
 static Cell *
-r_execute(Node *u)
+execute(Node *u)	/* execute a node of the parse tree */
 {
-	register Cell *(*proc)();
-	register Cell *x;
-	register Node *a;
+	Cell *(*proc)(Node **, int);
+	Cell *x;
+	Node *a;
 
 	if (u == NULL)
-		return (true);
+		return (True);
 	for (a = u; ; a = a->nnext) {
 		curnode = a;
 		if (isvalue(a)) {
-			x = (Cell *) (a->narg[0]);
-			if ((x->tval & FLD) && !donefld)
+			x = (Cell *)(a->narg[0]);
+			if (isfld(x) && !donefld)
 				fldbld();
-			else if ((x->tval & REC) && !donerec)
+			else if (isrec(x) && !donerec)
 				recbld();
 			return (x);
 		}
 		/* probably a Cell* but too risky to print */
 		if (notlegal(a->nobj))
-			ERROR "illegal statement" FATAL;
+			FATAL("illegal statement");
 		proc = proctab[a->nobj-FIRSTTOKEN];
 		x = (*proc)(a->narg, a->nobj);
-		if ((x->tval & FLD) && !donefld)
+		if (isfld(x) && !donefld)
 			fldbld();
-		else if ((x->tval & REC) && !donerec)
+		else if (isrec(x) && !donerec)
 			recbld();
 		if (isexpr(a))
 			return (x);
-		/* a statement, goto next statement */
 		if (isjump(x))
 			return (x);
 		if (a->nnext == (Node *)NULL)
 			return (x);
-		tempfree(x, "execute");
+		tempfree(x);
 	}
 }
 
 /*ARGSUSED*/
 Cell *
-program(Node **a, int n)
-{
-	register Cell *x;
+program(Node **a, int n)	/* execute an awk program */
+{				/* a[0] = BEGIN, a[1] = body, a[2] = END */
+	Cell *x;
 
 	if (setjmp(env) != 0)
 		goto ex;
 	if (a[0]) {		/* BEGIN */
 		x = execute(a[0]);
 		if (isexit(x))
-			return (true);
+			return (True);
 		if (isjump(x)) {
-			ERROR "illegal break, continue or next from BEGIN"
-			    FATAL;
+			FATAL(
+		"illegal break, continue, next or nextfile from BEGIN");
 		}
-		tempfree(x, "");
+		tempfree(x);
 	}
-loop:
-	if (a[1] || a[2])
-		while (getrec(&record, &record_size) > 0) {
+
+	if (a[1] || a[2]) {
+		while (getrec(&record, &record_size, 1) > 0) {
 			x = execute(a[1]);
 			if (isexit(x))
 				break;
-			tempfree(x, "");
+			tempfree(x);
 		}
+	}
 ex:
-	if (setjmp(env) != 0)
+	if (setjmp(env) != 0)	/* handles exit within END */
 		goto ex1;
 	if (a[2]) {		/* END */
 		x = execute(a[2]);
-		if (iscont(x))	/* read some more */
-			goto loop;
-		if (isbreak(x) || isnext(x))
-			ERROR "illegal break or next from END" FATAL;
-		tempfree(x, "");
+		if (isbreak(x) || isnext(x) || iscont(x))
+			FATAL(
+		"illegal break, continue, next or nextfile from END");
+		tempfree(x);
 	}
 ex1:
-	return (true);
+	return (True);
 }
 
-struct Frame {
+struct Frame {	/* stack frame for awk function calls */
 	int nargs;	/* number of arguments in this call */
 	Cell *fcncell;	/* pointer to Cell for function */
 	Cell **args;	/* pointer to array of arguments after execute */
 	Cell *retval;	/* return value */
 };
 
-#define	NARGS	30
+#define	NARGS	50	/* max args in a call */
 
 struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
 int	nframe = 0;		/* number of frames allocated */
@@ -179,60 +236,63 @@
 
 /*ARGSUSED*/
 Cell *
-call(Node **a, int n)
+call(Node **a, int n)	/* function call.  very kludgy and fragile */
 {
 	static Cell newcopycell =
-		{ OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
-	int i, ncall, ndef, freed = 0;
+	    { OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
+	int i, ncall, ndef;
+	/* handles potential double freeing when fcn & param share a tempcell */
+	int freed = 0;
 	Node *x;
-	Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;
+	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
+	Cell *y, *z, *fcn;
 	uchar *s;
 
 	fcn = execute(a[0]);	/* the function itself */
 	s = fcn->nval;
-	if (!isfunc(fcn))
-		ERROR "calling undefined function %s", s FATAL;
+	if (!isfcn(fcn))
+		FATAL("calling undefined function %s", s);
 	if (frame == NULL) {
 		fp = frame = (struct Frame *)calloc(nframe += 100,
 		    sizeof (struct Frame));
 		if (frame == NULL) {
-			ERROR "out of space for stack frames calling %s",
-			    s FATAL;
+			FATAL("out of space for stack frames calling %s", s);
 		}
 	}
 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
 		ncall++;
 	ndef = (int)fcn->fval;			/* args in defn */
 	dprintf(("calling %s, %d args (%d in defn), fp=%d\n",
-	    s, ncall, ndef, fp-frame));
+	    s, ncall, ndef, (int)(fp-frame)));
+
 	if (ncall > ndef) {
-		ERROR "function %s called with %d args, uses only %d",
-		    s, ncall, ndef WARNING;
+		WARNING("function %s called with %d args, uses only %d",
+		    s, ncall, ndef);
 	}
 	if (ncall + ndef > NARGS) {
-		ERROR "function %s has %d arguments, limit %d",
-		    s, ncall+ndef, NARGS FATAL;
+		FATAL("function %s has %d arguments, limit %d",
+		    s, ncall + ndef, NARGS);
 	}
 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {
 		/* get call args */
-		dprintf(("evaluate args[%d], fp=%d:\n", i, fp-frame));
+		dprintf(("evaluate args[%d], fp=%d:\n", i, (int)(fp-frame)));
 		y = execute(x);
 		oargs[i] = y;
 		dprintf(("args[%d]: %s %f <%s>, t=%o\n",
 		    i, y->nval, y->fval,
 		    isarr(y) ? "(array)" : (char *)y->sval, y->tval));
-		if (isfunc(y)) {
-			ERROR "can't use function %s as argument in %s",
-			    y->nval, s FATAL;
+		if (isfcn(y)) {
+			FATAL("can't use function %s as argument in %s",
+			    y->nval, s);
 		}
 		if (isarr(y))
 			args[i] = y;	/* arrays by ref */
 		else
 			args[i] = copycell(y);
-		tempfree(y, "callargs");
+		tempfree(y);
 	}
 	for (; i < ndef; i++) { /* add null args for ones not provided */
-		args[i] = gettemp("nullargs");
+		args[i] = gettemp();
 		*args[i] = newcopycell;
 	}
 	fp++;	/* now ok to up frame */
@@ -241,18 +301,18 @@
 		frame = (struct Frame *)
 		    realloc(frame, (nframe += 100) * sizeof (struct Frame));
 		if (frame == NULL)
-			ERROR "out of space for stack frames in %s", s FATAL;
+			FATAL("out of space for stack frames in %s", s);
 		fp = frame + dfp;
 	}
 	fp->fcncell = fcn;
 	fp->args = args;
 	fp->nargs = ndef;	/* number defined with (excess are locals) */
-	fp->retval = gettemp("retval");
+	fp->retval = gettemp();
 
-	dprintf(("start exec of %s, fp=%d\n", s, fp-frame));
+	dprintf(("start exec of %s, fp=%d\n", s, (int)(fp-frame)));
 	/*LINTED align*/
 	y = execute((Node *)(fcn->sval));	/* execute body */
-	dprintf(("finished exec of %s, fp=%d\n", s, fp-frame));
+	dprintf(("finished exec of %s, fp=%d\n", s, (int)(fp-frame)));
 
 	for (i = 0; i < ndef; i++) {
 		Cell *t = fp->args[i];
@@ -261,24 +321,29 @@
 				if (i >= ncall) {
 					freesymtab(t);
 					t->csub = CTEMP;
+					tempfree(t);
 				} else {
 					oargs[i]->tval = t->tval;
 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
 					oargs[i]->sval = t->sval;
-					tempfree(t, "oargsarr");
+					tempfree(t);
 				}
 			}
-		} else {
+		} else if (t != y) {	/* kludge to prevent freeing twice */
 			t->csub = CTEMP;
-			tempfree(t, "fp->args");
-			if (t == y) freed = 1;
+			tempfree(t);
+		} else if (t == y && t->csub == CCOPY) {
+			t->csub = CTEMP;
+			tempfree(t);
+			freed = 1;
 		}
 	}
-	tempfree(fcn, "call.fcn");
+	tempfree(fcn);
 	if (isexit(y) || isnext(y))
 		return (y);
-	if (!freed)
-		tempfree(y, "fcn ret"); /* this can free twice! */
+	if (freed == 0) {
+		tempfree(y);	/* don't free twice! */
+	}
 	z = fp->retval;			/* return value */
 	dprintf(("%s returns %g |%s| %o\n",
 	    s, getfval(z), getsval(z), z->tval));
@@ -291,42 +356,41 @@
 {
 	Cell *y;
 
-	y = gettemp("copycell");
+	y = gettemp();
 	y->csub = CCOPY;	/* prevents freeing until call is over */
-	y->nval = x->nval;
-	y->sval = x->sval ? tostring(x->sval) : NULL;
+	y->nval = x->nval;	/* BUG? */
+	if (isstr(x))
+		y->sval = tostring(x->sval);
 	y->fval = x->fval;
 	/* copy is not constant or field is DONTFREE right? */
 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);
 	return (y);
 }
 
-/*ARGSUSED*/
 Cell *
-arg(Node **a, int nnn)
+arg(Node **a, int n)		/* nth argument of a function */
 {
-	int n;
 
-	n = (int)a[0];	/* argument number, counting from 0 */
+	n = ptoi(a[0]);	/* argument number, counting from 0 */
 	dprintf(("arg(%d), fp->nargs=%d\n", n, fp->nargs));
-	if (n+1 > fp->nargs) {
-		ERROR "argument #%d of function %s was not supplied",
-		    n+1, fp->fcncell->nval FATAL;
+	if (n + 1 > fp->nargs) {
+		FATAL("argument #%d of function %s was not supplied",
+		    n + 1, fp->fcncell->nval);
 	}
 	return (fp->args[n]);
 }
 
 Cell *
-jump(Node **a, int n)
+jump(Node **a, int n)	/* break, continue, next, nextfile, return */
 {
-	register Cell *y;
+	Cell *y;
 
 	switch (n) {
 	case EXIT:
 		if (a[0] != NULL) {
 			y = execute(a[0]);
 			errorflag = (int)getfval(y);
-			tempfree(y, "");
+			tempfree(y);
 		}
 		longjmp(env, 1);
 		/*NOTREACHED*/
@@ -341,77 +405,87 @@
 				(void) setsval(fp->retval, getsval(y));
 			else if (y->tval & NUM)
 				(void) setfval(fp->retval, getfval(y));
-			tempfree(y, "");
+			else		/* can't happen */
+				FATAL("bad type variable %d", y->tval);
+			tempfree(y);
 		}
 		return (jret);
 	case NEXT:
 		return (jnext);
+	case NEXTFILE:
+		nextfile();
+		return (jnextfile);
 	case BREAK:
 		return (jbreak);
 	case CONTINUE:
 		return (jcont);
 	default:	/* can't happen */
-		ERROR "illegal jump type %d", n FATAL;
+		FATAL("illegal jump type %d", n);
 	}
 	/*NOTREACHED*/
 	return (NULL);
 }
 
+/*
+ * get next line from specific input
+ *
+ * a[0] is variable, a[1] is operator, a[2] is filename
+ */
 Cell *
-getaline(Node **a, int n)
+awkgetline(Node **a, int n)
 {
-	/* a[0] is variable, a[1] is operator, a[2] is filename */
-	register Cell *r, *x;
-	uchar *buf;
+	Cell *r, *x;
+	extern Cell **fldtab;
 	FILE *fp;
-	size_t len;
+	uchar *buf;
+	size_t bufsize = record_size;
+	int mode;
+
+	if ((buf = (uchar *)malloc(bufsize)) == NULL)
+		FATAL("out of memory in getline");
 
 	(void) fflush(stdout);	/* in case someone is waiting for a prompt */
-	r = gettemp("");
+	r = gettemp();
 	if (a[1] != NULL) {		/* getline < file */
 		x = execute(a[2]);		/* filename */
-		if ((int)a[1] == '|')	/* input pipe */
-			a[1] = (Node *)LE;	/* arbitrary flag */
-		fp = openfile((int)a[1], getsval(x));
-		tempfree(x, "");
-		buf = NULL;
+		mode = ptoi(a[1]);
+		if (mode == '|')	/* input pipe */
+			mode = LE;	/* arbitrary flag */
+		fp = openfile(mode, getsval(x));
+		tempfree(x);
 		if (fp == NULL)
 			n = -1;
 		else
-			n = readrec(&buf, &len, fp);
-		if (n > 0) {
-			if (a[0] != NULL) {	/* getline var <file */
-				(void) setsval(execute(a[0]), buf);
-			} else {			/* getline <file */
-				if (!(recloc->tval & DONTFREE))
-					xfree(recloc->sval);
-				expand_buf(&record, &record_size, len);
-				(void) memcpy(record, buf, len);
-				record[len] = '\0';
-				recloc->sval = record;
-				recloc->tval = REC | STR | DONTFREE;
-				donerec = 1; donefld = 0;
+			n = readrec(&buf, &bufsize, fp);
+		if (a[0] != NULL) {	/* getline var <file */
+			x = execute(a[0]);
+			(void) setsval(x, buf);
+			tempfree(x);
+		} else {			/* getline <file */
+			(void) setsval(fldtab[0], buf);
+			if (is_number(fldtab[0]->sval)) {
+				fldtab[0]->fval = atof((char *)fldtab[0]->sval);
+				fldtab[0]->tval |= NUM;
 			}
 		}
-		if (buf != NULL)
-			free(buf);
 	} else {			/* bare getline; use current input */
 		if (a[0] == NULL)	/* getline */
-			n = getrec(&record, &record_size);
+			n = getrec(&record, &record_size, 1);
 		else {			/* getline var */
-			init_buf(&buf, &len, LINE_INCR);
-			n = getrec(&buf, &len);
-			(void) setsval(execute(a[0]), buf);
-			free(buf);
+			n = getrec(&buf, &bufsize, 0);
+			x = execute(a[0]);
+			(void) setsval(x, buf);
+			tempfree(x);
 		}
 	}
 	(void) setfval(r, (Awkfloat)n);
+	free(buf);
 	return (r);
 }
 
 /*ARGSUSED*/
 Cell *
-getnf(Node **a, int n)
+getnf(Node **a, int n)		/* get NF */
 {
 	if (donefld == 0)
 		fldbld();
@@ -420,32 +494,30 @@
 
 /*ARGSUSED*/
 Cell *
-array(Node **a, int n)
+array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
 {
-	register Cell *x, *y, *z;
-	register uchar *s;
-	register Node *np;
-	uchar	*buf;
-	size_t	bsize, tlen, len, slen;
+	Cell *x, *y, *z;
+	uchar *s;
+	Node *np;
+	uchar *buf;
+	size_t bufsz = record_size;
+	size_t nsub = strlen((char *)*SUBSEP);
+
+	if ((buf = (uchar *)malloc(bufsz)) == NULL)
+		FATAL("out of memory in array");
 
 	x = execute(a[0]);	/* Cell* for symbol table */
-	init_buf(&buf, &bsize, LINE_INCR);
 	buf[0] = '\0';
-	tlen = 0;
-	slen = strlen((char *)*SUBSEP);
 	for (np = a[1]; np; np = np->nnext) {
 		y = execute(np);	/* subscript */
 		s = getsval(y);
-		len = strlen((char *)s);
-		expand_buf(&buf, &bsize, tlen + len + slen);
-		(void) memcpy(&buf[tlen], s, len);
-		tlen += len;
-		if (np->nnext) {
-			(void) memcpy(&buf[tlen], *SUBSEP, slen);
-			tlen += slen;
-		}
-		buf[tlen] = '\0';
-		tempfree(y, "");
+		if (!adjbuf(&buf, &bufsz, strlen((char *)buf) +
+		    strlen((char *)s) + nsub + 1, record_size, 0, "array"))
+			FATAL("out of memory for %s[%s...]", x->nval, buf);
+		(void) strcat((char *)buf, (char *)s);
+		if (np->nnext)
+			(void) strcat((char *)buf, (char *)*SUBSEP);
+		tempfree(y);
 	}
 	if (!isarr(x)) {
 		dprintf(("making %s into an array\n", x->nval));
@@ -453,265 +525,278 @@
 			xfree(x->sval);
 		x->tval &= ~(STR|NUM|DONTFREE);
 		x->tval |= ARR;
-		x->sval = (uchar *) makesymtab(NSYMTAB);
+		x->sval = (uchar *)makesymtab(NSYMTAB);
 	}
 	/*LINTED align*/
 	z = setsymtab(buf, (uchar *)"", 0.0, STR|NUM, (Array *)x->sval);
 	z->ctype = OCELL;
 	z->csub = CVAR;
-	tempfree(x, "");
+	tempfree(x);
 	free(buf);
 	return (z);
 }
 
 /*ARGSUSED*/
 Cell *
-delete(Node **a, int n)
+awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
 {
 	Cell *x, *y;
 	Node *np;
-	uchar *buf, *s;
-	size_t bsize, tlen, slen, len;
+	uchar *s;
+	size_t nsub = strlen((char *)*SUBSEP);
 
 	x = execute(a[0]);	/* Cell* for symbol table */
 	if (!isarr(x))
-		return (true);
-	init_buf(&buf, &bsize, LINE_INCR);
-	buf[0] = '\0';
-	tlen = 0;
-	slen = strlen((char *)*SUBSEP);
-	for (np = a[1]; np; np = np->nnext) {
-		y = execute(np);	/* subscript */
-		s = getsval(y);
-		len = strlen((char *)s);
-		expand_buf(&buf, &bsize, tlen + len + slen);
-		(void) memcpy(&buf[tlen], s, len);
-		tlen += len;
-		if (np->nnext) {
-			(void) memcpy(&buf[tlen], *SUBSEP, slen);
-			tlen += slen;
+		return (True);
+	if (a[1] == 0) {	/* delete the elements, not the table */
+		freesymtab(x);
+		x->tval &= ~STR;
+		x->tval |= ARR;
+		x->sval = (uchar *)makesymtab(NSYMTAB);
+	} else {
+		size_t bufsz = record_size;
+		uchar *buf;
+		if ((buf = (uchar *)malloc(bufsz)) == NULL)
+			FATAL("out of memory in delete");
+		buf[0] = '\0';
+		for (np = a[1]; np; np = np->nnext) {
+			y = execute(np);	/* subscript */
+			s = getsval(y);
+			if (!adjbuf(&buf, &bufsz, strlen((char *)buf) +
+			    strlen((char *)s) + nsub + 1, record_size, 0,
+			    "awkdelete")) {
+				FATAL("out of memory deleting %s[%s...]",
+				    x->nval, buf);
+			}
+			(void) strcat((char *)buf, (char *)s);
+			if (np->nnext)
+				(void) strcat((char *)buf, (char *)*SUBSEP);
+			tempfree(y);
 		}
-		buf[tlen] = '\0';
-		tempfree(y, "");
+		freeelem(x, buf);
+		free(buf);
 	}
-	freeelem(x, buf);
-	tempfree(x, "");
-	free(buf);
-	return (true);
+	tempfree(x);
+	return (True);
 }
 
 /*ARGSUSED*/
 Cell *
-intest(Node **a, int n)
+intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
 {
-	register Cell *x, *ap, *k;
+	Cell *x, *ap, *k;
 	Node *p;
 	uchar *buf;
 	uchar *s;
-	size_t bsize, tlen, slen, len;
+	size_t bufsz = record_size;
+	size_t nsub = strlen((char *)*SUBSEP);
 
 	ap = execute(a[1]);	/* array name */
-	if (!isarr(ap))
-		ERROR "%s is not an array", ap->nval FATAL;
-	init_buf(&buf, &bsize, LINE_INCR);
+	if (!isarr(ap))	{
+		dprintf(("making %s into an array\n", ap->nval));
+		if (freeable(ap))
+			xfree(ap->sval);
+		ap->tval &= ~(STR|NUM|DONTFREE);
+		ap->tval |= ARR;
+		ap->sval = (uchar *)makesymtab(NSYMTAB);
+	}
+	if ((buf = (uchar *)malloc(bufsz)) == NULL) {
+		FATAL("out of memory in intest");
+	}
 	buf[0] = 0;
-	tlen = 0;
-	slen = strlen((char *)*SUBSEP);
 	for (p = a[0]; p; p = p->nnext) {
 		x = execute(p);	/* expr */
 		s = getsval(x);
-		len = strlen((char *)s);
-		expand_buf(&buf, &bsize, tlen + len + slen);
-		(void) memcpy(&buf[tlen], s, len);
-		tlen += len;
-		tempfree(x, "");
-		if (p->nnext) {
-			(void) memcpy(&buf[tlen], *SUBSEP, slen);
-			tlen += slen;
-		}
-		buf[tlen] = '\0';
+		if (!adjbuf(&buf, &bufsz, strlen((char *)buf) +
+		    strlen((char *)s) + nsub + 1, record_size, 0, "intest"))
+			FATAL("out of memory deleting %s[%s...]", x->nval, buf);
+		(void) strcat((char *)buf, (char *)s);
+		tempfree(x);
+		if (p->nnext)
+			(void) strcat((char *)buf, (char *)*SUBSEP);
 	}
 	/*LINTED align*/
 	k = lookup(buf, (Array *)ap->sval);
-	tempfree(ap, "");
+	tempfree(ap);
 	free(buf);
 	if (k == NULL)
-		return (false);
+		return (False);
 	else
-		return (true);
+		return (True);
 }
 
-
 Cell *
-matchop(Node **a, int n)
+matchop(Node **a, int n)	/* ~ and match() */
 {
-	register Cell *x, *y;
-	register uchar *s, *t;
-	register int i;
+	Cell *x, *y;
+	uchar *s, *t;
+	int i;
 	fa *pfa;
-	int (*mf)() = match, mode = 0;
+	int (*mf)(fa *, const uchar *) = match, mode = 0;
 
 	if (n == MATCHFCN) {
 		mf = pmatch;
 		mode = 1;
 	}
-	x = execute(a[1]);
+	x = execute(a[1]);	/* a[1] = target text */
 	s = getsval(x);
-	if (a[0] == 0)
-		i = (*mf)(a[2], s);
+	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
+		i = (*mf)((fa *)a[2], s);
 	else {
-		y = execute(a[2]);
+		y = execute(a[2]);	/* a[2] = regular expr */
 		t = getsval(y);
 		pfa = makedfa(t, mode);
 		i = (*mf)(pfa, s);
-		tempfree(y, "");
+		tempfree(y);
 	}
-	tempfree(x, "");
+	tempfree(x);
 	if (n == MATCHFCN) {
 		int start = patbeg - s + 1;
 		if (patlen < 0)
 			start = 0;
 		(void) setfval(rstartloc, (Awkfloat)start);
 		(void) setfval(rlengthloc, (Awkfloat)patlen);
-		x = gettemp("");
+		x = gettemp();
 		x->tval = NUM;
 		x->fval = start;
 		return (x);
-	} else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
-		return (true);
+	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
+		return (True);
 	else
-		return (false);
+		return (False);
 }
 
-
 Cell *
-boolop(Node **a, int n)
+boolop(Node **a, int n)		/* a[0] || a[1], a[0] && a[1], !a[0] */
 {
-	register Cell *x, *y;
-	register int i;
+	Cell *x, *y;
+	int i;
 
 	x = execute(a[0]);
 	i = istrue(x);
-	tempfree(x, "");
+	tempfree(x);
 	switch (n) {
 	case BOR:
 		if (i)
-			return (true);
+			return (True);
 		y = execute(a[1]);
 		i = istrue(y);
-		tempfree(y, "");
-		return (i ? true : false);
+		tempfree(y);
+		return (i ? True : False);
 	case AND:
 		if (!i)
-			return (false);
+			return (False);
 		y = execute(a[1]);
 		i = istrue(y);
-		tempfree(y, "");
-		return (i ? true : false);
+		tempfree(y);
+		return (i ? True : False);
 	case NOT:
-		return (i ? false : true);
+		return (i ? False : True);
 	default:	/* can't happen */
-		ERROR "unknown boolean operator %d", n FATAL;
+		FATAL("unknown boolean operator %d", n);
 	}
 	/*NOTREACHED*/
 	return (NULL);
 }
 
 Cell *
-relop(Node **a, int n)
+relop(Node **a, int n)		/* a[0 < a[1], etc. */
 {
-	register int i;
-	register Cell *x, *y;
+	int i;
+	Cell *x, *y;
 	Awkfloat j;
 
 	x = execute(a[0]);
 	y = execute(a[1]);
-	if (x->tval&NUM && y->tval&NUM) {
+	if (x->tval & NUM && y->tval & NUM) {
 		j = x->fval - y->fval;
 		i = j < 0 ? -1: (j > 0 ? 1: 0);
 	} else {
 		i = strcmp((char *)getsval(x), (char *)getsval(y));
 	}
-	tempfree(x, "");
-	tempfree(y, "");
+	tempfree(x);
+	tempfree(y);
 	switch (n) {
-	case LT:	return (i < 0 ? true : false);
-	case LE:	return (i <= 0 ? true : false);
-	case NE:	return (i != 0 ? true : false);
-	case EQ:	return (i == 0 ? true : false);
-	case GE:	return (i >= 0 ? true : false);
-	case GT:	return (i > 0 ? true : false);
+	case LT:	return (i < 0 ? True : False);
+	case LE:	return (i <= 0 ? True : False);
+	case NE:	return (i != 0 ? True : False);
+	case EQ:	return (i == 0 ? True : False);
+	case GE:	return (i >= 0 ? True : False);
+	case GT:	return (i > 0 ? True : False);
 	default:	/* can't happen */
-		ERROR "unknown relational operator %d", n FATAL;
+		FATAL("unknown relational operator %d", n);
 	}
 	/*NOTREACHED*/
-	return (false);
+	return (False);
 }
 
 static void
-tfree(Cell *a, char *s)
+tfree(Cell *a)		/* free a tempcell */
 {
-	if (dbg > 1) {
-		(void) printf("## tfree %.8s %06lo %s\n",
-		    s, (ulong_t)a, a->sval ? a->sval : (uchar *)"");
-	}
-	if (freeable(a))
+	if (freeable(a)) {
+		dprintf(("freeing %s %s %o\n", (char *)a->nval,
+		    (char *)a->sval, a->tval));
 		xfree(a->sval);
+	}
 	if (a == tmps)
-		ERROR "tempcell list is curdled" FATAL;
+		FATAL("tempcell list is curdled");
 	a->cnext = tmps;
 	tmps = a;
 }
 
 static Cell *
-gettemp(char *s)
+gettemp(void)		/* get a tempcell */
 {
 	int i;
-	register Cell *x;
+	Cell *x;
 
 	if (!tmps) {
 		tmps = (Cell *)calloc(100, sizeof (Cell));
 		if (!tmps)
-			ERROR "no space for temporaries" FATAL;
+			FATAL("out of space for temporaries");
 		for (i = 1; i < 100; i++)
-			tmps[i-1].cnext = &tmps[i];
-		tmps[i-1].cnext = 0;
+			tmps[i - 1].cnext = &tmps[i];
+		tmps[i - 1].cnext = 0;
 	}
 	x = tmps;
 	tmps = x->cnext;
 	*x = tempcell;
-	if (dbg > 1)
-		(void) printf("## gtemp %.8s %06lo\n", s, (ulong_t)x);
 	return (x);
 }
 
 /*ARGSUSED*/
 Cell *
-indirect(Node **a, int n)
+indirect(Node **a, int n)	/* $( a[0] ) */
 {
-	register Cell *x;
-	register int m;
-	register uchar *s;
+	Awkfloat val;
+	Cell *x;
+	int m;
+	uchar *s;
 
 	x = execute(a[0]);
-	m = (int)getfval(x);
+	/* freebsd: defend against super large field numbers */
+	val = getfval(x);
+	if ((Awkfloat)INT_MAX < val)
+		FATAL("trying to access out of range field %s", x->nval);
+	m = (int)val;
 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
-		ERROR "illegal field $(%s)", s FATAL;
-	tempfree(x, "");
+		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
+		/* BUG: can x->nval ever be null??? */
+	tempfree(x);
 	x = fieldadr(m);
-	x->ctype = OCELL;
+	x->ctype = OCELL;	/* BUG?  why are these needed? */
 	x->csub = CFLD;
 	return (x);
 }
 
 /*ARGSUSED*/
 Cell *
-substr(Node **a, int nnn)
+substr(Node **a, int nnn)	/* substr(a[0], a[1], a[2]) */
 {
-	register int k, m, n;
-	register uchar *s;
+	int k, m, n;
+	uchar *s;
 	int temp;
-	register Cell *x, *y, *z;
+	Cell *x, *y, *z = 0;
 
 	x = execute(a[0]);
 	y = execute(a[1]);
@@ -720,11 +805,12 @@
 	s = getsval(x);
 	k = strlen((char *)s) + 1;
 	if (k <= 1) {
-		tempfree(x, "");
-		tempfree(y, "");
-		if (a[2] != 0)
-			tempfree(z, "");
-		x = gettemp("");
+		tempfree(x);
+		tempfree(y);
+		if (a[2] != 0) {
+			tempfree(z);
+		}
+		x = gettemp();
 		(void) setsval(x, (uchar *)"");
 		return (x);
 	}
@@ -733,10 +819,10 @@
 		m = 1;
 	else if (m > k)
 		m = k;
-	tempfree(y, "");
+	tempfree(y);
 	if (a[2] != 0) {
 		n = (int)getfval(z);
-		tempfree(z, "");
+		tempfree(z);
 	} else
 		n = k - 1;
 	if (n < 0)
@@ -744,21 +830,21 @@
 	else if (n > k - m)
 		n = k - m;
 	dprintf(("substr: m=%d, n=%d, s=%s\n", m, n, s));
-	y = gettemp("");
+	y = gettemp();
 	temp = s[n + m - 1];	/* with thanks to John Linderman */
 	s[n + m - 1] = '\0';
 	(void) setsval(y, s + m - 1);
 	s[n + m - 1] = temp;
-	tempfree(x, "");
+	tempfree(x);
 	return (y);
 }
 
 /*ARGSUSED*/
 Cell *
-sindex(Node **a, int nnn)
+sindex(Node **a, int nnn)	/* index(a[0], a[1]) */
 {
-	register Cell *x, *y, *z;
-	register uchar *s1, *s2, *p1, *p2, *q;
+	Cell *x, *y, *z;
+	uchar *s1, *s2, *p1, *p2, *q;
 	Awkfloat v = 0.0;
 
 	x = execute(a[0]);
@@ -766,179 +852,222 @@
 	y = execute(a[1]);
 	s2 = getsval(y);
 
-	z = gettemp("");
+	z = gettemp();
 	for (p1 = s1; *p1 != '\0'; p1++) {
 		for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
 			;
 		if (*p2 == '\0') {
-			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
+			v = (Awkfloat)(p1 - s1 + 1);	/* origin 1 */
 			break;
 		}
 	}
-	tempfree(x, "");
-	tempfree(y, "");
+	tempfree(x);
+	tempfree(y);
 	(void) setfval(z, v);
 	return (z);
 }
 
-void
-format(uchar **bufp, uchar *s, Node *a)
+#define	MAXNUMSIZE	50
+
+/*
+ * printf-like conversions
+ */
+int
+format(uchar **bufp, size_t *pbufsize, const uchar *s, Node *a)
 {
 	uchar *fmt;
-	register uchar *os;
-	register Cell *x;
-	int flag = 0, len;
-	uchar_t	*buf;
-	size_t bufsize, fmtsize, cnt, tcnt, ret;
+	uchar *p, *t;
+	const uchar *os;
+	Cell *x;
+	int flag = 0, n;
+	int fmtwd; /* format width */
+	size_t fmtsz = record_size;
+	uchar_t	*buf = *bufp;
+	size_t bufsize = *pbufsize;
 
-	init_buf(&buf, &bufsize, LINE_INCR);
-	init_buf(&fmt, &fmtsize, LINE_INCR);
 	os = s;
-	cnt = 0;
+	p = buf;
+	if ((fmt = (uchar *)malloc(fmtsz)) == NULL)
+		FATAL("out of memory in format()");
 	while (*s) {
+		(void) adjbuf(&buf, &bufsize, MAXNUMSIZE + 1 + p - buf,
+		    record_size, &p, "format1");
 		if (*s != '%') {
-			expand_buf(&buf, &bufsize, cnt);
-			buf[cnt++] = *s++;
+			*p++ = *s++;
 			continue;
 		}
 		if (*(s+1) == '%') {
-			expand_buf(&buf, &bufsize, cnt);
-			buf[cnt++] = '%';
+			*p++ = '%';
 			s += 2;
 			continue;
 		}
-		for (tcnt = 0; ; s++) {
-			expand_buf(&fmt, &fmtsize, tcnt);
-			fmt[tcnt++] = *s;
-			if (*s == '\0')
-				break;
-			if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
-				break;	/* the ansi panoply */
+		/*
+		 * have to be real careful in case this is a huge number,
+		 * eg, %100000d
+		 */
+		fmtwd = atoi((char *)s + 1);
+		if (fmtwd < 0)
+			fmtwd = -fmtwd;
+		(void) adjbuf(&buf, &bufsize, fmtwd + 1 + p - buf,
+		    record_size, &p, "format2");
+		for (t = fmt; (*t++ = *s) != '\0'; s++) {
+			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE + 1 + t - fmt,
+			    record_size, &t, "format3"))
+				FATAL(
+			"format item %.30s... ran format() out of memory", os);
+			if (isalpha((uchar)*s) && *s != 'l' && *s != 'h' &&
+			    *s != 'L')
+				break;  /* the ansi panoply */
 			if (*s == '*') {
-				if (a == NULL) {
-					ERROR
-		"not enough args in printf(%s) or sprintf(%s)", os, os FATAL;
-				}
 				x = execute(a);
 				a = a->nnext;
-				tcnt--;
-				expand_buf(&fmt, &fmtsize, tcnt + 12);
-				ret = sprintf((char *)&fmt[tcnt], "%d",
-				    (int)getfval(x));
-				tcnt += ret;
-				tempfree(x, "");
+				(void) sprintf((char *)t - 1, "%d",
+				    fmtwd = (int)getfval(x));
+				if (fmtwd < 0)
+					fmtwd = -fmtwd;
+				(void) adjbuf(&buf, &bufsize, fmtwd + 1 + p -
+				    buf, record_size, &p, "format");
+				t = fmt + strlen((char *)fmt);
+				tempfree(x);
 			}
 		}
-		fmt[tcnt] = '\0';
+		*t = '\0';
+		if (fmtwd < 0)
+			fmtwd = -fmtwd;
+		(void) adjbuf(&buf, &bufsize, fmtwd + 1 + p - buf,
+		    record_size, &p, "format4");
 
 		switch (*s) {
 		case 'f': case 'e': case 'g': case 'E': case 'G':
-			flag = 1;
+			flag = 'f';
 			break;
 		case 'd': case 'i':
-			flag = 2;
+			flag = 'd';
 			if (*(s-1) == 'l')
 				break;
-			fmt[tcnt - 1] = 'l';
-			expand_buf(&fmt, &fmtsize, tcnt);
-			fmt[tcnt++] = 'd';
-			fmt[tcnt] = '\0';
+			*(t-1) = 'l';
+			*t = 'd';
+			*++t = '\0';
 			break;
 		case 'o': case 'x': case 'X': case 'u':
-			flag = *(s-1) == 'l' ? 2 : 3;
+			flag = *(s-1) == 'l' ? 'd' : 'u';
 			break;
 		case 's':
-			flag = 4;
+			flag = 's';
 			break;
 		case 'c':
-			flag = 5;
+			flag = 'c';
 			break;
 		default:
-			flag = 0;
+			WARNING("weird printf conversion %s", fmt);
+			flag = '?';
 			break;
 		}
-		if (flag == 0) {
-			len = strlen((char *)fmt);
-			expand_buf(&buf, &bufsize, cnt + len);
-			(void) memcpy(&buf[cnt], fmt, len);
-			cnt += len;
-			buf[cnt] = '\0';
-			continue;
-		}
 		if (a == NULL) {
-			ERROR
-	"not enough args in printf(%s) or sprintf(%s)", os, os FATAL;
+			FATAL(
+	"not enough args in printf(%s)", os);
 		}
 		x = execute(a);
 		a = a->nnext;
-		for (;;) {
-			/* make sure we have at least 1 byte space */
-			expand_buf(&buf, &bufsize, cnt + 1);
-			len = bufsize - cnt;
-			switch (flag) {
-			case 1:
-				/*LINTED*/
-				ret = snprintf((char *)&buf[cnt], len,
-				    (char *)fmt, getfval(x));
-				break;
-			case 2:
-				/*LINTED*/
-				ret = snprintf((char *)&buf[cnt], len,
-				    (char *)fmt, (long)getfval(x));
-				break;
-			case 3:
-				/*LINTED*/
-				ret = snprintf((char *)&buf[cnt], len,
-				    (char *)fmt, (int)getfval(x));
-				break;
-			case 4:
-				/*LINTED*/
-				ret = snprintf((char *)&buf[cnt], len,
-				    (char *)fmt, getsval(x));
-				break;
-			case 5:
-				if (isnum(x)) {
-					/*LINTED*/
-					ret = snprintf((char *)&buf[cnt], len,
-					    (char *)fmt, (int)getfval(x));
-				} else {
-					/*LINTED*/
-					ret = snprintf((char *)&buf[cnt], len,
-					    (char *)fmt, getsval(x)[0]);
+		n = MAXNUMSIZE;
+		if (fmtwd > n)
+			n = fmtwd;
+		(void) adjbuf(&buf, &bufsize, 1 + n + p - buf, record_size,
+		    &p, "format5");
+
+		switch (flag) {
+		case '?':
+			/* unknown, so dump it too */
+			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
+			(void) sprintf((char *)p, "%s", (char *)fmt);
+			t = getsval(x);
+			n = strlen((char *)t);
+			if (fmtwd > n)
+				n = fmtwd;
+			(void) adjbuf(&buf, &bufsize, 1 + strlen((char *)p) +
+			    n + p - buf, record_size, &p, "format6");
+			p += strlen((char *)p);
+			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
+			(void) sprintf((char *)p, "%s", t);
+			break;
+		case 'f':
+			/* LINTED E_SEC_PRINTF_VAR_FMT */
+			(void) sprintf((char *)p, (char *)fmt, getfval(x));
+			break;
+		case 'd':
+			/* LINTED E_SEC_PRINTF_VAR_FMT */
+			(void) sprintf((char *)p, (char *)fmt,
+			    (long) getfval(x));
+			break;
+		case 'u':
+			/* LINTED E_SEC_PRINTF_VAR_FMT */
+			(void) sprintf((char *)p, (char *)fmt,
+			    (int) getfval(x));
+			break;
+		case 's':
+			t = getsval(x);
+			n = strlen((char *)t);
+			if (fmtwd > n)
+				n = fmtwd;
+			if (!adjbuf(&buf, &bufsize, 1+n+p-buf, record_size,
+			    &p, "format7"))
+				FATAL(
+		"huge string/format (%d chars) in printf %.30s... "
+		"ran format() out of memory", n, t);
+			/* LINTED E_SEC_PRINTF_VAR_FMT */
+			(void) sprintf((char *)p, (char *)fmt, t);
+			break;
+		case 'c':
+			if (isnum(x)) {
+				if (getfval(x))
+					/* LINTED E_SEC_PRINTF_VAR_FMT */
+					(void) sprintf((char *)p, (char *)fmt,
+					    (int) getfval(x));
+				else {
+					*p++ = '\0'; /* explicit null byte */
+					/* next output will start here */
+					*p = '\0';
 				}
-				break;
-			default:
-				ret = 0;
+			} else {
+				/* LINTED E_SEC_PRINTF_VAR_FMT */
+				(void) sprintf((char *)p, (char *)fmt,
+				    getsval(x)[0]);
 			}
-			if (ret < len)
-				break;
-			expand_buf(&buf, &bufsize, cnt + ret);
+			break;
+		default:
+			FATAL("can't happen: bad conversion %c in format()",
+			    flag);
 		}
-		tempfree(x, "");
-		cnt += ret;
+		tempfree(x);
+		p += strlen((char *)p);
 		s++;
 	}
-	buf[cnt] = '\0';
+	*p = '\0';
+	free(fmt);
 	for (; a; a = a->nnext)	/* evaluate any remaining args */
 		(void) execute(a);
-	*bufp = tostring(buf);
-	free(buf);
-	free(fmt);
+	*bufp = buf;
+	*pbufsize = bufsize;
+	return (p - buf);
 }
 
 /*ARGSUSED*/
 Cell *
-a_sprintf(Node **a, int n)
+awksprintf(Node **a, int n)	/* sprintf(a[0]) */
 {
-	register Cell *x;
-	register Node *y;
+	Cell *x;
+	Node *y;
 	uchar *buf;
+	size_t bufsz = 3 * record_size;
 
+	if ((buf = (uchar *)malloc(bufsz)) == NULL)
+		FATAL("out of memory in awksprintf");
 	y = a[0]->nnext;
 	x = execute(a[0]);
-	format(&buf, getsval(x), y);
-	tempfree(x, "");
-	x = gettemp("");
+	if (format(&buf, &bufsz, getsval(x), y) == -1)
+		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
+	tempfree(x);
+	x = gettemp();
 	x->sval = buf;
 	x->tval = STR;
 	return (x);
@@ -946,44 +1075,56 @@
 
 /*ARGSUSED*/
 Cell *
-aprintf(Node **a, int n)
-{
+awkprintf(Node **a, int n)	/* printf */
+{	/* a[0] is list of args, starting with format string */
+	/* a[1] is redirection operator, a[2] is redirection file */
 	FILE *fp;
-	register Cell *x;
-	register Node *y;
+	Cell *x;
+	Node *y;
 	uchar *buf;
+	int len;
+	size_t bufsz = 3 * record_size;
 
+	if ((buf = (uchar *)malloc(bufsz)) == NULL)
+		FATAL("out of memory in awkprintf");
 	y = a[0]->nnext;
 	x = execute(a[0]);
-	format(&buf, getsval(x), y);
-	tempfree(x, "");
-	if (a[1] == NULL)
-		(void) fputs((char *)buf, stdout);
-	else {
-		fp = redirect((int)a[1], a[2]);
-		(void) fputs((char *)buf, fp);
+	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
+		FATAL("printf string %.30s... too long.  can't happen.", buf);
+	tempfree(x);
+	if (a[1] == NULL) {
+		/* fputs(buf, stdout); */
+		(void) fwrite((char *)buf, len, 1, stdout);
+		if (ferror(stdout))
+			FATAL("write error on stdout");
+	} else {
+		fp = redirect(ptoi(a[1]), a[2]);
+		/* fputs(buf, fp); */
+		(void) fwrite(buf, len, 1, fp);
 		(void) fflush(fp);
+		if (ferror(fp))
+			FATAL("write error on %s", filename(fp));
 	}
 	free(buf);
-	return (true);
+	return (True);
 }
 
 Cell *
-arith(Node **a, int n)
+arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
 {
-	Awkfloat i, j;
+	Awkfloat i, j = 0;
 	double v;
-	register Cell *x, *y, *z;
+	Cell *x, *y, *z;
 
 	x = execute(a[0]);
 	i = getfval(x);
-	tempfree(x, "");
+	tempfree(x);
 	if (n != UMINUS) {
 		y = execute(a[1]);
 		j = getfval(y);
-		tempfree(y, "");
+		tempfree(y);
 	}
-	z = gettemp("");
+	z = gettemp();
 	switch (n) {
 	case ADD:
 		i += j;
@@ -996,12 +1137,12 @@
 		break;
 	case DIVIDE:
 		if (j == 0)
-			ERROR "division by zero" FATAL;
+			FATAL("division by zero");
 		i /= j;
 		break;
 	case MOD:
 		if (j == 0)
-			ERROR "division by zero in mod" FATAL;
+			FATAL("division by zero in mod");
 		(void) modf(i/j, &v);
 		i = i - j * v;
 		break;
@@ -1015,20 +1156,20 @@
 			i = errcheck(pow(i, j), "pow");
 		break;
 	default:	/* can't happen */
-		ERROR "illegal arithmetic operator %d", n FATAL;
+		FATAL("illegal arithmetic operator %d", n);
 	}
 	(void) setfval(z, i);
 	return (z);
 }
 
 static double
-ipow(double x, int n)
+ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
 {
 	double v;
 
 	if (n <= 0)
 		return (1.0);
-	v = ipow(x, n/2);
+	v = ipow(x, n / 2);
 	if (n % 2 == 0)
 		return (v * v);
 	else
@@ -1036,10 +1177,10 @@
 }
 
 Cell *
-incrdecr(Node **a, int n)
+incrdecr(Node **a, int n)	/* a[0]++, etc. */
 {
-	register Cell *x, *z;
-	register int k;
+	Cell *x, *z;
+	int k;
 	Awkfloat xf;
 
 	x = execute(a[0]);
@@ -1049,34 +1190,39 @@
 		(void) setfval(x, xf + k);
 		return (x);
 	}
-	z = gettemp("");
+	z = gettemp();
 	(void) setfval(z, xf);
 	(void) setfval(x, xf + k);
-	tempfree(x, "");
+	tempfree(x);
 	return (z);
 }
 
 Cell *
-assign(Node **a, int n)
-{
-	register Cell *x, *y;
+assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
+{			/* this is subtle; don't muck with it. */
+	Cell *x, *y;
 	Awkfloat xf, yf;
 	double v;
 
 	y = execute(a[1]);
-	x = execute(a[0]);	/* order reversed from before... */
+	x = execute(a[0]);
 	if (n == ASSIGN) {	/* ordinary assignment */
-		if ((y->tval & (STR|NUM)) == (STR|NUM)) {
+		/* self-assignment: */
+		/* LINTED E_NOP_IF_STMT */
+		if (x == y && !(x->tval & (FLD|REC)))
+			/* leave alone unless it's a field */
+			;
+		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
 			(void) setsval(x, getsval(y));
 			x->fval = getfval(y);
 			x->tval |= NUM;
-		} else if (y->tval & STR)
+		} else if (isstr(y))
 			(void) setsval(x, getsval(y));
-		else if (y->tval & NUM)
+		else if (isnum(y))
 			(void) setfval(x, getfval(y));
 		else
 			funnyvar(y, "read value of");
-		tempfree(y, "");
+		tempfree(y);
 		return (x);
 	}
 	xf = getfval(x);
@@ -1093,12 +1239,12 @@
 		break;
 	case DIVEQ:
 		if (yf == 0)
-			ERROR "division by zero in /=" FATAL;
+			FATAL("division by zero in /=");
 		xf /= yf;
 		break;
 	case MODEQ:
 		if (yf == 0)
-			ERROR "division by zero in %%=" FATAL;
+			FATAL("division by zero in %%=");
 		(void) modf(xf/yf, &v);
 		xf = xf - yf * v;
 		break;
@@ -1109,21 +1255,21 @@
 			xf = errcheck(pow(xf, yf), "pow");
 		break;
 	default:
-		ERROR "illegal assignment operator %d", n FATAL;
+		FATAL("illegal assignment operator %d", n);
 		break;
 	}
-	tempfree(y, "");
+	tempfree(y);
 	(void) setfval(x, xf);
 	return (x);
 }
 
 /*ARGSUSED*/
 Cell *
-cat(Node **a, int q)
+cat(Node **a, int q)		/* a[0] cat a[1] */
 {
-	register Cell *x, *y, *z;
-	register int n1, n2;
-	register uchar *s;
+	Cell *x, *y, *z;
+	int n1, n2;
+	uchar *s;
 
 	x = execute(a[0]);
 	y = execute(a[1]);
@@ -1133,31 +1279,31 @@
 	n2 = strlen((char *)y->sval);
 	s = (uchar *)malloc(n1 + n2 + 1);
 	if (s == NULL) {
-		ERROR "out of space concatenating %.15s and %.15s",
-		    x->sval, y->sval FATAL;
+		FATAL("out of space concatenating %.15s... and %.15s...",
+		    x->sval, y->sval);
 	}
 	(void) strcpy((char *)s, (char *)x->sval);
 	(void) strcpy((char *)s + n1, (char *)y->sval);
-	tempfree(y, "");
-	z = gettemp("");
+	tempfree(x);
+	tempfree(y);
+	z = gettemp();
 	z->sval = s;
 	z->tval = STR;
-	tempfree(x, "");
 	return (z);
 }
 
 /*ARGSUSED*/
 Cell *
-pastat(Node **a, int n)
+pastat(Node **a, int n)		/* a[0] { a[1] } */
 {
-	register Cell *x;
+	Cell *x;
 
 	if (a[0] == 0)
 		x = execute(a[1]);
 	else {
 		x = execute(a[0]);
 		if (istrue(x)) {
-			tempfree(x, "");
+			tempfree(x);
 			x = execute(a[1]);
 		}
 	}
@@ -1166,60 +1312,51 @@
 
 /*ARGSUSED*/
 Cell *
-dopa2(Node **a, int n)
+dopa2(Node **a, int n)		/* a[0], a[1] { a[2] } */
 {
-	Cell	*x;
-	int	pair;
-	static int	*pairstack = NULL;
-
-	if (!pairstack) {
-		/* first time */
-		dprintf(("paircnt: %d\n", paircnt));
-		pairstack = (int *)malloc(sizeof (int) * paircnt);
-		if (!pairstack)
-			ERROR "out of space in dopa2" FATAL;
-		(void) memset(pairstack, 0, sizeof (int) * paircnt);
-	}
+	Cell *x;
+	int pair;
 
-	pair = (int)a[3];
+	pair = ptoi(a[3]);
 	if (pairstack[pair] == 0) {
 		x = execute(a[0]);
 		if (istrue(x))
 			pairstack[pair] = 1;
-		tempfree(x, "");
+		tempfree(x);
 	}
 	if (pairstack[pair] == 1) {
 		x = execute(a[1]);
 		if (istrue(x))
 			pairstack[pair] = 0;
-		tempfree(x, "");
+		tempfree(x);
 		x = execute(a[2]);
 		return (x);
 	}
-	return (false);
+	return (False);
 }
 
 /*ARGSUSED*/
 Cell *
-split(Node **a, int nnn)
+split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
 {
-	Cell *x, *y, *ap;
-	register uchar *s;
-	register int sep;
-	uchar *t, temp, num[11], *fs;
-	int n, tempstat;
+	Cell *x = 0, *y, *ap;
+	uchar *s, *origs;
+	int sep;
+	uchar *t, temp, num[50], *fs = 0;
+	int n, tempstat, arg3type;
 
 	y = execute(a[0]);	/* source string */
-	s = getsval(y);
+	origs = s = (uchar *)strdup((char *)getsval(y));
+	arg3type = ptoi(a[3]);
 	if (a[2] == 0)		/* fs string */
 		fs = *FS;
-	else if ((int)a[3] == STRING) {	/* split(str,arr,"string") */
+	else if (arg3type == STRING) {	/* split(str,arr,"string") */
 		x = execute(a[2]);
 		fs = getsval(x);
-	} else if ((int)a[3] == REGEXPR)
+	} else if (arg3type == REGEXPR)
 		fs = (uchar *)"(regexpr)";	/* split(str,arr,/regexpr/) */
 	else
-		ERROR "illegal type of split()" FATAL;
+		FATAL("illegal type of split");
 	sep = *fs;
 	ap = execute(a[1]);	/* array name */
 	freesymtab(ap);
@@ -1229,10 +1366,15 @@
 	ap->sval = (uchar *)makesymtab(NSYMTAB);
 
 	n = 0;
-	if (*s != '\0' && strlen((char *)fs) > 1 || (int)a[3] == REGEXPR) {
+	if (arg3type == REGEXPR && strlen((char *)((fa *)a[2])->restr) == 0) {
+		arg3type = 0;
+		fs = (uchar *)"";
+		sep = 0;
+	}
+	if (*s != '\0' && (strlen((char *)fs) > 1 || arg3type == REGEXPR)) {
 		/* reg expr */
 		fa *pfa;
-		if ((int)a[3] == REGEXPR) {	/* it's ready already */
+		if (arg3type == REGEXPR) {	/* it's ready already */
 			pfa = (fa *)a[2];
 		} else {
 			pfa = makedfa(fs, 1);
@@ -1267,6 +1409,9 @@
 					goto spdone;
 				}
 			} while (nematch(pfa, s));
+			/* bwk: has to be here to reset */
+			pfa->initstat = tempstat;
+			/* cf gsub and refldbld */
 		}
 		n++;
 		(void) sprintf((char *)num, "%d", n);
@@ -1309,6 +1454,23 @@
 			if (*s != 0)
 				s++;
 		}
+	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
+		for (n = 0; *s != 0; s++) {
+			uchar buf[2];
+			n++;
+			(void) sprintf((char *)num, "%d", n);
+			buf[0] = *s;
+			buf[1] = 0;
+			if (isdigit(buf[0])) {
+				(void) setsymtab(num, buf, atof((char *)buf),
+				    /* LINTED align */
+				    STR | NUM, (Array *)ap->sval);
+			} else {
+				(void) setsymtab(num, buf, 0.0,
+				    /* LINTED align */
+				    STR, (Array *)ap->sval);
+			}
+		}
 	} else if (*s != 0) {
 		for (;;) {
 			n++;
@@ -1332,11 +1494,13 @@
 				break;
 		}
 	}
-	tempfree(ap, "");
-	tempfree(y, "");
-	if (a[2] != 0 && (int)a[3] == STRING)
-		tempfree(x, "");
-	x = gettemp("");
+	tempfree(ap);
+	tempfree(y);
+	free(origs);
+	if (a[2] != 0 && arg3type == STRING) {
+		tempfree(x);
+	}
+	x = gettemp();
 	x->tval = NUM;
 	x->fval = n;
 	return (x);
@@ -1344,16 +1508,16 @@
 
 /*ARGSUSED*/
 Cell *
-condexpr(Node **a, int n)
+condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
 {
-	register Cell *x;
+	Cell *x;
 
 	x = execute(a[0]);
 	if (istrue(x)) {
-		tempfree(x, "");
+		tempfree(x);
 		x = execute(a[1]);
 	} else {
-		tempfree(x, "");
+		tempfree(x);
 		x = execute(a[2]);
 	}
 	return (x);
@@ -1361,16 +1525,16 @@
 
 /*ARGSUSED*/
 Cell *
-ifstat(Node **a, int n)
+ifstat(Node **a, int n)		/* if (a[0]) a[1]; else a[2] */
 {
-	register Cell *x;
+	Cell *x;
 
 	x = execute(a[0]);
 	if (istrue(x)) {
-		tempfree(x, "");
+		tempfree(x);
 		x = execute(a[1]);
 	} else if (a[2] != 0) {
-		tempfree(x, "");
+		tempfree(x);
 		x = execute(a[2]);
 	}
 	return (x);
@@ -1378,123 +1542,136 @@
 
 /*ARGSUSED*/
 Cell *
-whilestat(Node **a, int n)
+whilestat(Node **a, int n)	/* while (a[0]) a[1] */
 {
-	register Cell *x;
+	Cell *x;
 
 	for (;;) {
 		x = execute(a[0]);
 		if (!istrue(x))
 			return (x);
-		tempfree(x, "");
+		tempfree(x);
 		x = execute(a[1]);
 		if (isbreak(x)) {
-			x = true;
+			x = True;
 			return (x);
 		}
 		if (isnext(x) || isexit(x) || isret(x))
 			return (x);
-		tempfree(x, "");
+		tempfree(x);
 	}
 }
 
 /*ARGSUSED*/
 Cell *
-dostat(Node **a, int n)
+dostat(Node **a, int n)		/* do a[0]; while(a[1]) */
 {
-	register Cell *x;
+	Cell *x;
 
 	for (;;) {
 		x = execute(a[0]);
 		if (isbreak(x))
-			return (true);
+			return (True);
 		if (isnext(x) || isexit(x) || isret(x))
 			return (x);
-		tempfree(x, "");
+		tempfree(x);
 		x = execute(a[1]);
 		if (!istrue(x))
 			return (x);
-		tempfree(x, "");
+		tempfree(x);
 	}
 }
 
 /*ARGSUSED*/
 Cell *
-forstat(Node **a, int n)
+forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
 {
-	register Cell *x;
+	Cell *x;
 
 	x = execute(a[0]);
-	tempfree(x, "");
+	tempfree(x);
 	for (;;) {
 		if (a[1] != 0) {
 			x = execute(a[1]);
 			if (!istrue(x))
 				return (x);
 			else
-				tempfree(x, "");
+				tempfree(x);
 		}
 		x = execute(a[3]);
 		if (isbreak(x))		/* turn off break */
-			return (true);
+			return (True);
 		if (isnext(x) || isexit(x) || isret(x))
 			return (x);
-		tempfree(x, "");
+		tempfree(x);
 		x = execute(a[2]);
-		tempfree(x, "");
+		tempfree(x);
 	}
 }
 
 /*ARGSUSED*/
 Cell *
-instat(Node **a, int n)
+instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
 {
-	register Cell *x, *vp, *arrayp, *cp, *ncp;
+	Cell *x, *vp, *arrayp, *cp, *ncp;
 	Array *tp;
 	int i;
 
 	vp = execute(a[0]);
 	arrayp = execute(a[1]);
-	if (!isarr(arrayp))
-		ERROR "%s is not an array", arrayp->nval FATAL;
+	if (!isarr(arrayp)) {
+		return (True);
+	}
 	/*LINTED align*/
 	tp = (Array *)arrayp->sval;
-	tempfree(arrayp, "");
+	tempfree(arrayp);
 	for (i = 0; i < tp->size; i++) { /* this routine knows too much */
 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
 			(void) setsval(vp, cp->nval);
 			ncp = cp->cnext;
 			x = execute(a[2]);
 			if (isbreak(x)) {
-				tempfree(vp, "");
-				return (true);
+				tempfree(vp);
+				return (True);
 			}
 			if (isnext(x) || isexit(x) || isret(x)) {
-				tempfree(vp, "");
+				tempfree(vp);
 				return (x);
 			}
-			tempfree(x, "");
+			tempfree(x);
 		}
 	}
-	return (true);
+	return (True);
 }
 
+/*
+ * builtin functions. a[0] is type, a[1] is arg list
+ */
 /*ARGSUSED*/
 Cell *
 bltin(Node **a, int n)
 {
-	register Cell *x, *y;
+	Cell *x, *y;
 	Awkfloat u;
-	register int t;
+	int t;
+	Awkfloat tmp;
 	uchar *p, *buf;
 	Node *nextarg;
+	FILE *fp;
 
-	t = (int)a[0];
+	t = ptoi(a[0]);
 	x = execute(a[1]);
 	nextarg = a[1]->nnext;
 	switch (t) {
 	case FLENGTH:
-		u = (Awkfloat)strlen((char *)getsval(x)); break;
+		if (isarr(x)) {
+			/* GROT.  should be function */
+			/* LINTED align */
+			u = (Awkfloat)((Array *)x->sval)->nelem;
+		} else {
+			u = (Awkfloat)strlen((char *)getsval(x));
+		}
+		break;
 	case FLOG:
 		u = errcheck(log(getfval(x)), "log"); break;
 	case FINT:
@@ -1509,13 +1686,12 @@
 		u = cos(getfval(x)); break;
 	case FATAN:
 		if (nextarg == 0) {
-			ERROR "atan2 requires two arguments; returning 1.0"
-			    WARNING;
+			WARNING("atan2 requires two arguments; returning 1.0");
 			u = 1.0;
 		} else {
 			y = execute(a[1]->nnext);
 			u = atan2(getfval(x), getfval(y));
-			tempfree(y, "");
+			tempfree(y);
 			nextarg = nextarg->nnext;
 		}
 		break;
@@ -1526,14 +1702,18 @@
 		u = (Awkfloat)system((char *)getsval(x)) / 256;
 		break;
 	case FRAND:
-		u = (Awkfloat)(rand() % 32767) / 32767.0;
+		/* in principle, rand() returns something in 0..RAND_MAX */
+		u = (Awkfloat)(rand() % RAND_MAX) / RAND_MAX;
 		break;
 	case FSRAND:
-		if (x->tval & REC)	/* no argument provided */
+		if (isrec(x))	/* no argument provided */
 			u = time((time_t *)0);
 		else
 			u = getfval(x);
-		srand((int)u); u = (int)u;
+		tmp = u;
+		srand((unsigned int)u);
+		u = srand_seed;
+		srand_seed = tmp;
 		break;
 	case FTOUPPER:
 	case FTOLOWER:
@@ -1547,20 +1727,30 @@
 				if (isupper(*p))
 					*p = tolower(*p);
 		}
-		tempfree(x, "");
-		x = gettemp("");
+		tempfree(x);
+		x = gettemp();
 		(void) setsval(x, buf);
 		free(buf);
 		return (x);
+	case FFLUSH:
+		if (isrec(x) || strlen((char *)getsval(x)) == 0) {
+			/* fflush() or fflush("") -> all */
+			flush_all();
+			u = 0;
+		} else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
+			u = EOF;
+		else
+			u = fflush(fp);
+		break;
 	default:	/* can't happen */
-		ERROR "illegal function type %d", t FATAL;
+		FATAL("illegal function type %d", t);
 		break;
 	}
-	tempfree(x, "");
-	x = gettemp("");
+	tempfree(x);
+	x = gettemp();
 	(void) setfval(x, u);
 	if (nextarg != 0) {
-		ERROR "warning: function has too many arguments" WARNING;
+		WARNING("warning: function has too many arguments");
 		for (; nextarg; nextarg = nextarg->nnext)
 			(void) execute(nextarg);
 	}
@@ -1569,20 +1759,20 @@
 
 /*ARGSUSED*/
 Cell *
-print(Node **a, int n)
+printstat(Node **a, int n)		/* print a[0] */
 {
-	register Node *x;
-	register Cell *y;
+	Node *x;
+	Cell *y;
 	FILE *fp;
 
-	if (a[1] == 0)
+	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
 		fp = stdout;
 	else
-		fp = redirect((int)a[1], a[2]);
+		fp = redirect(ptoi(a[1]), a[2]);
 	for (x = a[0]; x != NULL; x = x->nnext) {
 		y = execute(x);
 		(void) fputs((char *)getsval(y), fp);
-		tempfree(y, "");
+		tempfree(y);
 		if (x->nnext == NULL)
 			(void) fputs((char *)*ORS, fp);
 		else
@@ -1590,7 +1780,9 @@
 	}
 	if (a[1] != 0)
 		(void) fflush(fp);
-	return (true);
+	if (ferror(fp))
+		FATAL("write error on %s", filename(fp));
+	return (True);
 }
 
 /*ARGSUSED*/
@@ -1600,14 +1792,8 @@
 	return (0);
 }
 
-struct {
-	FILE	*fp;
-	uchar	*fname;
-	int	mode;	/* '|', 'a', 'w' */
-} files[FOPEN_MAX];
-
 static FILE *
-redirect(int a, Node *b)
+redirect(int a, Node *b)	/* set up all i/o redirections */
 {
 	FILE *fp;
 	Cell *x;
@@ -1617,34 +1803,74 @@
 	fname = getsval(x);
 	fp = openfile(a, fname);
 	if (fp == NULL)
-		ERROR "can't open file %s", fname FATAL;
-	tempfree(x, "");
+		FATAL("can't open file %s", fname);
+	tempfree(x);
 	return (fp);
 }
 
+struct files {
+	FILE	*fp;
+	const uchar	*fname;
+	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
+} *files;
+
+int nfiles;
+
+static void
+stdinit(void)	/* in case stdin, etc., are not constants */
+{
+	nfiles = FOPEN_MAX;
+	files = calloc(nfiles, sizeof (*files));
+	if (files == NULL)
+		FATAL("can't allocate file memory for %u files", nfiles);
+	files[0].fp = stdin;
+	files[0].fname = (uchar *)"/dev/stdin";
+	files[0].mode = LT;
+	files[1].fp = stdout;
+	files[1].fname = (uchar *)"/dev/stdout";
+	files[1].mode = GT;
+	files[2].fp = stderr;
+	files[2].fname = (uchar *)"/dev/stderr";
+	files[2].mode = GT;
+}
+
 static FILE *
-openfile(int a, uchar *s)
+openfile(int a, const uchar *us)
 {
-	register int i, m;
-	register FILE *fp;
+	const uchar *s = us;
+	int i, m;
+	FILE *fp = 0;
 
 	if (*s == '\0')
-		ERROR "null file name in print or getline" FATAL;
-	for (i = 0; i < FOPEN_MAX; i++) {
+		FATAL("null file name in print or getline");
+	for (i = 0; i < nfiles; i++) {
 		if (files[i].fname &&
-		    strcmp((char *)s, (char *)files[i].fname) == 0) {
+		    (strcmp((char *)s, (char *)files[i].fname) == 0)) {
 			if (a == files[i].mode ||
-			    a == APPEND && files[i].mode == GT) {
+			    (a == APPEND && files[i].mode == GT)) {
 				return (files[i].fp);
 			}
+			if (a == FFLUSH)
+				return (files[i].fp);
 		}
 	}
-	for (i = 0; i < FOPEN_MAX; i++) {
+	if (a == FFLUSH)	/* didn't find it, so don't create it! */
+		return (NULL);
+
+	for (i = 0; i < nfiles; i++) {
 		if (files[i].fp == 0)
 			break;
 	}
-	if (i >= FOPEN_MAX)
-		ERROR "%s makes too many open files", s FATAL;
+	if (i >= nfiles) {
+		struct files *nf;
+		int nnf = nfiles + FOPEN_MAX;
+		nf = realloc(files, nnf * sizeof (*nf));
+		if (nf == NULL)
+			FATAL("cannot grow files for %s and %d files", s, nnf);
+		(void) memset(&nf[nfiles], 0, FOPEN_MAX * sizeof (*nf));
+		nfiles = nnf;
+		files = nf;
+	}
 	(void) fflush(stdout);	/* force a semblance of order */
 	m = a;
 	if (a == GT) {
@@ -1660,7 +1886,7 @@
 		fp = strcmp((char *)s, "-") == 0 ?
 		    stdin : fopen((char *)s, "r");	/* "-" is stdin */
 	} else	/* can't happen */
-		ERROR "illegal redirection" FATAL;
+		FATAL("illegal redirection %d", a);
 	if (fp != NULL) {
 		files[i].fname = tostring(s);
 		files[i].fp = fp;
@@ -1669,38 +1895,55 @@
 	return (fp);
 }
 
+static const char *
+filename(FILE *fp)
+{
+	int i;
+
+	for (i = 0; i < nfiles; i++) {
+		if (fp == files[i].fp)
+			return ((char *)files[i].fname);
+	}
+
+	return ("???");
+}
+
 /*ARGSUSED*/
 Cell *
 closefile(Node **a, int n)
 {
-	register Cell *x;
+	Cell *x;
 	int i, stat;
 
 	x = execute(a[0]);
 	(void) getsval(x);
-	for (i = 0; i < FOPEN_MAX; i++) {
+	stat = -1;
+	for (i = 0; i < nfiles; i++) {
 		if (files[i].fname &&
 		    strcmp((char *)x->sval, (char *)files[i].fname) == 0) {
 			if (ferror(files[i].fp)) {
-				ERROR "i/o error occurred on %s",
-				    files[i].fname WARNING;
+				WARNING("i/o error occurred on %s",
+				    files[i].fname);
 			}
 			if (files[i].mode == '|' || files[i].mode == LE)
 				stat = pclose(files[i].fp);
 			else
 				stat = fclose(files[i].fp);
 			if (stat == EOF) {
-				ERROR "i/o error occurred closing %s",
-				    files[i].fname WARNING;
+				WARNING("i/o error occurred closing %s",
+				    files[i].fname);
 			}
-			xfree(files[i].fname);
+			if (i > 2)	/* don't do /dev/std... */
+				xfree(files[i].fname);
 			/* watch out for ref thru this */
 			files[i].fname = NULL;
 			files[i].fp = NULL;
 		}
 	}
-	tempfree(x, "close");
-	return (true);
+	tempfree(x);
+	x = gettemp();
+	(void) setfval(x, (Awkfloat)stat);
+	return (x);
 }
 
 static void
@@ -1711,114 +1954,131 @@
 	for (i = 0; i < FOPEN_MAX; i++) {
 		if (files[i].fp) {
 			if (ferror(files[i].fp)) {
-				ERROR "i/o error occurred on %s",
-				    files[i].fname WARNING;
+				WARNING("i/o error occurred on %s",
+				    files[i].fname);
 			}
 			if (files[i].mode == '|' || files[i].mode == LE)
 				stat = pclose(files[i].fp);
 			else
 				stat = fclose(files[i].fp);
 			if (stat == EOF) {
-				ERROR "i/o error occurred while closing %s",
-				    files[i].fname WARNING;
+				WARNING("i/o error occurred while closing %s",
+				    files[i].fname);
 			}
 		}
 	}
 }
 
+static void
+flush_all(void)
+{
+	int i;
+
+	for (i = 0; i < nfiles; i++)
+		if (files[i].fp)
+			(void) fflush(files[i].fp);
+}
+
+void backsub(uchar **pb_ptr, uchar **sptr_ptr);
+
 /*ARGSUSED*/
 Cell *
-sub(Node **a, int nnn)
+sub(Node **a, int nnn)	/* substitute command */
 {
-	register uchar *sptr;
-	register Cell *x, *y, *result;
-	uchar *buf, *t;
+	uchar *sptr, *pb, *q;
+	Cell *x, *y, *result;
+	uchar *t, *buf;
 	fa *pfa;
-	size_t	bsize, cnt, len;
+	size_t	bufsz = record_size;
 
+	if ((buf = (uchar *)malloc(bufsz)) == NULL)
+		FATAL("out of memory in sub");
 	x = execute(a[3]);	/* target string */
 	t = getsval(x);
-	if (a[0] == 0)
+	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
 		pfa = (fa *)a[1];	/* regular expression */
 	else {
 		y = execute(a[1]);
 		pfa = makedfa(getsval(y), 1);
-		tempfree(y, "");
+		tempfree(y);
 	}
 	y = execute(a[2]);	/* replacement string */
-	result = false;
+	result = False;
 	if (pmatch(pfa, t)) {
-		init_buf(&buf, &bsize, LINE_INCR);
-		cnt = 0;
 		sptr = t;
-		len = patbeg - sptr;
-		if (len > 0) {
-			expand_buf(&buf, &bsize, cnt + len);
-			(void) memcpy(buf, sptr, len);
-			cnt += len;
-		}
+		(void) adjbuf(&buf, &bufsz, 1+patbeg-sptr, record_size,
+		    0, "sub");
+		pb = buf;
+		while (sptr < patbeg)
+			*pb++ = *sptr++;
 		sptr = getsval(y);
 		while (*sptr != 0) {
-			expand_buf(&buf, &bsize, cnt);
-			if (*sptr == '\\' &&
-			    (*(sptr+1) == '&' || *(sptr+1) == '\\')) {
-				sptr++;		/* skip \, */
-				buf[cnt++] = *sptr++; /* add & or \ */
+			(void) adjbuf(&buf, &bufsz, 5 + pb - buf, record_size,
+			    &pb, "sub");
+			if (*sptr == '\\') {
+				backsub(&pb, &sptr);
 			} else if (*sptr == '&') {
-				expand_buf(&buf, &bsize, cnt + patlen);
 				sptr++;
-				(void) memcpy(&buf[cnt], patbeg, patlen);
-				cnt += patlen;
+				(void) adjbuf(&buf, &bufsz, 1+patlen+pb-buf,
+				    record_size, &pb, "sub");
+				for (q = patbeg; q < patbeg + patlen; )
+					*pb++ = *q++;
 			} else {
-				buf[cnt++] = *sptr++;
+				*pb++ = *sptr++;
 			}
 		}
+		*pb = '\0';
+		if (pb > buf + bufsz)
+			FATAL("sub result1 %.30s too big; can't happen", buf);
 		sptr = patbeg + patlen;
 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
-			len = strlen((char *)sptr);
-			expand_buf(&buf, &bsize, cnt + len);
-			(void) memcpy(&buf[cnt], sptr, len);
-			cnt += len;
+			(void) adjbuf(&buf, &bufsz, 1 + strlen((char *)sptr) +
+			    pb - buf, 0, &pb, "sub");
+			while ((*pb++ = *sptr++) != 0)
+				;
 		}
-		buf[cnt] = '\0';
+		if (pb > buf + bufsz)
+			FATAL("sub result2 %.30s too big; can't happen", buf);
+		/* BUG: should be able to avoid copy */
 		(void) setsval(x, buf);
-		free(buf);
-		result = true;
+		result = True;
 	}
-	tempfree(x, "");
-	tempfree(y, "");
+	tempfree(x);
+	tempfree(y);
+	free(buf);
 	return (result);
 }
 
 /*ARGSUSED*/
 Cell *
-gsub(Node **a, int nnn)
+gsub(Node **a, int nnn)		/* global substitute */
 {
-	register Cell *x, *y;
-	register uchar *rptr, *sptr, *t;
+	Cell *x, *y;
+	uchar *rptr, *sptr, *t, *pb, *q;
 	uchar *buf;
-	register fa *pfa;
+	fa *pfa;
 	int mflag, tempstat, num;
-	size_t	bsize, cnt, len;
+	size_t bufsz = record_size;
 
+	if ((buf = (uchar *)malloc(bufsz)) == NULL)
+		FATAL("out of memory in gsub");
 	mflag = 0;	/* if mflag == 0, can replace empty string */
 	num = 0;
 	x = execute(a[3]);	/* target string */
 	t = getsval(x);
-	if (a[0] == 0)
-		pfa = (fa *) a[1];	/* regular expression */
+	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
+		pfa = (fa *)a[1];	/* regular expression */
 	else {
 		y = execute(a[1]);
 		pfa = makedfa(getsval(y), 1);
-		tempfree(y, "");
+		tempfree(y);
 	}
 	y = execute(a[2]);	/* replacement string */
 	if (pmatch(pfa, t)) {
 		tempstat = pfa->initstat;
 		pfa->initstat = 2;
-		init_buf(&buf, &bsize, LINE_INCR);
+		pb = buf;
 		rptr = getsval(y);
-		cnt = 0;
 		do {
 			if (patlen == 0 && *patbeg != 0) {
 				/* matched empty string */
@@ -1826,79 +2086,112 @@
 					num++;
 					sptr = rptr;
 					while (*sptr != 0) {
-						expand_buf(&buf, &bsize, cnt);
-						if (*sptr == '\\' &&
-						    (*(sptr+1) == '&' ||
-						    *(sptr+1) == '\\')) {
-							sptr++;
-							buf[cnt++] = *sptr++;
-						} else if (*sptr == '&') {
-							expand_buf(&buf,
-							    &bsize,
-							    cnt + patlen);
-							sptr++;
-							(void) memcpy(&buf[cnt],
-							    patbeg, patlen);
-							cnt += patlen;
-						} else {
-							buf[cnt++] = *sptr++;
-						}
+					(void) adjbuf(&buf, &bufsz, 5+pb-buf,
+					    record_size, &pb, "gsub");
+					if (*sptr == '\\') {
+						backsub(&pb, &sptr);
+					} else if (*sptr == '&') {
+						sptr++;
+						(void) adjbuf(&buf, &bufsz, 1 +
+						    patlen+pb-buf, record_size,
+						    &pb, "gsub");
+					for (q = patbeg; q < patbeg+patlen; )
+						*pb++ = *q++;
+					} else {
+						*pb++ = *sptr++;
+					}
 					}
 				}
 				if (*t == 0)	/* at end */
 					goto done;
-				expand_buf(&buf, &bsize, cnt);
-				buf[cnt++] = *t++;
+				(void) adjbuf(&buf, &bufsz, 2 + pb - buf,
+				    record_size, &pb, "gsub");
+				*pb++ = *t++;
+				/* BUG: not sure of this test */
+				if (pb > buf + bufsz)
+					FATAL(
+			"gsub result0 %.30s too big; can't happen", buf);
 				mflag = 0;
 			} else {	/* matched nonempty string */
 				num++;
 				sptr = t;
-				len = patbeg - sptr;
-				if (len > 0) {
-					expand_buf(&buf, &bsize, cnt + len);
-					(void) memcpy(&buf[cnt], sptr, len);
-					cnt += len;
-				}
+				(void) adjbuf(&buf, &bufsz, 1 +
+				    (patbeg - sptr) + pb - buf, record_size,
+				    &pb, "gsub");
+				while (sptr < patbeg)
+					*pb++ = *sptr++;
 				sptr = rptr;
 				while (*sptr != 0) {
-					expand_buf(&buf, &bsize, cnt);
-					if (*sptr == '\\' &&
-					    (*(sptr+1) == '&' ||
-					    *(sptr+1) == '\\')) {
-						sptr++;
-						buf[cnt++] = *sptr++;
+					(void) adjbuf(&buf, &bufsz, 5 + pb -
+					    buf, record_size, &pb, "gsub");
+					if (*sptr == '\\') {
+						backsub(&pb, &sptr);
 					} else if (*sptr == '&') {
-						expand_buf(&buf, &bsize,
-						    cnt + patlen);
 						sptr++;
-						(void) memcpy(&buf[cnt],
-						    patbeg, patlen);
-						cnt += patlen;
+					(void) adjbuf(&buf, &bufsz, 1 +
+					    patlen + pb - buf, record_size,
+					    &pb, "gsub");
+				for (q = patbeg; q < patbeg + patlen; )
+							*pb++ = *q++;
 					} else {
-						buf[cnt++] = *sptr++;
+						*pb++ = *sptr++;
 					}
 				}
 				t = patbeg + patlen;
-				if ((*(t-1) == 0) || (*t == 0))
+				if (patlen == 0 || *t == 0 || *(t - 1) == 0)
 					goto done;
+				if (pb > buf + bufsz)
+					FATAL(
+			"gsub result1 %.30s too big; can't happen", buf);
 				mflag = 1;
 			}
 		} while (pmatch(pfa, t));
 		sptr = t;
-		len = strlen((char *)sptr);
-		expand_buf(&buf, &bsize, len + cnt);
-		(void) memcpy(&buf[cnt], sptr, len);
-		cnt += len;
-	done:
-		buf[cnt] = '\0';
+		(void) adjbuf(&buf, &bufsz, 1 + strlen((char *)sptr) + pb -
+		    buf, 0, &pb, "gsub");
+		while ((*pb++ = *sptr++) != 0)
+			;
+	done:	if (pb < buf + bufsz)
+			*pb = '\0';
+		else if (*(pb-1) != '\0')
+			FATAL("gsub result2 %.30s truncated; can't happen",
+			    buf);
+		/* BUG: should be able to avoid copy + free */
 		(void) setsval(x, buf);
-		free(buf);
 		pfa->initstat = tempstat;
 	}
-	tempfree(x, "");
-	tempfree(y, "");
-	x = gettemp("");
+	tempfree(x);
+	tempfree(y);
+	x = gettemp();
 	x->tval = NUM;
 	x->fval = num;
+	free(buf);
 	return (x);
 }
+
+void
+backsub(uchar **pb_ptr, uchar **sptr_ptr)	/* handle \\& variations */
+{					/* sptr[0] == '\\' */
+	uchar *pb = *pb_ptr, *sptr = *sptr_ptr;
+
+	if (sptr[1] == '\\') {
+		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
+			*pb++ = '\\';
+			*pb++ = '&';
+			sptr += 4;
+		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
+			*pb++ = '\\';
+			sptr += 2;
+		} else {			/* \\x -> \\x */
+			*pb++ = *sptr++;
+			*pb++ = *sptr++;
+		}
+	} else if (sptr[1] == '&') {	/* literal & */
+		sptr++;
+		*pb++ = *sptr++;
+	} else				/* literal \ */
+		*pb++ = *sptr++;
+
+	*pb_ptr = pb;
+	*sptr_ptr = sptr;
+}
--- 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);
 }
