Annotation of src/usr.bin/awk/tran.c, Revision 1.23
1.23 ! millert 1: /* $OpenBSD: tran.c,v 1.22 2020/06/10 21:02:33 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:
1.23 ! millert 168: ap = malloc(sizeof(*ap));
! 169: tp = calloc(n, sizeof(*tp));
1.1 tholo 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.22 millert 195: free(cp);
1.8 millert 196: tp->nelem--;
1.1 tholo 197: }
1.22 millert 198: tp->tab[i] = NULL;
1.1 tholo 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;
1.22 millert 211:
1.1 tholo 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: }
1.23 ! millert 239: p = malloc(sizeof(*p));
1.1 tholo 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;
1.23 ! millert 274: np = calloc(nsz, sizeof(*np));
1.1 tholo 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.22 millert 307: if ((vp->tval & (NUM | STR)) == 0)
1.1 tholo 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.22 millert 322: savefs();
1.21 millert 323: } else if (vp == ofsloc) {
324: if (donerec == 0)
325: recbld();
1.1 tholo 326: }
1.4 millert 327: if (freeable(vp))
328: xfree(vp->sval); /* free any previous string */
1.19 millert 329: vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */
330: vp->fmt = NULL;
1.1 tholo 331: vp->tval |= NUM; /* mark number ok */
1.18 millert 332: if (f == -0) /* who would have thought this possible? */
333: f = 0;
1.16 deraadt 334: DPRINTF( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
1.1 tholo 335: return vp->fval = f;
336: }
337:
1.8 millert 338: void funnyvar(Cell *vp, const char *rw)
1.1 tholo 339: {
1.3 kstailey 340: if (isarr(vp))
1.6 millert 341: FATAL("can't %s %s; it's an array name.", rw, vp->nval);
1.1 tholo 342: if (vp->tval & FCN)
1.6 millert 343: FATAL("can't %s %s; it's a function.", rw, vp->nval);
344: WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
345: vp, vp->nval, vp->sval, vp->fval, vp->tval);
1.1 tholo 346: }
347:
1.8 millert 348: char *setsval(Cell *vp, const char *s) /* set string val of a Cell */
1.1 tholo 349: {
350: char *t;
1.3 kstailey 351: int fldno;
1.19 millert 352: Awkfloat f;
1.1 tholo 353:
1.22 millert 354: DPRINTF( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
1.15 millert 355: (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
1.1 tholo 356: if ((vp->tval & (NUM | STR)) == 0)
357: funnyvar(vp, "assign to");
1.3 kstailey 358: if (isfld(vp)) {
1.1 tholo 359: donerec = 0; /* mark $0 invalid */
1.3 kstailey 360: fldno = atoi(vp->nval);
361: if (fldno > *NF)
362: newfld(fldno);
1.23 ! millert 363: DPRINTF( ("setting field %d to %s (%p)\n", fldno, s, s) );
1.3 kstailey 364: } else if (isrec(vp)) {
1.1 tholo 365: donefld = 0; /* mark $1... invalid */
366: donerec = 1;
1.22 millert 367: savefs();
1.21 millert 368: } else if (vp == ofsloc) {
1.19 millert 369: if (donerec == 0)
370: recbld();
1.1 tholo 371: }
1.19 millert 372: t = s ? tostring(s) : tostring(""); /* in case it's self-assign */
1.14 jmc 373: if (freeable(vp))
374: xfree(vp->sval);
1.19 millert 375: vp->tval &= ~(NUM|CONVC|CONVO);
1.1 tholo 376: vp->tval |= STR;
1.19 millert 377: vp->fmt = NULL;
378: setfree(vp);
1.22 millert 379: DPRINTF( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
1.23 ! millert 380: (void*)vp, NN(vp->nval), t, t, vp->tval, donerec, donefld) );
1.19 millert 381: vp->sval = t;
382: if (&vp->fval == NF) {
383: donerec = 0; /* mark $0 invalid */
384: f = getfval(vp);
385: setlastfld(f);
386: DPRINTF( ("setting NF to %g\n", f) );
387: }
388:
389: return(vp->sval);
1.1 tholo 390: }
391:
392: Awkfloat getfval(Cell *vp) /* get float val of a Cell */
393: {
394: if ((vp->tval & (NUM | STR)) == 0)
395: funnyvar(vp, "read value of");
1.3 kstailey 396: if (isfld(vp) && donefld == 0)
1.1 tholo 397: fldbld();
1.3 kstailey 398: else if (isrec(vp) && donerec == 0)
1.1 tholo 399: recbld();
400: if (!isnum(vp)) { /* not a number */
401: vp->fval = atof(vp->sval); /* best guess */
1.4 millert 402: if (is_number(vp->sval) && !(vp->tval&CON))
1.1 tholo 403: vp->tval |= NUM; /* make NUM only sparingly */
404: }
1.16 deraadt 405: DPRINTF( ("getfval %p: %s = %g, t=%o\n",
1.15 millert 406: (void*)vp, NN(vp->nval), vp->fval, vp->tval) );
1.1 tholo 407: return(vp->fval);
408: }
409:
1.11 millert 410: static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
1.1 tholo 411: {
1.13 millert 412: int n;
1.1 tholo 413: double dtemp;
414:
415: if ((vp->tval & (NUM | STR)) == 0)
416: funnyvar(vp, "read value of");
1.3 kstailey 417: if (isfld(vp) && donefld == 0)
1.1 tholo 418: fldbld();
1.3 kstailey 419: else if (isrec(vp) && donerec == 0)
1.1 tholo 420: recbld();
1.19 millert 421:
422: /*
423: * ADR: This is complicated and more fragile than is desirable.
424: * Retrieving a string value for a number associates the string
425: * value with the scalar. Previously, the string value was
426: * sticky, meaning if converted via OFMT that became the value
427: * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
428: * changed after a string value was retrieved, the original value
429: * was maintained and used. Also not per POSIX.
430: *
431: * We work around this design by adding two additional flags,
432: * CONVC and CONVO, indicating how the string value was
433: * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
434: * of the pointer to the xFMT format string used for the
435: * conversion. This pointer is only read, **never** dereferenced.
436: * The next time we do a conversion, if it's coming from the same
437: * xFMT as last time, and the pointer value is different, we
438: * know that the xFMT format string changed, and we need to
439: * redo the conversion. If it's the same, we don't have to.
440: *
441: * There are also several cases where we don't do a conversion,
442: * such as for a field (see the checks below).
443: */
444:
445: /* Don't duplicate the code for actually updating the value */
446: #define update_str_val(vp) \
447: { \
448: if (freeable(vp)) \
449: xfree(vp->sval); \
450: if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \
451: n = asprintf(&vp->sval, "%.30g", vp->fval); \
452: else \
453: n = asprintf(&vp->sval, *fmt, vp->fval); \
454: if (n == -1) \
455: FATAL("out of space in get_str_val"); \
456: vp->tval &= ~DONTFREE; \
457: vp->tval |= STR; \
458: }
459:
1.3 kstailey 460: if (isstr(vp) == 0) {
1.19 millert 461: update_str_val(vp);
462: if (fmt == OFMT) {
463: vp->tval &= ~CONVC;
464: vp->tval |= CONVO;
465: } else {
466: /* CONVFMT */
467: vp->tval &= ~CONVO;
468: vp->tval |= CONVC;
469: }
470: vp->fmt = *fmt;
471: } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
472: goto done;
473: } else if (isstr(vp)) {
474: if (fmt == OFMT) {
475: if ((vp->tval & CONVC) != 0
476: || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
477: update_str_val(vp);
478: vp->tval &= ~CONVC;
479: vp->tval |= CONVO;
480: vp->fmt = *fmt;
481: }
482: } else {
483: /* CONVFMT */
484: if ((vp->tval & CONVO) != 0
485: || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
486: update_str_val(vp);
487: vp->tval &= ~CONVO;
488: vp->tval |= CONVC;
489: vp->fmt = *fmt;
490: }
491: }
1.1 tholo 492: }
1.19 millert 493: done:
1.16 deraadt 494: DPRINTF( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
1.23 ! millert 495: (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
1.1 tholo 496: return(vp->sval);
497: }
498:
1.8 millert 499: char *getsval(Cell *vp) /* get string val of a Cell */
500: {
501: return get_str_val(vp, CONVFMT);
502: }
503:
504: char *getpssval(Cell *vp) /* get string val of a Cell for print */
505: {
506: return get_str_val(vp, OFMT);
507: }
508:
509:
510: char *tostring(const char *s) /* make a copy of string s */
1.1 tholo 511: {
1.23 ! millert 512: char *p = strdup(s);
1.12 millert 513: if (p == NULL)
514: FATAL("out of space in tostring on %s", s);
1.23 ! millert 515: return(p);
1.1 tholo 516: }
517:
1.22 millert 518: Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
519: {
520: Cell *c;
521: char *p;
522: char *sa = getsval(a);
523: char *sb = getsval(b);
524: size_t l = strlen(sa) + strlen(sb) + 1;
525: p = malloc(l);
526: if (p == NULL)
527: FATAL("out of space concatenating %s and %s", sa, sb);
528: snprintf(p, l, "%s%s", sa, sb);
529: c = setsymtab(p, p, 0.0, CON|STR|DONTFREE, symtab);
530: free(p);
531: return c;
532: }
533:
1.8 millert 534: char *qstring(const char *is, int delim) /* collect string up to next delim */
1.1 tholo 535: {
1.8 millert 536: const char *os = is;
1.1 tholo 537: int c, n;
1.23 ! millert 538: const uschar *s = (const uschar *) is;
1.7 millert 539: uschar *buf, *bp;
1.1 tholo 540:
1.23 ! millert 541: if ((buf = malloc(strlen(is)+3)) == NULL)
1.6 millert 542: FATAL( "out of space in qstring(%s)", s);
1.3 kstailey 543: for (bp = buf; (c = *s) != delim; s++) {
1.1 tholo 544: if (c == '\n')
1.6 millert 545: SYNTAX( "newline in string %.20s...", os );
1.1 tholo 546: else if (c != '\\')
1.3 kstailey 547: *bp++ = c;
1.6 millert 548: else { /* \something */
549: c = *++s;
550: if (c == 0) { /* \ at end */
551: *bp++ = '\\';
552: break; /* for loop */
1.22 millert 553: }
1.6 millert 554: switch (c) {
1.3 kstailey 555: case '\\': *bp++ = '\\'; break;
556: case 'n': *bp++ = '\n'; break;
557: case 't': *bp++ = '\t'; break;
558: case 'b': *bp++ = '\b'; break;
559: case 'f': *bp++ = '\f'; break;
560: case 'r': *bp++ = '\r'; break;
1.22 millert 561: case 'v': *bp++ = '\v'; break;
562: case 'a': *bp++ = '\a'; break;
1.1 tholo 563: default:
564: if (!isdigit(c)) {
1.3 kstailey 565: *bp++ = c;
1.1 tholo 566: break;
567: }
568: n = c - '0';
569: if (isdigit(s[1])) {
570: n = 8 * n + *++s - '0';
571: if (isdigit(s[1]))
572: n = 8 * n + *++s - '0';
573: }
1.3 kstailey 574: *bp++ = n;
1.1 tholo 575: break;
576: }
1.3 kstailey 577: }
1.1 tholo 578: }
1.3 kstailey 579: *bp++ = 0;
1.7 millert 580: return (char *) buf;
1.19 millert 581: }
582:
583: const char *flags2str(int flags)
584: {
585: static const struct ftab {
586: const char *name;
587: int value;
588: } flagtab[] = {
589: { "NUM", NUM },
590: { "STR", STR },
591: { "DONTFREE", DONTFREE },
592: { "CON", CON },
593: { "ARR", ARR },
594: { "FCN", FCN },
595: { "FLD", FLD },
596: { "REC", REC },
597: { "CONVC", CONVC },
598: { "CONVO", CONVO },
599: { NULL, 0 }
600: };
601: static char buf[100];
602: int i, len;
603: char *cp = buf;
604:
605: for (i = 0; flagtab[i].name != NULL; i++) {
606: if ((flags & flagtab[i].value) != 0) {
607: len = snprintf(cp, sizeof(buf) - (cp - buf),
608: "%s%s", cp > buf ? "|" : "", flagtab[i].name);
609: if (len < 0 || len >= sizeof(buf) - (cp - buf))
610: FATAL("out of space in flags2str");
611: cp += len;
612: }
613: }
614:
615: return buf;
1.1 tholo 616: }