xref: /csrg-svn/contrib/awk.research/tran.c (revision 65396)
165394Sbostic /****************************************************************
265394Sbostic Copyright (C) AT&T 1993
365394Sbostic All Rights Reserved
465394Sbostic 
565394Sbostic Permission to use, copy, modify, and distribute this software and
665394Sbostic its documentation for any purpose and without fee is hereby
765394Sbostic granted, provided that the above copyright notice appear in all
865394Sbostic copies and that both that the copyright notice and this
965394Sbostic permission notice and warranty disclaimer appear in supporting
1065394Sbostic documentation, and that the name of AT&T or any of its entities
1165394Sbostic not be used in advertising or publicity pertaining to
1265394Sbostic distribution of the software without specific, written prior
1365394Sbostic permission.
1465394Sbostic 
1565394Sbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1665394Sbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1765394Sbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1865394Sbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1965394Sbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2065394Sbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2165394Sbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2265394Sbostic THIS SOFTWARE.
2365394Sbostic ****************************************************************/
2465394Sbostic 
2565394Sbostic #define	DEBUG
2665394Sbostic #include <stdio.h>
2765394Sbostic #include <math.h>
2865394Sbostic #include <ctype.h>
2965394Sbostic #include <string.h>
3065394Sbostic #include <stdlib.h>
3165394Sbostic #include "awk.h"
3265394Sbostic #include "y.tab.h"
3365394Sbostic 
3465394Sbostic #define	FULLTAB	2	/* rehash when table gets this x full */
3565394Sbostic #define	GROWTAB 4	/* grow table by this factor */
3665394Sbostic 
3765394Sbostic Array	*symtab;	/* main symbol table */
3865394Sbostic 
3965394Sbostic uchar	**FS;		/* initial field sep */
4065394Sbostic uchar	**RS;		/* initial record sep */
4165394Sbostic uchar	**OFS;		/* output field sep */
4265394Sbostic uchar	**ORS;		/* output record sep */
4365394Sbostic uchar	**OFMT;		/* output format for numbers */
4465394Sbostic uchar	**CONVFMT;	/* format for conversions in getsval */
4565394Sbostic Awkfloat *NF;		/* number of fields in current record */
4665394Sbostic Awkfloat *NR;		/* number of current record */
4765394Sbostic Awkfloat *FNR;		/* number of current record in current file */
4865394Sbostic uchar	**FILENAME;	/* current filename argument */
4965394Sbostic Awkfloat *ARGC;		/* number of arguments from command line */
5065394Sbostic uchar	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
5165394Sbostic Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
5265394Sbostic Awkfloat *RLENGTH;	/* length of same */
5365394Sbostic 
5465394Sbostic Cell	*recloc;	/* location of record */
5565394Sbostic Cell	*nrloc;		/* NR */
5665394Sbostic Cell	*nfloc;		/* NF */
5765394Sbostic Cell	*fnrloc;	/* FNR */
5865394Sbostic Array	*ARGVtab;	/* symbol table containing ARGV[...] */
5965394Sbostic Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
6065394Sbostic Cell	*rstartloc;	/* RSTART */
6165394Sbostic Cell	*rlengthloc;	/* RLENGTH */
6265394Sbostic Cell	*symtabloc;	/* SYMTAB */
6365394Sbostic 
6465394Sbostic Cell	*nullloc;	/* a guaranteed empty cell */
6565394Sbostic Node	*nullnode;	/* zero&null, converted into a node for comparisons */
6665394Sbostic 
6765394Sbostic extern Cell *fldtab;
6865394Sbostic 
syminit(void)6965394Sbostic void syminit(void)	/* initialize symbol table with builtin vars */
7065394Sbostic {
7165394Sbostic 	setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
7265394Sbostic 	/* this is used for if(x)... tests: */
7365394Sbostic 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
7465394Sbostic 	nullnode = valtonode(nullloc, CCON);
7565394Sbostic 
7665394Sbostic 	/* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */
7765394Sbostic 	/* has been done elsewhere */
7865394Sbostic 	recloc = &fldtab[0];
7965394Sbostic 	FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
8065394Sbostic 	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
8165394Sbostic 	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
8265394Sbostic 	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
8365394Sbostic 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
8465394Sbostic 	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
8565394Sbostic 	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
8665394Sbostic 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
8765394Sbostic 	NF = &nfloc->fval;
8865394Sbostic 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
8965394Sbostic 	NR = &nrloc->fval;
9065394Sbostic 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
9165394Sbostic 	FNR = &fnrloc->fval;
9265394Sbostic 	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
9365394Sbostic 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
9465394Sbostic 	RSTART = &rstartloc->fval;
9565394Sbostic 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
9665394Sbostic 	RLENGTH = &rlengthloc->fval;
9765394Sbostic 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
9865394Sbostic 	symtabloc->sval = (uchar *) symtab;
9965394Sbostic }
10065394Sbostic 
arginit(int ac,uchar * av[])10165394Sbostic void arginit(int ac, uchar *av[])	/* set up ARGV and ARGC */
10265394Sbostic {
10365394Sbostic 	Cell *cp;
10465394Sbostic 	int i;
10565394Sbostic 	uchar temp[5];
10665394Sbostic 
10765394Sbostic 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
10865394Sbostic 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
10965394Sbostic 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
11065394Sbostic 	cp->sval = (uchar *) ARGVtab;
11165394Sbostic 	for (i = 0; i < ac; i++) {
11265394Sbostic 		sprintf((char *)temp, "%d", i);
113*65396Sbostic 		if (is_a_number(*av))
11465394Sbostic 			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
11565394Sbostic 		else
11665394Sbostic 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
11765394Sbostic 		av++;
11865394Sbostic 	}
11965394Sbostic }
12065394Sbostic 
envinit(uchar ** envp)12165394Sbostic void envinit(uchar **envp)	/* set up ENVIRON variable */
12265394Sbostic {
12365394Sbostic 	Cell *cp;
12465394Sbostic 	uchar *p;
12565394Sbostic 
12665394Sbostic 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
12765394Sbostic 	ENVtab = makesymtab(NSYMTAB);
12865394Sbostic 	cp->sval = (uchar *) ENVtab;
12965394Sbostic 	for ( ; *envp; envp++) {
13065394Sbostic 		if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL)
13165394Sbostic 			continue;
13265394Sbostic 		*p++ = 0;	/* split into two strings at = */
133*65396Sbostic 		if (is_a_number(p))
13465394Sbostic 			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
13565394Sbostic 		else
13665394Sbostic 			setsymtab(*envp, p, 0.0, STR, ENVtab);
13765394Sbostic 		p[-1] = '=';	/* restore in case env is passed down to a shell */
13865394Sbostic 	}
13965394Sbostic }
14065394Sbostic 
makesymtab(int n)14165394Sbostic Array *makesymtab(int n)	/* make a new symbol table */
14265394Sbostic {
14365394Sbostic 	Array *ap;
14465394Sbostic 	Cell **tp;
14565394Sbostic 
14665394Sbostic 	ap = (Array *) malloc(sizeof(Array));
14765394Sbostic 	tp = (Cell **) calloc(n, sizeof(Cell *));
14865394Sbostic 	if (ap == NULL || tp == NULL)
14965394Sbostic 		ERROR "out of space in makesymtab" FATAL;
15065394Sbostic 	ap->nelem = 0;
15165394Sbostic 	ap->size = n;
15265394Sbostic 	ap->tab = tp;
15365394Sbostic 	return(ap);
15465394Sbostic }
15565394Sbostic 
freesymtab(Cell * ap)15665394Sbostic void freesymtab(Cell *ap)	/* free a symbol table */
15765394Sbostic {
15865394Sbostic 	Cell *cp, *temp;
15965394Sbostic 	Array *tp;
16065394Sbostic 	int i;
16165394Sbostic 
16265394Sbostic 	if (!isarr(ap))
16365394Sbostic 		return;
16465394Sbostic 	tp = (Array *) ap->sval;
16565394Sbostic 	if (tp == NULL)
16665394Sbostic 		return;
16765394Sbostic 	for (i = 0; i < tp->size; i++) {
16865394Sbostic 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
16965394Sbostic 			xfree(cp->nval);
17065394Sbostic 			if (freeable(cp))
17165394Sbostic 				xfree(cp->sval);
17265394Sbostic 			temp = cp->cnext;	/* avoids freeing then using */
17365394Sbostic 			free((char *) cp);
17465394Sbostic 		}
17565394Sbostic 	}
17665394Sbostic 	free((char *) (tp->tab));
17765394Sbostic 	free((char *) tp);
17865394Sbostic }
17965394Sbostic 
freeelem(Cell * ap,uchar * s)18065394Sbostic void freeelem(Cell *ap, uchar *s)	/* free elem s from ap (i.e., ap["s"] */
18165394Sbostic {
18265394Sbostic 	Array *tp;
18365394Sbostic 	Cell *p, *prev = NULL;
18465394Sbostic 	int h;
18565394Sbostic 
18665394Sbostic 	tp = (Array *) ap->sval;
18765394Sbostic 	h = hash(s, tp->size);
18865394Sbostic 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
18965394Sbostic 		if (strcmp((char *) s, (char *) p->nval) == 0) {
19065394Sbostic 			if (prev == NULL)	/* 1st one */
19165394Sbostic 				tp->tab[h] = p->cnext;
19265394Sbostic 			else			/* middle somewhere */
19365394Sbostic 				prev->cnext = p->cnext;
19465394Sbostic 			if (freeable(p))
19565394Sbostic 				xfree(p->sval);
19665394Sbostic 			free(p->nval);
19765394Sbostic 			free((char *) p);
19865394Sbostic 			tp->nelem--;
19965394Sbostic 			return;
20065394Sbostic 		}
20165394Sbostic }
20265394Sbostic 
setsymtab(uchar * n,uchar * s,Awkfloat f,unsigned t,Array * tp)20365394Sbostic Cell *setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned t, Array *tp)
20465394Sbostic {
20565394Sbostic 	register int h;
20665394Sbostic 	register Cell *p;
20765394Sbostic 
20865394Sbostic 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
20965394Sbostic 		dprintf( ("setsymtab found %o: n=%s s=\"%s\" f=%g t=%o\n",
21065394Sbostic 			p, p->nval, p->sval, p->fval, p->tval) );
21165394Sbostic 		return(p);
21265394Sbostic 	}
21365394Sbostic 	p = (Cell *) malloc(sizeof(Cell));
21465394Sbostic 	if (p == NULL)
21565394Sbostic 		ERROR "out of space for symbol table at %s", n FATAL;
21665394Sbostic 	p->nval = tostring(n);
21765394Sbostic 	p->sval = s ? tostring(s) : tostring("");
21865394Sbostic 	p->fval = f;
21965394Sbostic 	p->tval = t;
22065394Sbostic 	tp->nelem++;
22165394Sbostic 	if (tp->nelem > FULLTAB * tp->size)
22265394Sbostic 		rehash(tp);
22365394Sbostic 	h = hash(n, tp->size);
22465394Sbostic 	p->cnext = tp->tab[h];
22565394Sbostic 	tp->tab[h] = p;
22665394Sbostic 	dprintf( ("setsymtab set %o: n=%s s=\"%s\" f=%g t=%o\n",
22765394Sbostic 		p, p->nval, p->sval, p->fval, p->tval) );
22865394Sbostic 	return(p);
22965394Sbostic }
23065394Sbostic 
hash(uchar * s,int n)23165394Sbostic hash(uchar *s, int n)	/* form hash value for string s */
23265394Sbostic {
23365394Sbostic 	register unsigned hashval;
23465394Sbostic 
23565394Sbostic 	for (hashval = 0; *s != '\0'; s++)
23665394Sbostic 		hashval = (*s + 31 * hashval);
23765394Sbostic 	return hashval % n;
23865394Sbostic }
23965394Sbostic 
rehash(Array * tp)24065394Sbostic void rehash(Array *tp)	/* rehash items in small table into big one */
24165394Sbostic {
24265394Sbostic 	int i, nh, nsz;
24365394Sbostic 	Cell *cp, *op, **np;
24465394Sbostic 
24565394Sbostic 	nsz = GROWTAB * tp->size;
24665394Sbostic 	np = (Cell **) calloc(nsz, sizeof(Cell *));
24765394Sbostic 	if (np == NULL)		/* can't do it, but can keep running. */
24865394Sbostic 		return;		/* someone else will run out later. */
24965394Sbostic 	for (i = 0; i < tp->size; i++) {
25065394Sbostic 		for (cp = tp->tab[i]; cp; cp = op) {
25165394Sbostic 			op = cp->cnext;
25265394Sbostic 			nh = hash(cp->nval, nsz);
25365394Sbostic 			cp->cnext = np[nh];
25465394Sbostic 			np[nh] = cp;
25565394Sbostic 		}
25665394Sbostic 	}
25765394Sbostic 	free((char *) (tp->tab));
25865394Sbostic 	tp->tab = np;
25965394Sbostic 	tp->size = nsz;
26065394Sbostic }
26165394Sbostic 
lookup(uchar * s,Array * tp)26265394Sbostic Cell *lookup(uchar *s, Array *tp)	/* look for s in tp */
26365394Sbostic {
26465394Sbostic 	register Cell *p, *prev = NULL;
26565394Sbostic 	int h;
26665394Sbostic 
26765394Sbostic 	h = hash(s, tp->size);
26865394Sbostic 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
26965394Sbostic 		if (strcmp((char *) s, (char *) p->nval) == 0)
27065394Sbostic 			return(p);	/* found it */
27165394Sbostic 	return(NULL);			/* not found */
27265394Sbostic }
27365394Sbostic 
setfval(Cell * vp,Awkfloat f)27465394Sbostic Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
27565394Sbostic {
27665394Sbostic 	if ((vp->tval & (NUM | STR)) == 0)
27765394Sbostic 		funnyvar(vp, "assign to");
27865394Sbostic 	if (vp->tval & FLD) {
27965394Sbostic 		donerec = 0;	/* mark $0 invalid */
28065394Sbostic 		if (vp-fldtab > *NF)
28165394Sbostic 			newfld(vp-fldtab);
28265394Sbostic 		dprintf( ("setting field %d to %g\n", vp-fldtab, f) );
28365394Sbostic 	} else if (vp->tval & REC) {
28465394Sbostic 		donefld = 0;	/* mark $1... invalid */
28565394Sbostic 		donerec = 1;
28665394Sbostic 	}
28765394Sbostic 	vp->tval &= ~STR;	/* mark string invalid */
28865394Sbostic 	vp->tval |= NUM;	/* mark number ok */
28965394Sbostic 	dprintf( ("setfval %o: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
29065394Sbostic 	return vp->fval = f;
29165394Sbostic }
29265394Sbostic 
funnyvar(Cell * vp,char * rw)29365394Sbostic void funnyvar(Cell *vp, char *rw)
29465394Sbostic {
29565394Sbostic 	if (vp->tval & ARR)
29665394Sbostic 		ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
29765394Sbostic 	if (vp->tval & FCN)
29865394Sbostic 		ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
29965394Sbostic 	ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
30065394Sbostic 		vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING;
30165394Sbostic }
30265394Sbostic 
setsval(Cell * vp,uchar * s)30365394Sbostic uchar *setsval(Cell *vp, uchar *s)	/* set string val of a Cell */
30465394Sbostic {
30565394Sbostic 	if ((vp->tval & (NUM | STR)) == 0)
30665394Sbostic 		funnyvar(vp, "assign to");
30765394Sbostic 	if (vp->tval & FLD) {
30865394Sbostic 		donerec = 0;	/* mark $0 invalid */
30965394Sbostic 		if (vp-fldtab > *NF)
31065394Sbostic 			newfld(vp-fldtab);
31165394Sbostic 		dprintf( ("setting field %d to %s\n", vp-fldtab, s) );
31265394Sbostic 	} else if (vp->tval & REC) {
31365394Sbostic 		donefld = 0;	/* mark $1... invalid */
31465394Sbostic 		donerec = 1;
31565394Sbostic 	}
31665394Sbostic 	vp->tval &= ~NUM;
31765394Sbostic 	vp->tval |= STR;
31865394Sbostic 	if (freeable(vp))
31965394Sbostic 		xfree(vp->sval);
32065394Sbostic 	vp->tval &= ~DONTFREE;
32165394Sbostic 	dprintf( ("setsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
32265394Sbostic 	return(vp->sval = tostring(s));
32365394Sbostic }
32465394Sbostic 
r_getfval(Cell * vp)32565394Sbostic Awkfloat r_getfval(Cell *vp)	/* get float val of a Cell */
32665394Sbostic {
32765394Sbostic 	if ((vp->tval & (NUM | STR)) == 0)
32865394Sbostic 		funnyvar(vp, "read value of");
32965394Sbostic 	if ((vp->tval & FLD) && donefld == 0)
33065394Sbostic 		fldbld();
33165394Sbostic 	else if ((vp->tval & REC) && donerec == 0)
33265394Sbostic 		recbld();
33365394Sbostic 	if (!isnum(vp)) {	/* not a number */
33465394Sbostic 		vp->fval = atof(vp->sval);	/* best guess */
335*65396Sbostic 		if (is_a_number(vp->sval) && !(vp->tval&CON))
33665394Sbostic 			vp->tval |= NUM;	/* make NUM only sparingly */
33765394Sbostic 	}
33865394Sbostic 	dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
33965394Sbostic 	return(vp->fval);
34065394Sbostic }
34165394Sbostic 
r_getsval(Cell * vp)34265394Sbostic uchar *r_getsval(Cell *vp)	/* get string val of a Cell */
34365394Sbostic {
34465394Sbostic 	uchar s[100];
34565394Sbostic 	double dtemp;
34665394Sbostic 
34765394Sbostic 	if ((vp->tval & (NUM | STR)) == 0)
34865394Sbostic 		funnyvar(vp, "read value of");
34965394Sbostic 	if ((vp->tval & FLD) && donefld == 0)
35065394Sbostic 		fldbld();
35165394Sbostic 	else if ((vp->tval & REC) && donerec == 0)
35265394Sbostic 		recbld();
35365394Sbostic 	if ((vp->tval & STR) == 0) {
35465394Sbostic 		if (!(vp->tval&DONTFREE))
35565394Sbostic 			xfree(vp->sval);
35665394Sbostic 		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
35765394Sbostic 			sprintf((char *)s, "%.20g", vp->fval);
35865394Sbostic 		else
35965394Sbostic 			sprintf((char *)s, (char *)*CONVFMT, vp->fval);
36065394Sbostic 		vp->sval = tostring(s);
36165394Sbostic 		vp->tval &= ~DONTFREE;
36265394Sbostic 		vp->tval |= STR;
36365394Sbostic 	}
36465394Sbostic 	dprintf( ("getsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, vp->sval, vp->tval) );
36565394Sbostic 	return(vp->sval);
36665394Sbostic }
36765394Sbostic 
tostring(uchar * s)36865394Sbostic uchar *tostring(uchar *s)	/* make a copy of string s */
36965394Sbostic {
37065394Sbostic 	register uchar *p;
37165394Sbostic 
37265394Sbostic 	p = (uchar *) malloc(strlen((char *) s)+1);
37365394Sbostic 	if (p == NULL)
37465394Sbostic 		ERROR "out of space in tostring on %s", s FATAL;
37565394Sbostic 	strcpy((char *) p, (char *) s);
37665394Sbostic 	return(p);
37765394Sbostic }
37865394Sbostic 
qstring(uchar * s,int delim)37965394Sbostic uchar *qstring(uchar *s, int delim)	/* collect string up to next delim */
38065394Sbostic {
38165394Sbostic 	uchar *q;
38265394Sbostic 	int c, n;
38365394Sbostic 
38465394Sbostic 	for (q = cbuf; (c = *s) != delim; s++) {
38565394Sbostic 		if (q >= cbuf + CBUFLEN - 1)
38665394Sbostic 			ERROR "string %.10s... too long", cbuf SYNTAX;
38765394Sbostic 		else if (c == '\n')
38865394Sbostic 			ERROR "newline in string %.10s...", cbuf SYNTAX;
38965394Sbostic 		else if (c != '\\')
39065394Sbostic 			*q++ = c;
39165394Sbostic 		else	/* \something */
39265394Sbostic 			switch (c = *++s) {
39365394Sbostic 			case '\\':	*q++ = '\\'; break;
39465394Sbostic 			case 'n':	*q++ = '\n'; break;
39565394Sbostic 			case 't':	*q++ = '\t'; break;
39665394Sbostic 			case 'b':	*q++ = '\b'; break;
39765394Sbostic 			case 'f':	*q++ = '\f'; break;
39865394Sbostic 			case 'r':	*q++ = '\r'; break;
39965394Sbostic 			default:
40065394Sbostic 				if (!isdigit(c)) {
40165394Sbostic 					*q++ = c;
40265394Sbostic 					break;
40365394Sbostic 				}
40465394Sbostic 				n = c - '0';
40565394Sbostic 				if (isdigit(s[1])) {
40665394Sbostic 					n = 8 * n + *++s - '0';
40765394Sbostic 					if (isdigit(s[1]))
40865394Sbostic 						n = 8 * n + *++s - '0';
40965394Sbostic 				}
41065394Sbostic 				*q++ = n;
41165394Sbostic 				break;
41265394Sbostic 			}
41365394Sbostic 	}
41465394Sbostic 	*q = '\0';
41565394Sbostic 	return cbuf;
41665394Sbostic }
417