tran.c revision 146299
185587Sobrien/****************************************************************
285587SobrienCopyright (C) Lucent Technologies 1997
385587SobrienAll Rights Reserved
485587Sobrien
585587SobrienPermission to use, copy, modify, and distribute this software and
685587Sobrienits documentation for any purpose and without fee is hereby
785587Sobriengranted, provided that the above copyright notice appear in all
885587Sobriencopies and that both that the copyright notice and this
985587Sobrienpermission notice and warranty disclaimer appear in supporting
1085587Sobriendocumentation, and that the name Lucent Technologies or any of
1185587Sobrienits entities not be used in advertising or publicity pertaining
1285587Sobriento distribution of the software without specific, written prior
1385587Sobrienpermission.
1485587Sobrien
1585587SobrienLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1685587SobrienINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1785587SobrienIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1885587SobrienSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1985587SobrienWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2085587SobrienIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2185587SobrienARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2285587SobrienTHIS SOFTWARE.
2385587Sobrien****************************************************************/
2485587Sobrien
2585587Sobrien#define	DEBUG
2685587Sobrien#include <stdio.h>
2785587Sobrien#include <math.h>
2885587Sobrien#include <ctype.h>
2985587Sobrien#include <string.h>
3085587Sobrien#include <stdlib.h>
3185587Sobrien#include "awk.h"
3285587Sobrien#include "ytab.h"
3385587Sobrien
3485587Sobrien#define	FULLTAB	2	/* rehash when table gets this x full */
3585587Sobrien#define	GROWTAB 4	/* grow table by this factor */
3685587Sobrien
3785587SobrienArray	*symtab;	/* main symbol table */
3885587Sobrien
3985587Sobrienchar	**FS;		/* initial field sep */
4085587Sobrienchar	**RS;		/* initial record sep */
4185587Sobrienchar	**OFS;		/* output field sep */
4285587Sobrienchar	**ORS;		/* output record sep */
4385587Sobrienchar	**OFMT;		/* output format for numbers */
4485587Sobrienchar	**CONVFMT;	/* format for conversions in getsval */
4585587SobrienAwkfloat *NF;		/* number of fields in current record */
4685587SobrienAwkfloat *NR;		/* number of current record */
4785587SobrienAwkfloat *FNR;		/* number of current record in current file */
4885587Sobrienchar	**FILENAME;	/* current filename argument */
4985587SobrienAwkfloat *ARGC;		/* number of arguments from command line */
5085587Sobrienchar	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
5185587SobrienAwkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
5285587SobrienAwkfloat *RLENGTH;	/* length of same */
5385587Sobrien
54146299SruCell	*fsloc;		/* FS */
5585587SobrienCell	*nrloc;		/* NR */
5685587SobrienCell	*nfloc;		/* NF */
5785587SobrienCell	*fnrloc;	/* FNR */
5885587SobrienArray	*ARGVtab;	/* symbol table containing ARGV[...] */
5985587SobrienArray	*ENVtab;	/* symbol table containing ENVIRON[...] */
6085587SobrienCell	*rstartloc;	/* RSTART */
6185587SobrienCell	*rlengthloc;	/* RLENGTH */
6285587SobrienCell	*symtabloc;	/* SYMTAB */
6385587Sobrien
6485587SobrienCell	*nullloc;	/* a guaranteed empty cell */
6585587SobrienNode	*nullnode;	/* zero&null, converted into a node for comparisons */
6685587SobrienCell	*literal0;
6785587Sobrien
6885587Sobrienextern Cell **fldtab;
6985587Sobrien
7085587Sobrienvoid syminit(void)	/* initialize symbol table with builtin vars */
7185587Sobrien{
7285587Sobrien	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
7385587Sobrien	/* this is used for if(x)... tests: */
7485587Sobrien	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
7585587Sobrien	nullnode = celltonode(nullloc, CCON);
7685587Sobrien
77146299Sru	fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
78146299Sru	FS = &fsloc->sval;
7985587Sobrien	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
8085587Sobrien	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
8185587Sobrien	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
8285587Sobrien	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
8385587Sobrien	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
8485587Sobrien	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
8585587Sobrien	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
8685587Sobrien	NF = &nfloc->fval;
8785587Sobrien	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
8885587Sobrien	NR = &nrloc->fval;
8985587Sobrien	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
9085587Sobrien	FNR = &fnrloc->fval;
9185587Sobrien	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
9285587Sobrien	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
9385587Sobrien	RSTART = &rstartloc->fval;
9485587Sobrien	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
9585587Sobrien	RLENGTH = &rlengthloc->fval;
9685587Sobrien	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
9785587Sobrien	symtabloc->sval = (char *) symtab;
9885587Sobrien}
9985587Sobrien
10085587Sobrienvoid arginit(int ac, char **av)	/* set up ARGV and ARGC */
10185587Sobrien{
10285587Sobrien	Cell *cp;
10385587Sobrien	int i;
10485587Sobrien	char temp[50];
10585587Sobrien
10685587Sobrien	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
10785587Sobrien	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
10885587Sobrien	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
10985587Sobrien	cp->sval = (char *) ARGVtab;
11085587Sobrien	for (i = 0; i < ac; i++) {
11185587Sobrien		sprintf(temp, "%d", i);
11285587Sobrien		if (is_number(*av))
11385587Sobrien			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
11485587Sobrien		else
11585587Sobrien			setsymtab(temp, *av, 0.0, STR, ARGVtab);
11685587Sobrien		av++;
11785587Sobrien	}
11885587Sobrien}
11985587Sobrien
12085587Sobrienvoid envinit(char **envp)	/* set up ENVIRON variable */
12185587Sobrien{
12285587Sobrien	Cell *cp;
12385587Sobrien	char *p;
12485587Sobrien
12585587Sobrien	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
12685587Sobrien	ENVtab = makesymtab(NSYMTAB);
12785587Sobrien	cp->sval = (char *) ENVtab;
12885587Sobrien	for ( ; *envp; envp++) {
12985587Sobrien		if ((p = strchr(*envp, '=')) == NULL)
13085587Sobrien			continue;
13185587Sobrien		if( p == *envp ) /* no left hand side name in env string */
13285587Sobrien			continue;
13385587Sobrien		*p++ = 0;	/* split into two strings at = */
13485587Sobrien		if (is_number(p))
13585587Sobrien			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
13685587Sobrien		else
13785587Sobrien			setsymtab(*envp, p, 0.0, STR, ENVtab);
13885587Sobrien		p[-1] = '=';	/* restore in case env is passed down to a shell */
13985587Sobrien	}
14085587Sobrien}
14185587Sobrien
14285587SobrienArray *makesymtab(int n)	/* make a new symbol table */
14385587Sobrien{
14485587Sobrien	Array *ap;
14585587Sobrien	Cell **tp;
14685587Sobrien
14785587Sobrien	ap = (Array *) malloc(sizeof(Array));
14885587Sobrien	tp = (Cell **) calloc(n, sizeof(Cell *));
14985587Sobrien	if (ap == NULL || tp == NULL)
15085587Sobrien		FATAL("out of space in makesymtab");
15185587Sobrien	ap->nelem = 0;
15285587Sobrien	ap->size = n;
15385587Sobrien	ap->tab = tp;
15485587Sobrien	return(ap);
15585587Sobrien}
15685587Sobrien
15785587Sobrienvoid freesymtab(Cell *ap)	/* free a symbol table */
15885587Sobrien{
15985587Sobrien	Cell *cp, *temp;
16085587Sobrien	Array *tp;
16185587Sobrien	int i;
16285587Sobrien
16385587Sobrien	if (!isarr(ap))
16485587Sobrien		return;
16585587Sobrien	tp = (Array *) ap->sval;
16685587Sobrien	if (tp == NULL)
16785587Sobrien		return;
16885587Sobrien	for (i = 0; i < tp->size; i++) {
16985587Sobrien		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
17085587Sobrien			xfree(cp->nval);
17185587Sobrien			if (freeable(cp))
17285587Sobrien				xfree(cp->sval);
17385587Sobrien			temp = cp->cnext;	/* avoids freeing then using */
17485587Sobrien			free(cp);
17590902Sdes			tp->nelem--;
17685587Sobrien		}
17785587Sobrien		tp->tab[i] = 0;
17885587Sobrien	}
17990902Sdes	if (tp->nelem != 0)
18090902Sdes		WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
18185587Sobrien	free(tp->tab);
18285587Sobrien	free(tp);
18385587Sobrien}
18485587Sobrien
185107806Sobrienvoid freeelem(Cell *ap, const char *s)	/* free elem s from ap (i.e., ap["s"] */
18685587Sobrien{
18785587Sobrien	Array *tp;
18885587Sobrien	Cell *p, *prev = NULL;
18985587Sobrien	int h;
19085587Sobrien
19185587Sobrien	tp = (Array *) ap->sval;
19285587Sobrien	h = hash(s, tp->size);
19385587Sobrien	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
19485587Sobrien		if (strcmp(s, p->nval) == 0) {
19585587Sobrien			if (prev == NULL)	/* 1st one */
19685587Sobrien				tp->tab[h] = p->cnext;
19785587Sobrien			else			/* middle somewhere */
19885587Sobrien				prev->cnext = p->cnext;
19985587Sobrien			if (freeable(p))
20085587Sobrien				xfree(p->sval);
20185587Sobrien			free(p->nval);
20285587Sobrien			free(p);
20385587Sobrien			tp->nelem--;
20485587Sobrien			return;
20585587Sobrien		}
20685587Sobrien}
20785587Sobrien
208107806SobrienCell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
20985587Sobrien{
21085587Sobrien	int h;
21185587Sobrien	Cell *p;
21285587Sobrien
21385587Sobrien	if (n != NULL && (p = lookup(n, tp)) != NULL) {
21485587Sobrien		   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
215107806Sobrien			p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
21685587Sobrien		return(p);
21785587Sobrien	}
21885587Sobrien	p = (Cell *) malloc(sizeof(Cell));
21985587Sobrien	if (p == NULL)
22085587Sobrien		FATAL("out of space for symbol table at %s", n);
22185587Sobrien	p->nval = tostring(n);
22285587Sobrien	p->sval = s ? tostring(s) : tostring("");
22385587Sobrien	p->fval = f;
22485587Sobrien	p->tval = t;
22585587Sobrien	p->csub = CUNK;
22685587Sobrien	p->ctype = OCELL;
22785587Sobrien	tp->nelem++;
22885587Sobrien	if (tp->nelem > FULLTAB * tp->size)
22985587Sobrien		rehash(tp);
23085587Sobrien	h = hash(n, tp->size);
23185587Sobrien	p->cnext = tp->tab[h];
23285587Sobrien	tp->tab[h] = p;
23385587Sobrien	   dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
23485587Sobrien		p, p->nval, p->sval, p->fval, p->tval) );
23585587Sobrien	return(p);
23685587Sobrien}
23785587Sobrien
238107806Sobrienint hash(const char *s, int n)	/* form hash value for string s */
23985587Sobrien{
24085587Sobrien	unsigned hashval;
24185587Sobrien
24285587Sobrien	for (hashval = 0; *s != '\0'; s++)
24385587Sobrien		hashval = (*s + 31 * hashval);
24485587Sobrien	return hashval % n;
24585587Sobrien}
24685587Sobrien
24785587Sobrienvoid rehash(Array *tp)	/* rehash items in small table into big one */
24885587Sobrien{
24985587Sobrien	int i, nh, nsz;
25085587Sobrien	Cell *cp, *op, **np;
25185587Sobrien
25285587Sobrien	nsz = GROWTAB * tp->size;
25385587Sobrien	np = (Cell **) calloc(nsz, sizeof(Cell *));
25485587Sobrien	if (np == NULL)		/* can't do it, but can keep running. */
25585587Sobrien		return;		/* someone else will run out later. */
25685587Sobrien	for (i = 0; i < tp->size; i++) {
25785587Sobrien		for (cp = tp->tab[i]; cp; cp = op) {
25885587Sobrien			op = cp->cnext;
25985587Sobrien			nh = hash(cp->nval, nsz);
26085587Sobrien			cp->cnext = np[nh];
26185587Sobrien			np[nh] = cp;
26285587Sobrien		}
26385587Sobrien	}
26485587Sobrien	free(tp->tab);
26585587Sobrien	tp->tab = np;
26685587Sobrien	tp->size = nsz;
26785587Sobrien}
26885587Sobrien
269107806SobrienCell *lookup(const char *s, Array *tp)	/* look for s in tp */
27085587Sobrien{
27185587Sobrien	Cell *p;
27285587Sobrien	int h;
27385587Sobrien
27485587Sobrien	h = hash(s, tp->size);
27585587Sobrien	for (p = tp->tab[h]; p != NULL; p = p->cnext)
27685587Sobrien		if (strcmp(s, p->nval) == 0)
27785587Sobrien			return(p);	/* found it */
27885587Sobrien	return(NULL);			/* not found */
27985587Sobrien}
28085587Sobrien
28185587SobrienAwkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
28285587Sobrien{
28385587Sobrien	int fldno;
28485587Sobrien
28585587Sobrien	if ((vp->tval & (NUM | STR)) == 0)
28685587Sobrien		funnyvar(vp, "assign to");
28785587Sobrien	if (isfld(vp)) {
28885587Sobrien		donerec = 0;	/* mark $0 invalid */
28985587Sobrien		fldno = atoi(vp->nval);
29085587Sobrien		if (fldno > *NF)
29185587Sobrien			newfld(fldno);
29285587Sobrien		   dprintf( ("setting field %d to %g\n", fldno, f) );
29385587Sobrien	} else if (isrec(vp)) {
29485587Sobrien		donefld = 0;	/* mark $1... invalid */
29585587Sobrien		donerec = 1;
29685587Sobrien	}
29785587Sobrien	if (freeable(vp))
29885587Sobrien		xfree(vp->sval); /* free any previous string */
29985587Sobrien	vp->tval &= ~STR;	/* mark string invalid */
30085587Sobrien	vp->tval |= NUM;	/* mark number ok */
301107806Sobrien	   dprintf( ("setfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), f, vp->tval) );
30285587Sobrien	return vp->fval = f;
30385587Sobrien}
30485587Sobrien
305107806Sobrienvoid funnyvar(Cell *vp, const char *rw)
30685587Sobrien{
30785587Sobrien	if (isarr(vp))
30885587Sobrien		FATAL("can't %s %s; it's an array name.", rw, vp->nval);
30985587Sobrien	if (vp->tval & FCN)
31085587Sobrien		FATAL("can't %s %s; it's a function.", rw, vp->nval);
31185587Sobrien	WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
31285587Sobrien		vp, vp->nval, vp->sval, vp->fval, vp->tval);
31385587Sobrien}
31485587Sobrien
315107806Sobrienchar *setsval(Cell *vp, const char *s)	/* set string val of a Cell */
31685587Sobrien{
31785587Sobrien	char *t;
31885587Sobrien	int fldno;
31985587Sobrien
320146299Sru	   dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
321146299Sru		vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
32285587Sobrien	if ((vp->tval & (NUM | STR)) == 0)
32385587Sobrien		funnyvar(vp, "assign to");
32485587Sobrien	if (isfld(vp)) {
32585587Sobrien		donerec = 0;	/* mark $0 invalid */
32685587Sobrien		fldno = atoi(vp->nval);
32785587Sobrien		if (fldno > *NF)
32885587Sobrien			newfld(fldno);
32985587Sobrien		   dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
33085587Sobrien	} else if (isrec(vp)) {
33185587Sobrien		donefld = 0;	/* mark $1... invalid */
33285587Sobrien		donerec = 1;
33385587Sobrien	}
33485587Sobrien	t = tostring(s);	/* in case it's self-assign */
33585587Sobrien	vp->tval &= ~NUM;
33685587Sobrien	vp->tval |= STR;
33785587Sobrien	if (freeable(vp))
33885587Sobrien		xfree(vp->sval);
33985587Sobrien	vp->tval &= ~DONTFREE;
340146299Sru	   dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
341146299Sru		vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) );
34285587Sobrien	return(vp->sval = t);
34385587Sobrien}
34485587Sobrien
34585587SobrienAwkfloat getfval(Cell *vp)	/* get float val of a Cell */
34685587Sobrien{
34785587Sobrien	if ((vp->tval & (NUM | STR)) == 0)
34885587Sobrien		funnyvar(vp, "read value of");
34985587Sobrien	if (isfld(vp) && donefld == 0)
35085587Sobrien		fldbld();
35185587Sobrien	else if (isrec(vp) && donerec == 0)
35285587Sobrien		recbld();
35385587Sobrien	if (!isnum(vp)) {	/* not a number */
35485587Sobrien		vp->fval = atof(vp->sval);	/* best guess */
35585587Sobrien		if (is_number(vp->sval) && !(vp->tval&CON))
35685587Sobrien			vp->tval |= NUM;	/* make NUM only sparingly */
35785587Sobrien	}
358107806Sobrien	   dprintf( ("getfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), vp->fval, vp->tval) );
35985587Sobrien	return(vp->fval);
36085587Sobrien}
36185587Sobrien
362146299Srustatic char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
36385587Sobrien{
36485587Sobrien	char s[100];	/* BUG: unchecked */
36585587Sobrien	double dtemp;
36685587Sobrien
36785587Sobrien	if ((vp->tval & (NUM | STR)) == 0)
36885587Sobrien		funnyvar(vp, "read value of");
36985587Sobrien	if (isfld(vp) && donefld == 0)
37085587Sobrien		fldbld();
37185587Sobrien	else if (isrec(vp) && donerec == 0)
37285587Sobrien		recbld();
37385587Sobrien	if (isstr(vp) == 0) {
37485587Sobrien		if (freeable(vp))
37585587Sobrien			xfree(vp->sval);
37685587Sobrien		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
37785587Sobrien			sprintf(s, "%.30g", vp->fval);
37885587Sobrien		else
379107806Sobrien			sprintf(s, *fmt, vp->fval);
38085587Sobrien		vp->sval = tostring(s);
38185587Sobrien		vp->tval &= ~DONTFREE;
38285587Sobrien		vp->tval |= STR;
38385587Sobrien	}
384107806Sobrien	   dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
38585587Sobrien	return(vp->sval);
38685587Sobrien}
38785587Sobrien
388107806Sobrienchar *getsval(Cell *vp)       /* get string val of a Cell */
38985587Sobrien{
390107806Sobrien      return get_str_val(vp, CONVFMT);
391107806Sobrien}
392107806Sobrien
393107806Sobrienchar *getpssval(Cell *vp)     /* get string val of a Cell for print */
394107806Sobrien{
395107806Sobrien      return get_str_val(vp, OFMT);
396107806Sobrien}
397107806Sobrien
398107806Sobrien
399107806Sobrienchar *tostring(const char *s)	/* make a copy of string s */
400107806Sobrien{
40185587Sobrien	char *p;
40285587Sobrien
40385587Sobrien	p = (char *) malloc(strlen(s)+1);
40485587Sobrien	if (p == NULL)
40585587Sobrien		FATAL("out of space in tostring on %s", s);
40685587Sobrien	strcpy(p, s);
40785587Sobrien	return(p);
40885587Sobrien}
40985587Sobrien
410107806Sobrienchar *qstring(const char *is, int delim)	/* collect string up to next delim */
41185587Sobrien{
412107806Sobrien	const char *os = is;
41385587Sobrien	int c, n;
41485587Sobrien	uschar *s = (uschar *) is;
41585587Sobrien	uschar *buf, *bp;
41685587Sobrien
41790902Sdes	if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
41885587Sobrien		FATAL( "out of space in qstring(%s)", s);
41985587Sobrien	for (bp = buf; (c = *s) != delim; s++) {
42085587Sobrien		if (c == '\n')
42185587Sobrien			SYNTAX( "newline in string %.20s...", os );
42285587Sobrien		else if (c != '\\')
42385587Sobrien			*bp++ = c;
42485587Sobrien		else {	/* \something */
42585587Sobrien			c = *++s;
42685587Sobrien			if (c == 0) {	/* \ at end */
42785587Sobrien				*bp++ = '\\';
42885587Sobrien				break;	/* for loop */
42985587Sobrien			}
43085587Sobrien			switch (c) {
43185587Sobrien			case '\\':	*bp++ = '\\'; break;
43285587Sobrien			case 'n':	*bp++ = '\n'; break;
43385587Sobrien			case 't':	*bp++ = '\t'; break;
43485587Sobrien			case 'b':	*bp++ = '\b'; break;
43585587Sobrien			case 'f':	*bp++ = '\f'; break;
43685587Sobrien			case 'r':	*bp++ = '\r'; break;
43785587Sobrien			default:
43885587Sobrien				if (!isdigit(c)) {
43985587Sobrien					*bp++ = c;
44085587Sobrien					break;
44185587Sobrien				}
44285587Sobrien				n = c - '0';
44385587Sobrien				if (isdigit(s[1])) {
44485587Sobrien					n = 8 * n + *++s - '0';
44585587Sobrien					if (isdigit(s[1]))
44685587Sobrien						n = 8 * n + *++s - '0';
44785587Sobrien				}
44885587Sobrien				*bp++ = n;
44985587Sobrien				break;
45085587Sobrien			}
45185587Sobrien		}
45285587Sobrien	}
45385587Sobrien	*bp++ = 0;
45485587Sobrien	return (char *) buf;
45585587Sobrien}
456