Annotation of src/usr.bin/awk/tran.c, Revision 1.21
1.21 ! millert 1: /* $OpenBSD: tran.c,v 1.20 2020/06/10 21:00:31 millert Exp $ */
1.1 tholo 2: /****************************************************************
1.3 kstailey 3: Copyright (C) Lucent Technologies 1997
1.1 tholo 4: All Rights Reserved
5:
6: Permission to use, copy, modify, and distribute this software and
7: its documentation for any purpose and without fee is hereby
8: granted, provided that the above copyright notice appear in all
9: copies and that both that the copyright notice and this
10: permission notice and warranty disclaimer appear in supporting
1.3 kstailey 11: documentation, and that the name Lucent Technologies or any of
12: its entities not be used in advertising or publicity pertaining
13: to distribution of the software without specific, written prior
14: permission.
15:
16: LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
18: IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
19: SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20: WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
21: IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
23: THIS SOFTWARE.
1.1 tholo 24: ****************************************************************/
25:
26: #define DEBUG
27: #include <stdio.h>
28: #include <math.h>
29: #include <ctype.h>
30: #include <string.h>
31: #include <stdlib.h>
32: #include "awk.h"
1.3 kstailey 33: #include "ytab.h"
1.1 tholo 34:
35: #define FULLTAB 2 /* rehash when table gets this x full */
36: #define GROWTAB 4 /* grow table by this factor */
37:
38: Array *symtab; /* main symbol table */
39:
40: char **FS; /* initial field sep */
41: char **RS; /* initial record sep */
42: char **OFS; /* output field sep */
43: char **ORS; /* output record sep */
44: char **OFMT; /* output format for numbers */
45: char **CONVFMT; /* format for conversions in getsval */
46: Awkfloat *NF; /* number of fields in current record */
47: Awkfloat *NR; /* number of current record */
48: Awkfloat *FNR; /* number of current record in current file */
49: char **FILENAME; /* current filename argument */
50: Awkfloat *ARGC; /* number of arguments from command line */
51: char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
52: Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
53: Awkfloat *RLENGTH; /* length of same */
54:
1.11 millert 55: Cell *fsloc; /* FS */
1.1 tholo 56: Cell *nrloc; /* NR */
57: Cell *nfloc; /* NF */
58: Cell *fnrloc; /* FNR */
1.21 ! millert 59: Cell *ofsloc; /* OFS */
! 60: Cell *orsloc; /* ORS */
! 61: Cell *rsloc; /* RS */
1.1 tholo 62: Array *ARGVtab; /* symbol table containing ARGV[...] */
63: Array *ENVtab; /* symbol table containing ENVIRON[...] */
64: Cell *rstartloc; /* RSTART */
65: Cell *rlengthloc; /* RLENGTH */
1.21 ! millert 66: Cell *subseploc; /* SUBSEP */
1.1 tholo 67: Cell *symtabloc; /* SYMTAB */
68:
69: Cell *nullloc; /* a guaranteed empty cell */
70: Node *nullnode; /* zero&null, converted into a node for comparisons */
1.3 kstailey 71: Cell *literal0;
1.1 tholo 72:
1.3 kstailey 73: extern Cell **fldtab;
1.1 tholo 74:
1.19 millert 75: static void
76: setfree(Cell *vp)
77: {
78: if (&vp->sval == FS || &vp->sval == RS ||
79: &vp->sval == OFS || &vp->sval == ORS ||
80: &vp->sval == OFMT || &vp->sval == CONVFMT ||
81: &vp->sval == FILENAME || &vp->sval == SUBSEP)
82: vp->tval |= DONTFREE;
83: else
84: vp->tval &= ~DONTFREE;
85: }
86:
1.1 tholo 87: void syminit(void) /* initialize symbol table with builtin vars */
88: {
1.3 kstailey 89: literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
1.1 tholo 90: /* this is used for if(x)... tests: */
91: nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
1.3 kstailey 92: nullnode = celltonode(nullloc, CCON);
1.1 tholo 93:
1.11 millert 94: fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
95: FS = &fsloc->sval;
1.21 ! millert 96: rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab);
! 97: RS = &rsloc->sval;
! 98: ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab);
! 99: OFS = &ofsloc->sval;
! 100: orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab);
! 101: ORS = &orsloc->sval;
1.1 tholo 102: OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
103: CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
1.2 millert 104: FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
1.1 tholo 105: nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
106: NF = &nfloc->fval;
107: nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
108: NR = &nrloc->fval;
109: fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
110: FNR = &fnrloc->fval;
1.21 ! millert 111: subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab);
! 112: SUBSEP = &subseploc->sval;
1.1 tholo 113: rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
114: RSTART = &rstartloc->fval;
115: rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
116: RLENGTH = &rlengthloc->fval;
117: symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
118: symtabloc->sval = (char *) symtab;
119: }
120:
1.3 kstailey 121: void arginit(int ac, char **av) /* set up ARGV and ARGC */
1.1 tholo 122: {
123: Cell *cp;
124: int i;
1.3 kstailey 125: char temp[50];
1.1 tholo 126:
127: ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
128: cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
129: ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
130: cp->sval = (char *) ARGVtab;
131: for (i = 0; i < ac; i++) {
1.9 deraadt 132: snprintf(temp, sizeof temp, "%d", i);
1.4 millert 133: if (is_number(*av))
1.1 tholo 134: setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
135: else
136: setsymtab(temp, *av, 0.0, STR, ARGVtab);
137: av++;
138: }
139: }
140:
141: void envinit(char **envp) /* set up ENVIRON variable */
142: {
143: Cell *cp;
144: char *p;
145:
146: cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
147: ENVtab = makesymtab(NSYMTAB);
148: cp->sval = (char *) ENVtab;
149: for ( ; *envp; envp++) {
1.3 kstailey 150: if ((p = strchr(*envp, '=')) == NULL)
1.1 tholo 151: continue;
1.7 millert 152: if( p == *envp ) /* no left hand side name in env string */
153: continue;
1.1 tholo 154: *p++ = 0; /* split into two strings at = */
1.4 millert 155: if (is_number(p))
1.1 tholo 156: setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
157: else
158: setsymtab(*envp, p, 0.0, STR, ENVtab);
159: p[-1] = '='; /* restore in case env is passed down to a shell */
160: }
161: }
162:
163: Array *makesymtab(int n) /* make a new symbol table */
164: {
165: Array *ap;
166: Cell **tp;
167:
168: ap = (Array *) malloc(sizeof(Array));
169: tp = (Cell **) calloc(n, sizeof(Cell *));
170: if (ap == NULL || tp == NULL)
1.6 millert 171: FATAL("out of space in makesymtab");
1.1 tholo 172: ap->nelem = 0;
173: ap->size = n;
174: ap->tab = tp;
175: return(ap);
176: }
177:
178: void freesymtab(Cell *ap) /* free a symbol table */
179: {
180: Cell *cp, *temp;
181: Array *tp;
182: int i;
183:
184: if (!isarr(ap))
185: return;
186: tp = (Array *) ap->sval;
187: if (tp == NULL)
188: return;
189: for (i = 0; i < tp->size; i++) {
190: for (cp = tp->tab[i]; cp != NULL; cp = temp) {
191: xfree(cp->nval);
192: if (freeable(cp))
193: xfree(cp->sval);
194: temp = cp->cnext; /* avoids freeing then using */
1.3 kstailey 195: free(cp);
1.8 millert 196: tp->nelem--;
1.1 tholo 197: }
198: tp->tab[i] = 0;
199: }
1.8 millert 200: if (tp->nelem != 0)
201: WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
1.3 kstailey 202: free(tp->tab);
203: free(tp);
1.1 tholo 204: }
205:
1.8 millert 206: void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */
1.1 tholo 207: {
208: Array *tp;
209: Cell *p, *prev = NULL;
210: int h;
211:
212: tp = (Array *) ap->sval;
213: h = hash(s, tp->size);
214: for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
1.3 kstailey 215: if (strcmp(s, p->nval) == 0) {
1.1 tholo 216: if (prev == NULL) /* 1st one */
217: tp->tab[h] = p->cnext;
218: else /* middle somewhere */
219: prev->cnext = p->cnext;
220: if (freeable(p))
221: xfree(p->sval);
222: free(p->nval);
1.3 kstailey 223: free(p);
1.1 tholo 224: tp->nelem--;
225: return;
226: }
227: }
228:
1.8 millert 229: Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
1.1 tholo 230: {
231: int h;
232: Cell *p;
233:
234: if (n != NULL && (p = lookup(n, tp)) != NULL) {
1.16 deraadt 235: DPRINTF( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
1.15 millert 236: (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
1.1 tholo 237: return(p);
238: }
239: p = (Cell *) malloc(sizeof(Cell));
240: if (p == NULL)
1.6 millert 241: FATAL("out of space for symbol table at %s", n);
1.1 tholo 242: p->nval = tostring(n);
243: p->sval = s ? tostring(s) : tostring("");
244: p->fval = f;
245: p->tval = t;
246: p->csub = CUNK;
247: p->ctype = OCELL;
248: tp->nelem++;
249: if (tp->nelem > FULLTAB * tp->size)
250: rehash(tp);
251: h = hash(n, tp->size);
252: p->cnext = tp->tab[h];
253: tp->tab[h] = p;
1.16 deraadt 254: DPRINTF( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
1.15 millert 255: (void*)p, p->nval, p->sval, p->fval, p->tval) );
1.1 tholo 256: return(p);
257: }
258:
1.8 millert 259: int hash(const char *s, int n) /* form hash value for string s */
1.1 tholo 260: {
261: unsigned hashval;
262:
263: for (hashval = 0; *s != '\0'; s++)
264: hashval = (*s + 31 * hashval);
265: return hashval % n;
266: }
267:
268: void rehash(Array *tp) /* rehash items in small table into big one */
269: {
270: int i, nh, nsz;
271: Cell *cp, *op, **np;
272:
273: nsz = GROWTAB * tp->size;
274: np = (Cell **) calloc(nsz, sizeof(Cell *));
275: if (np == NULL) /* can't do it, but can keep running. */
276: return; /* someone else will run out later. */
277: for (i = 0; i < tp->size; i++) {
278: for (cp = tp->tab[i]; cp; cp = op) {
279: op = cp->cnext;
280: nh = hash(cp->nval, nsz);
281: cp->cnext = np[nh];
282: np[nh] = cp;
283: }
284: }
1.3 kstailey 285: free(tp->tab);
1.1 tholo 286: tp->tab = np;
287: tp->size = nsz;
288: }
289:
1.8 millert 290: Cell *lookup(const char *s, Array *tp) /* look for s in tp */
1.1 tholo 291: {
1.5 millert 292: Cell *p;
1.1 tholo 293: int h;
294:
295: h = hash(s, tp->size);
1.5 millert 296: for (p = tp->tab[h]; p != NULL; p = p->cnext)
1.3 kstailey 297: if (strcmp(s, p->nval) == 0)
1.1 tholo 298: return(p); /* found it */
299: return(NULL); /* not found */
300: }
301:
302: Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
303: {
1.3 kstailey 304: int fldno;
305:
1.19 millert 306: f += 0.0; /* normalise negative zero to positive zero */
1.1 tholo 307: if ((vp->tval & (NUM | STR)) == 0)
308: funnyvar(vp, "assign to");
1.3 kstailey 309: if (isfld(vp)) {
1.1 tholo 310: donerec = 0; /* mark $0 invalid */
1.3 kstailey 311: fldno = atoi(vp->nval);
312: if (fldno > *NF)
313: newfld(fldno);
1.16 deraadt 314: DPRINTF( ("setting field %d to %g\n", fldno, f) );
1.19 millert 315: } else if (&vp->fval == NF) {
316: donerec = 0; /* mark $0 invalid */
317: setlastfld(f);
318: DPRINTF( ("setting NF to %g\n", f) );
1.3 kstailey 319: } else if (isrec(vp)) {
1.1 tholo 320: donefld = 0; /* mark $1... invalid */
321: donerec = 1;
1.21 ! millert 322: } else if (vp == ofsloc) {
! 323: if (donerec == 0)
! 324: recbld();
1.1 tholo 325: }
1.4 millert 326: if (freeable(vp))
327: xfree(vp->sval); /* free any previous string */
1.19 millert 328: vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */
329: vp->fmt = NULL;
1.1 tholo 330: vp->tval |= NUM; /* mark number ok */
1.18 millert 331: if (f == -0) /* who would have thought this possible? */
332: f = 0;
1.16 deraadt 333: DPRINTF( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
1.1 tholo 334: return vp->fval = f;
335: }
336:
1.8 millert 337: void funnyvar(Cell *vp, const char *rw)
1.1 tholo 338: {
1.3 kstailey 339: if (isarr(vp))
1.6 millert 340: FATAL("can't %s %s; it's an array name.", rw, vp->nval);
1.1 tholo 341: if (vp->tval & FCN)
1.6 millert 342: FATAL("can't %s %s; it's a function.", rw, vp->nval);
343: WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
344: vp, vp->nval, vp->sval, vp->fval, vp->tval);
1.1 tholo 345: }
346:
1.8 millert 347: char *setsval(Cell *vp, const char *s) /* set string val of a Cell */
1.1 tholo 348: {
349: char *t;
1.3 kstailey 350: int fldno;
1.19 millert 351: Awkfloat f;
1.1 tholo 352:
1.16 deraadt 353: DPRINTF( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
1.15 millert 354: (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
1.1 tholo 355: if ((vp->tval & (NUM | STR)) == 0)
356: funnyvar(vp, "assign to");
1.3 kstailey 357: if (isfld(vp)) {
1.1 tholo 358: donerec = 0; /* mark $0 invalid */
1.3 kstailey 359: fldno = atoi(vp->nval);
360: if (fldno > *NF)
361: newfld(fldno);
1.20 millert 362: DPRINTF( ("setting field %d to %s (%p)\n", fldno, s, (void *) s) );
1.3 kstailey 363: } else if (isrec(vp)) {
1.1 tholo 364: donefld = 0; /* mark $1... invalid */
365: donerec = 1;
1.21 ! millert 366: } else if (vp == ofsloc) {
1.19 millert 367: if (donerec == 0)
368: recbld();
1.1 tholo 369: }
1.19 millert 370: t = s ? tostring(s) : tostring(""); /* in case it's self-assign */
1.14 jmc 371: if (freeable(vp))
372: xfree(vp->sval);
1.19 millert 373: vp->tval &= ~(NUM|CONVC|CONVO);
1.1 tholo 374: vp->tval |= STR;
1.19 millert 375: vp->fmt = NULL;
376: setfree(vp);
1.16 deraadt 377: DPRINTF( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
1.20 millert 378: (void*)vp, NN(vp->nval), t, (void *) t, vp->tval, donerec, donefld) );
1.19 millert 379: vp->sval = t;
380: if (&vp->fval == NF) {
381: donerec = 0; /* mark $0 invalid */
382: f = getfval(vp);
383: setlastfld(f);
384: DPRINTF( ("setting NF to %g\n", f) );
385: }
386:
387: return(vp->sval);
1.1 tholo 388: }
389:
390: Awkfloat getfval(Cell *vp) /* get float val of a Cell */
391: {
392: if ((vp->tval & (NUM | STR)) == 0)
393: funnyvar(vp, "read value of");
1.3 kstailey 394: if (isfld(vp) && donefld == 0)
1.1 tholo 395: fldbld();
1.3 kstailey 396: else if (isrec(vp) && donerec == 0)
1.1 tholo 397: recbld();
398: if (!isnum(vp)) { /* not a number */
399: vp->fval = atof(vp->sval); /* best guess */
1.4 millert 400: if (is_number(vp->sval) && !(vp->tval&CON))
1.1 tholo 401: vp->tval |= NUM; /* make NUM only sparingly */
402: }
1.16 deraadt 403: DPRINTF( ("getfval %p: %s = %g, t=%o\n",
1.15 millert 404: (void*)vp, NN(vp->nval), vp->fval, vp->tval) );
1.1 tholo 405: return(vp->fval);
406: }
407:
1.11 millert 408: static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
1.1 tholo 409: {
1.13 millert 410: int n;
1.1 tholo 411: double dtemp;
412:
413: if ((vp->tval & (NUM | STR)) == 0)
414: funnyvar(vp, "read value of");
1.3 kstailey 415: if (isfld(vp) && donefld == 0)
1.1 tholo 416: fldbld();
1.3 kstailey 417: else if (isrec(vp) && donerec == 0)
1.1 tholo 418: recbld();
1.19 millert 419:
420: /*
421: * ADR: This is complicated and more fragile than is desirable.
422: * Retrieving a string value for a number associates the string
423: * value with the scalar. Previously, the string value was
424: * sticky, meaning if converted via OFMT that became the value
425: * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
426: * changed after a string value was retrieved, the original value
427: * was maintained and used. Also not per POSIX.
428: *
429: * We work around this design by adding two additional flags,
430: * CONVC and CONVO, indicating how the string value was
431: * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
432: * of the pointer to the xFMT format string used for the
433: * conversion. This pointer is only read, **never** dereferenced.
434: * The next time we do a conversion, if it's coming from the same
435: * xFMT as last time, and the pointer value is different, we
436: * know that the xFMT format string changed, and we need to
437: * redo the conversion. If it's the same, we don't have to.
438: *
439: * There are also several cases where we don't do a conversion,
440: * such as for a field (see the checks below).
441: */
442:
443: /* Don't duplicate the code for actually updating the value */
444: #define update_str_val(vp) \
445: { \
446: if (freeable(vp)) \
447: xfree(vp->sval); \
448: if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \
449: n = asprintf(&vp->sval, "%.30g", vp->fval); \
450: else \
451: n = asprintf(&vp->sval, *fmt, vp->fval); \
452: if (n == -1) \
453: FATAL("out of space in get_str_val"); \
454: vp->tval &= ~DONTFREE; \
455: vp->tval |= STR; \
456: }
457:
1.3 kstailey 458: if (isstr(vp) == 0) {
1.19 millert 459: update_str_val(vp);
460: if (fmt == OFMT) {
461: vp->tval &= ~CONVC;
462: vp->tval |= CONVO;
463: } else {
464: /* CONVFMT */
465: vp->tval &= ~CONVO;
466: vp->tval |= CONVC;
467: }
468: vp->fmt = *fmt;
469: } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
470: goto done;
471: } else if (isstr(vp)) {
472: if (fmt == OFMT) {
473: if ((vp->tval & CONVC) != 0
474: || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
475: update_str_val(vp);
476: vp->tval &= ~CONVC;
477: vp->tval |= CONVO;
478: vp->fmt = *fmt;
479: }
480: } else {
481: /* CONVFMT */
482: if ((vp->tval & CONVO) != 0
483: || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
484: update_str_val(vp);
485: vp->tval &= ~CONVO;
486: vp->tval |= CONVC;
487: vp->fmt = *fmt;
488: }
489: }
1.1 tholo 490: }
1.19 millert 491: done:
1.16 deraadt 492: DPRINTF( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
1.20 millert 493: (void*)vp, NN(vp->nval), vp->sval, (void *) vp->sval, vp->tval) );
1.1 tholo 494: return(vp->sval);
495: }
496:
1.8 millert 497: char *getsval(Cell *vp) /* get string val of a Cell */
498: {
499: return get_str_val(vp, CONVFMT);
500: }
501:
502: char *getpssval(Cell *vp) /* get string val of a Cell for print */
503: {
504: return get_str_val(vp, OFMT);
505: }
506:
507:
508: char *tostring(const char *s) /* make a copy of string s */
1.1 tholo 509: {
1.12 millert 510: char *p;
511:
512: p = strdup(s);
513: if (p == NULL)
514: FATAL("out of space in tostring on %s", s);
515: return p;
1.1 tholo 516: }
517:
1.8 millert 518: char *qstring(const char *is, int delim) /* collect string up to next delim */
1.1 tholo 519: {
1.8 millert 520: const char *os = is;
1.1 tholo 521: int c, n;
1.7 millert 522: uschar *s = (uschar *) is;
523: uschar *buf, *bp;
1.1 tholo 524:
1.8 millert 525: if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
1.6 millert 526: FATAL( "out of space in qstring(%s)", s);
1.3 kstailey 527: for (bp = buf; (c = *s) != delim; s++) {
1.1 tholo 528: if (c == '\n')
1.6 millert 529: SYNTAX( "newline in string %.20s...", os );
1.1 tholo 530: else if (c != '\\')
1.3 kstailey 531: *bp++ = c;
1.6 millert 532: else { /* \something */
533: c = *++s;
534: if (c == 0) { /* \ at end */
535: *bp++ = '\\';
536: break; /* for loop */
537: }
538: switch (c) {
1.3 kstailey 539: case '\\': *bp++ = '\\'; break;
540: case 'n': *bp++ = '\n'; break;
541: case 't': *bp++ = '\t'; break;
1.17 millert 542: case 'v': *bp++ = '\v'; break;
1.3 kstailey 543: case 'b': *bp++ = '\b'; break;
544: case 'f': *bp++ = '\f'; break;
545: case 'r': *bp++ = '\r'; break;
1.17 millert 546: case 'a': *bp++ = '\007'; break;
1.1 tholo 547: default:
548: if (!isdigit(c)) {
1.3 kstailey 549: *bp++ = c;
1.1 tholo 550: break;
551: }
552: n = c - '0';
553: if (isdigit(s[1])) {
554: n = 8 * n + *++s - '0';
555: if (isdigit(s[1]))
556: n = 8 * n + *++s - '0';
557: }
1.3 kstailey 558: *bp++ = n;
1.1 tholo 559: break;
560: }
1.3 kstailey 561: }
1.1 tholo 562: }
1.3 kstailey 563: *bp++ = 0;
1.7 millert 564: return (char *) buf;
1.19 millert 565: }
566:
567: const char *flags2str(int flags)
568: {
569: static const struct ftab {
570: const char *name;
571: int value;
572: } flagtab[] = {
573: { "NUM", NUM },
574: { "STR", STR },
575: { "DONTFREE", DONTFREE },
576: { "CON", CON },
577: { "ARR", ARR },
578: { "FCN", FCN },
579: { "FLD", FLD },
580: { "REC", REC },
581: { "CONVC", CONVC },
582: { "CONVO", CONVO },
583: { NULL, 0 }
584: };
585: static char buf[100];
586: int i, len;
587: char *cp = buf;
588:
589: for (i = 0; flagtab[i].name != NULL; i++) {
590: if ((flags & flagtab[i].value) != 0) {
591: len = snprintf(cp, sizeof(buf) - (cp - buf),
592: "%s%s", cp > buf ? "|" : "", flagtab[i].name);
593: if (len < 0 || len >= sizeof(buf) - (cp - buf))
594: FATAL("out of space in flags2str");
595: cp += len;
596: }
597: }
598:
599: return buf;
1.1 tholo 600: }