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