xref: /csrg-svn/contrib/awk.research/tran.c (revision 65394)
1*65394Sbostic /****************************************************************
2*65394Sbostic Copyright (C) AT&T 1993
3*65394Sbostic All Rights Reserved
4*65394Sbostic 
5*65394Sbostic Permission to use, copy, modify, and distribute this software and
6*65394Sbostic its documentation for any purpose and without fee is hereby
7*65394Sbostic granted, provided that the above copyright notice appear in all
8*65394Sbostic copies and that both that the copyright notice and this
9*65394Sbostic permission notice and warranty disclaimer appear in supporting
10*65394Sbostic documentation, and that the name of AT&T or any of its entities
11*65394Sbostic not be used in advertising or publicity pertaining to
12*65394Sbostic distribution of the software without specific, written prior
13*65394Sbostic permission.
14*65394Sbostic 
15*65394Sbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16*65394Sbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17*65394Sbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18*65394Sbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*65394Sbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20*65394Sbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21*65394Sbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22*65394Sbostic THIS SOFTWARE.
23*65394Sbostic ****************************************************************/
24*65394Sbostic 
25*65394Sbostic #define	DEBUG
26*65394Sbostic #include <stdio.h>
27*65394Sbostic #include <math.h>
28*65394Sbostic #include <ctype.h>
29*65394Sbostic #include <string.h>
30*65394Sbostic #include <stdlib.h>
31*65394Sbostic #include "awk.h"
32*65394Sbostic #include "y.tab.h"
33*65394Sbostic 
34*65394Sbostic #define	FULLTAB	2	/* rehash when table gets this x full */
35*65394Sbostic #define	GROWTAB 4	/* grow table by this factor */
36*65394Sbostic 
37*65394Sbostic Array	*symtab;	/* main symbol table */
38*65394Sbostic 
39*65394Sbostic uchar	**FS;		/* initial field sep */
40*65394Sbostic uchar	**RS;		/* initial record sep */
41*65394Sbostic uchar	**OFS;		/* output field sep */
42*65394Sbostic uchar	**ORS;		/* output record sep */
43*65394Sbostic uchar	**OFMT;		/* output format for numbers */
44*65394Sbostic uchar	**CONVFMT;	/* format for conversions in getsval */
45*65394Sbostic Awkfloat *NF;		/* number of fields in current record */
46*65394Sbostic Awkfloat *NR;		/* number of current record */
47*65394Sbostic Awkfloat *FNR;		/* number of current record in current file */
48*65394Sbostic uchar	**FILENAME;	/* current filename argument */
49*65394Sbostic Awkfloat *ARGC;		/* number of arguments from command line */
50*65394Sbostic uchar	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
51*65394Sbostic Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
52*65394Sbostic Awkfloat *RLENGTH;	/* length of same */
53*65394Sbostic 
54*65394Sbostic Cell	*recloc;	/* location of record */
55*65394Sbostic Cell	*nrloc;		/* NR */
56*65394Sbostic Cell	*nfloc;		/* NF */
57*65394Sbostic Cell	*fnrloc;	/* FNR */
58*65394Sbostic Array	*ARGVtab;	/* symbol table containing ARGV[...] */
59*65394Sbostic Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
60*65394Sbostic Cell	*rstartloc;	/* RSTART */
61*65394Sbostic Cell	*rlengthloc;	/* RLENGTH */
62*65394Sbostic Cell	*symtabloc;	/* SYMTAB */
63*65394Sbostic 
64*65394Sbostic Cell	*nullloc;	/* a guaranteed empty cell */
65*65394Sbostic Node	*nullnode;	/* zero&null, converted into a node for comparisons */
66*65394Sbostic 
67*65394Sbostic extern Cell *fldtab;
68*65394Sbostic 
69*65394Sbostic void syminit(void)	/* initialize symbol table with builtin vars */
70*65394Sbostic {
71*65394Sbostic 	setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
72*65394Sbostic 	/* this is used for if(x)... tests: */
73*65394Sbostic 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
74*65394Sbostic 	nullnode = valtonode(nullloc, CCON);
75*65394Sbostic 
76*65394Sbostic 	/* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */
77*65394Sbostic 	/* has been done elsewhere */
78*65394Sbostic 	recloc = &fldtab[0];
79*65394Sbostic 	FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
80*65394Sbostic 	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
81*65394Sbostic 	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
82*65394Sbostic 	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
83*65394Sbostic 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
84*65394Sbostic 	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
85*65394Sbostic 	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
86*65394Sbostic 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
87*65394Sbostic 	NF = &nfloc->fval;
88*65394Sbostic 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
89*65394Sbostic 	NR = &nrloc->fval;
90*65394Sbostic 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
91*65394Sbostic 	FNR = &fnrloc->fval;
92*65394Sbostic 	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
93*65394Sbostic 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
94*65394Sbostic 	RSTART = &rstartloc->fval;
95*65394Sbostic 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
96*65394Sbostic 	RLENGTH = &rlengthloc->fval;
97*65394Sbostic 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
98*65394Sbostic 	symtabloc->sval = (uchar *) symtab;
99*65394Sbostic }
100*65394Sbostic 
101*65394Sbostic void arginit(int ac, uchar *av[])	/* set up ARGV and ARGC */
102*65394Sbostic {
103*65394Sbostic 	Cell *cp;
104*65394Sbostic 	int i;
105*65394Sbostic 	uchar temp[5];
106*65394Sbostic 
107*65394Sbostic 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
108*65394Sbostic 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
109*65394Sbostic 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
110*65394Sbostic 	cp->sval = (uchar *) ARGVtab;
111*65394Sbostic 	for (i = 0; i < ac; i++) {
112*65394Sbostic 		sprintf((char *)temp, "%d", i);
113*65394Sbostic 		if (isnumber(*av))
114*65394Sbostic 			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
115*65394Sbostic 		else
116*65394Sbostic 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
117*65394Sbostic 		av++;
118*65394Sbostic 	}
119*65394Sbostic }
120*65394Sbostic 
121*65394Sbostic void envinit(uchar **envp)	/* set up ENVIRON variable */
122*65394Sbostic {
123*65394Sbostic 	Cell *cp;
124*65394Sbostic 	uchar *p;
125*65394Sbostic 
126*65394Sbostic 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
127*65394Sbostic 	ENVtab = makesymtab(NSYMTAB);
128*65394Sbostic 	cp->sval = (uchar *) ENVtab;
129*65394Sbostic 	for ( ; *envp; envp++) {
130*65394Sbostic 		if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL)
131*65394Sbostic 			continue;
132*65394Sbostic 		*p++ = 0;	/* split into two strings at = */
133*65394Sbostic 		if (isnumber(p))
134*65394Sbostic 			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
135*65394Sbostic 		else
136*65394Sbostic 			setsymtab(*envp, p, 0.0, STR, ENVtab);
137*65394Sbostic 		p[-1] = '=';	/* restore in case env is passed down to a shell */
138*65394Sbostic 	}
139*65394Sbostic }
140*65394Sbostic 
141*65394Sbostic Array *makesymtab(int n)	/* make a new symbol table */
142*65394Sbostic {
143*65394Sbostic 	Array *ap;
144*65394Sbostic 	Cell **tp;
145*65394Sbostic 
146*65394Sbostic 	ap = (Array *) malloc(sizeof(Array));
147*65394Sbostic 	tp = (Cell **) calloc(n, sizeof(Cell *));
148*65394Sbostic 	if (ap == NULL || tp == NULL)
149*65394Sbostic 		ERROR "out of space in makesymtab" FATAL;
150*65394Sbostic 	ap->nelem = 0;
151*65394Sbostic 	ap->size = n;
152*65394Sbostic 	ap->tab = tp;
153*65394Sbostic 	return(ap);
154*65394Sbostic }
155*65394Sbostic 
156*65394Sbostic void freesymtab(Cell *ap)	/* free a symbol table */
157*65394Sbostic {
158*65394Sbostic 	Cell *cp, *temp;
159*65394Sbostic 	Array *tp;
160*65394Sbostic 	int i;
161*65394Sbostic 
162*65394Sbostic 	if (!isarr(ap))
163*65394Sbostic 		return;
164*65394Sbostic 	tp = (Array *) ap->sval;
165*65394Sbostic 	if (tp == NULL)
166*65394Sbostic 		return;
167*65394Sbostic 	for (i = 0; i < tp->size; i++) {
168*65394Sbostic 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
169*65394Sbostic 			xfree(cp->nval);
170*65394Sbostic 			if (freeable(cp))
171*65394Sbostic 				xfree(cp->sval);
172*65394Sbostic 			temp = cp->cnext;	/* avoids freeing then using */
173*65394Sbostic 			free((char *) cp);
174*65394Sbostic 		}
175*65394Sbostic 	}
176*65394Sbostic 	free((char *) (tp->tab));
177*65394Sbostic 	free((char *) tp);
178*65394Sbostic }
179*65394Sbostic 
180*65394Sbostic void freeelem(Cell *ap, uchar *s)	/* free elem s from ap (i.e., ap["s"] */
181*65394Sbostic {
182*65394Sbostic 	Array *tp;
183*65394Sbostic 	Cell *p, *prev = NULL;
184*65394Sbostic 	int h;
185*65394Sbostic 
186*65394Sbostic 	tp = (Array *) ap->sval;
187*65394Sbostic 	h = hash(s, tp->size);
188*65394Sbostic 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
189*65394Sbostic 		if (strcmp((char *) s, (char *) p->nval) == 0) {
190*65394Sbostic 			if (prev == NULL)	/* 1st one */
191*65394Sbostic 				tp->tab[h] = p->cnext;
192*65394Sbostic 			else			/* middle somewhere */
193*65394Sbostic 				prev->cnext = p->cnext;
194*65394Sbostic 			if (freeable(p))
195*65394Sbostic 				xfree(p->sval);
196*65394Sbostic 			free(p->nval);
197*65394Sbostic 			free((char *) p);
198*65394Sbostic 			tp->nelem--;
199*65394Sbostic 			return;
200*65394Sbostic 		}
201*65394Sbostic }
202*65394Sbostic 
203*65394Sbostic Cell *setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned t, Array *tp)
204*65394Sbostic {
205*65394Sbostic 	register int h;
206*65394Sbostic 	register Cell *p;
207*65394Sbostic 
208*65394Sbostic 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
209*65394Sbostic 		dprintf( ("setsymtab found %o: n=%s s=\"%s\" f=%g t=%o\n",
210*65394Sbostic 			p, p->nval, p->sval, p->fval, p->tval) );
211*65394Sbostic 		return(p);
212*65394Sbostic 	}
213*65394Sbostic 	p = (Cell *) malloc(sizeof(Cell));
214*65394Sbostic 	if (p == NULL)
215*65394Sbostic 		ERROR "out of space for symbol table at %s", n FATAL;
216*65394Sbostic 	p->nval = tostring(n);
217*65394Sbostic 	p->sval = s ? tostring(s) : tostring("");
218*65394Sbostic 	p->fval = f;
219*65394Sbostic 	p->tval = t;
220*65394Sbostic 	tp->nelem++;
221*65394Sbostic 	if (tp->nelem > FULLTAB * tp->size)
222*65394Sbostic 		rehash(tp);
223*65394Sbostic 	h = hash(n, tp->size);
224*65394Sbostic 	p->cnext = tp->tab[h];
225*65394Sbostic 	tp->tab[h] = p;
226*65394Sbostic 	dprintf( ("setsymtab set %o: n=%s s=\"%s\" f=%g t=%o\n",
227*65394Sbostic 		p, p->nval, p->sval, p->fval, p->tval) );
228*65394Sbostic 	return(p);
229*65394Sbostic }
230*65394Sbostic 
231*65394Sbostic hash(uchar *s, int n)	/* form hash value for string s */
232*65394Sbostic {
233*65394Sbostic 	register unsigned hashval;
234*65394Sbostic 
235*65394Sbostic 	for (hashval = 0; *s != '\0'; s++)
236*65394Sbostic 		hashval = (*s + 31 * hashval);
237*65394Sbostic 	return hashval % n;
238*65394Sbostic }
239*65394Sbostic 
240*65394Sbostic void rehash(Array *tp)	/* rehash items in small table into big one */
241*65394Sbostic {
242*65394Sbostic 	int i, nh, nsz;
243*65394Sbostic 	Cell *cp, *op, **np;
244*65394Sbostic 
245*65394Sbostic 	nsz = GROWTAB * tp->size;
246*65394Sbostic 	np = (Cell **) calloc(nsz, sizeof(Cell *));
247*65394Sbostic 	if (np == NULL)		/* can't do it, but can keep running. */
248*65394Sbostic 		return;		/* someone else will run out later. */
249*65394Sbostic 	for (i = 0; i < tp->size; i++) {
250*65394Sbostic 		for (cp = tp->tab[i]; cp; cp = op) {
251*65394Sbostic 			op = cp->cnext;
252*65394Sbostic 			nh = hash(cp->nval, nsz);
253*65394Sbostic 			cp->cnext = np[nh];
254*65394Sbostic 			np[nh] = cp;
255*65394Sbostic 		}
256*65394Sbostic 	}
257*65394Sbostic 	free((char *) (tp->tab));
258*65394Sbostic 	tp->tab = np;
259*65394Sbostic 	tp->size = nsz;
260*65394Sbostic }
261*65394Sbostic 
262*65394Sbostic Cell *lookup(uchar *s, Array *tp)	/* look for s in tp */
263*65394Sbostic {
264*65394Sbostic 	register Cell *p, *prev = NULL;
265*65394Sbostic 	int h;
266*65394Sbostic 
267*65394Sbostic 	h = hash(s, tp->size);
268*65394Sbostic 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
269*65394Sbostic 		if (strcmp((char *) s, (char *) p->nval) == 0)
270*65394Sbostic 			return(p);	/* found it */
271*65394Sbostic 	return(NULL);			/* not found */
272*65394Sbostic }
273*65394Sbostic 
274*65394Sbostic Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
275*65394Sbostic {
276*65394Sbostic 	if ((vp->tval & (NUM | STR)) == 0)
277*65394Sbostic 		funnyvar(vp, "assign to");
278*65394Sbostic 	if (vp->tval & FLD) {
279*65394Sbostic 		donerec = 0;	/* mark $0 invalid */
280*65394Sbostic 		if (vp-fldtab > *NF)
281*65394Sbostic 			newfld(vp-fldtab);
282*65394Sbostic 		dprintf( ("setting field %d to %g\n", vp-fldtab, f) );
283*65394Sbostic 	} else if (vp->tval & REC) {
284*65394Sbostic 		donefld = 0;	/* mark $1... invalid */
285*65394Sbostic 		donerec = 1;
286*65394Sbostic 	}
287*65394Sbostic 	vp->tval &= ~STR;	/* mark string invalid */
288*65394Sbostic 	vp->tval |= NUM;	/* mark number ok */
289*65394Sbostic 	dprintf( ("setfval %o: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
290*65394Sbostic 	return vp->fval = f;
291*65394Sbostic }
292*65394Sbostic 
293*65394Sbostic void funnyvar(Cell *vp, char *rw)
294*65394Sbostic {
295*65394Sbostic 	if (vp->tval & ARR)
296*65394Sbostic 		ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
297*65394Sbostic 	if (vp->tval & FCN)
298*65394Sbostic 		ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
299*65394Sbostic 	ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
300*65394Sbostic 		vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING;
301*65394Sbostic }
302*65394Sbostic 
303*65394Sbostic uchar *setsval(Cell *vp, uchar *s)	/* set string val of a Cell */
304*65394Sbostic {
305*65394Sbostic 	if ((vp->tval & (NUM | STR)) == 0)
306*65394Sbostic 		funnyvar(vp, "assign to");
307*65394Sbostic 	if (vp->tval & FLD) {
308*65394Sbostic 		donerec = 0;	/* mark $0 invalid */
309*65394Sbostic 		if (vp-fldtab > *NF)
310*65394Sbostic 			newfld(vp-fldtab);
311*65394Sbostic 		dprintf( ("setting field %d to %s\n", vp-fldtab, s) );
312*65394Sbostic 	} else if (vp->tval & REC) {
313*65394Sbostic 		donefld = 0;	/* mark $1... invalid */
314*65394Sbostic 		donerec = 1;
315*65394Sbostic 	}
316*65394Sbostic 	vp->tval &= ~NUM;
317*65394Sbostic 	vp->tval |= STR;
318*65394Sbostic 	if (freeable(vp))
319*65394Sbostic 		xfree(vp->sval);
320*65394Sbostic 	vp->tval &= ~DONTFREE;
321*65394Sbostic 	dprintf( ("setsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
322*65394Sbostic 	return(vp->sval = tostring(s));
323*65394Sbostic }
324*65394Sbostic 
325*65394Sbostic Awkfloat r_getfval(Cell *vp)	/* get float val of a Cell */
326*65394Sbostic {
327*65394Sbostic 	if ((vp->tval & (NUM | STR)) == 0)
328*65394Sbostic 		funnyvar(vp, "read value of");
329*65394Sbostic 	if ((vp->tval & FLD) && donefld == 0)
330*65394Sbostic 		fldbld();
331*65394Sbostic 	else if ((vp->tval & REC) && donerec == 0)
332*65394Sbostic 		recbld();
333*65394Sbostic 	if (!isnum(vp)) {	/* not a number */
334*65394Sbostic 		vp->fval = atof(vp->sval);	/* best guess */
335*65394Sbostic 		if (isnumber(vp->sval) && !(vp->tval&CON))
336*65394Sbostic 			vp->tval |= NUM;	/* make NUM only sparingly */
337*65394Sbostic 	}
338*65394Sbostic 	dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
339*65394Sbostic 	return(vp->fval);
340*65394Sbostic }
341*65394Sbostic 
342*65394Sbostic uchar *r_getsval(Cell *vp)	/* get string val of a Cell */
343*65394Sbostic {
344*65394Sbostic 	uchar s[100];
345*65394Sbostic 	double dtemp;
346*65394Sbostic 
347*65394Sbostic 	if ((vp->tval & (NUM | STR)) == 0)
348*65394Sbostic 		funnyvar(vp, "read value of");
349*65394Sbostic 	if ((vp->tval & FLD) && donefld == 0)
350*65394Sbostic 		fldbld();
351*65394Sbostic 	else if ((vp->tval & REC) && donerec == 0)
352*65394Sbostic 		recbld();
353*65394Sbostic 	if ((vp->tval & STR) == 0) {
354*65394Sbostic 		if (!(vp->tval&DONTFREE))
355*65394Sbostic 			xfree(vp->sval);
356*65394Sbostic 		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
357*65394Sbostic 			sprintf((char *)s, "%.20g", vp->fval);
358*65394Sbostic 		else
359*65394Sbostic 			sprintf((char *)s, (char *)*CONVFMT, vp->fval);
360*65394Sbostic 		vp->sval = tostring(s);
361*65394Sbostic 		vp->tval &= ~DONTFREE;
362*65394Sbostic 		vp->tval |= STR;
363*65394Sbostic 	}
364*65394Sbostic 	dprintf( ("getsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, vp->sval, vp->tval) );
365*65394Sbostic 	return(vp->sval);
366*65394Sbostic }
367*65394Sbostic 
368*65394Sbostic uchar *tostring(uchar *s)	/* make a copy of string s */
369*65394Sbostic {
370*65394Sbostic 	register uchar *p;
371*65394Sbostic 
372*65394Sbostic 	p = (uchar *) malloc(strlen((char *) s)+1);
373*65394Sbostic 	if (p == NULL)
374*65394Sbostic 		ERROR "out of space in tostring on %s", s FATAL;
375*65394Sbostic 	strcpy((char *) p, (char *) s);
376*65394Sbostic 	return(p);
377*65394Sbostic }
378*65394Sbostic 
379*65394Sbostic uchar *qstring(uchar *s, int delim)	/* collect string up to next delim */
380*65394Sbostic {
381*65394Sbostic 	uchar *q;
382*65394Sbostic 	int c, n;
383*65394Sbostic 
384*65394Sbostic 	for (q = cbuf; (c = *s) != delim; s++) {
385*65394Sbostic 		if (q >= cbuf + CBUFLEN - 1)
386*65394Sbostic 			ERROR "string %.10s... too long", cbuf SYNTAX;
387*65394Sbostic 		else if (c == '\n')
388*65394Sbostic 			ERROR "newline in string %.10s...", cbuf SYNTAX;
389*65394Sbostic 		else if (c != '\\')
390*65394Sbostic 			*q++ = c;
391*65394Sbostic 		else	/* \something */
392*65394Sbostic 			switch (c = *++s) {
393*65394Sbostic 			case '\\':	*q++ = '\\'; break;
394*65394Sbostic 			case 'n':	*q++ = '\n'; break;
395*65394Sbostic 			case 't':	*q++ = '\t'; break;
396*65394Sbostic 			case 'b':	*q++ = '\b'; break;
397*65394Sbostic 			case 'f':	*q++ = '\f'; break;
398*65394Sbostic 			case 'r':	*q++ = '\r'; break;
399*65394Sbostic 			default:
400*65394Sbostic 				if (!isdigit(c)) {
401*65394Sbostic 					*q++ = c;
402*65394Sbostic 					break;
403*65394Sbostic 				}
404*65394Sbostic 				n = c - '0';
405*65394Sbostic 				if (isdigit(s[1])) {
406*65394Sbostic 					n = 8 * n + *++s - '0';
407*65394Sbostic 					if (isdigit(s[1]))
408*65394Sbostic 						n = 8 * n + *++s - '0';
409*65394Sbostic 				}
410*65394Sbostic 				*q++ = n;
411*65394Sbostic 				break;
412*65394Sbostic 			}
413*65394Sbostic 	}
414*65394Sbostic 	*q = '\0';
415*65394Sbostic 	return cbuf;
416*65394Sbostic }
417