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