Annotation of src/usr.bin/awk/tran.c, Revision 1.36
1.36 ! millert 1: /* $OpenBSD: tran.c,v 1.35 2022/06/03 19:46:09 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:
74: void syminit(void) /* initialize symbol table with builtin vars */
75: {
1.3 kstailey 76: literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
1.1 tholo 77: /* this is used for if(x)... tests: */
78: nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
1.3 kstailey 79: nullnode = celltonode(nullloc, CCON);
1.1 tholo 80:
1.11 millert 81: fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
82: FS = &fsloc->sval;
1.21 millert 83: rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab);
84: RS = &rsloc->sval;
85: ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab);
86: OFS = &ofsloc->sval;
87: orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab);
88: ORS = &orsloc->sval;
1.1 tholo 89: OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
90: CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
1.2 millert 91: FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
1.1 tholo 92: nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
93: NF = &nfloc->fval;
94: nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
95: NR = &nrloc->fval;
96: fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
97: FNR = &fnrloc->fval;
1.21 millert 98: subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab);
99: SUBSEP = &subseploc->sval;
1.1 tholo 100: rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
101: RSTART = &rstartloc->fval;
102: rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
103: RLENGTH = &rlengthloc->fval;
104: symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
1.25 millert 105: free(symtabloc->sval);
1.1 tholo 106: symtabloc->sval = (char *) symtab;
107: }
108:
1.3 kstailey 109: void arginit(int ac, char **av) /* set up ARGV and ARGC */
1.1 tholo 110: {
111: Cell *cp;
112: int i;
1.3 kstailey 113: char temp[50];
1.1 tholo 114:
115: ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
116: cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
117: ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
1.25 millert 118: free(cp->sval);
1.1 tholo 119: cp->sval = (char *) ARGVtab;
120: for (i = 0; i < ac; i++) {
1.32 millert 121: double result;
122:
1.9 deraadt 123: snprintf(temp, sizeof temp, "%d", i);
1.32 millert 124: if (is_number(*av, & result))
125: setsymtab(temp, *av, result, STR|NUM, ARGVtab);
1.1 tholo 126: else
127: setsymtab(temp, *av, 0.0, STR, ARGVtab);
128: av++;
129: }
130: }
131:
132: void envinit(char **envp) /* set up ENVIRON variable */
133: {
134: Cell *cp;
135: char *p;
136:
137: cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
138: ENVtab = makesymtab(NSYMTAB);
1.25 millert 139: free(cp->sval);
1.1 tholo 140: cp->sval = (char *) ENVtab;
141: for ( ; *envp; envp++) {
1.32 millert 142: double result;
143:
1.3 kstailey 144: if ((p = strchr(*envp, '=')) == NULL)
1.1 tholo 145: continue;
1.7 millert 146: if( p == *envp ) /* no left hand side name in env string */
147: continue;
1.1 tholo 148: *p++ = 0; /* split into two strings at = */
1.32 millert 149: if (is_number(p, & result))
150: setsymtab(*envp, p, result, STR|NUM, ENVtab);
1.1 tholo 151: else
152: setsymtab(*envp, p, 0.0, STR, ENVtab);
153: p[-1] = '='; /* restore in case env is passed down to a shell */
154: }
155: }
156:
157: Array *makesymtab(int n) /* make a new symbol table */
158: {
159: Array *ap;
160: Cell **tp;
161:
1.32 millert 162: ap = (Array *) malloc(sizeof(*ap));
163: tp = (Cell **) calloc(n, sizeof(*tp));
1.1 tholo 164: if (ap == NULL || tp == NULL)
1.6 millert 165: FATAL("out of space in makesymtab");
1.1 tholo 166: ap->nelem = 0;
167: ap->size = n;
168: ap->tab = tp;
169: return(ap);
170: }
171:
172: void freesymtab(Cell *ap) /* free a symbol table */
173: {
174: Cell *cp, *temp;
175: Array *tp;
176: int i;
177:
178: if (!isarr(ap))
179: return;
180: tp = (Array *) ap->sval;
181: if (tp == NULL)
182: return;
183: for (i = 0; i < tp->size; i++) {
184: for (cp = tp->tab[i]; cp != NULL; cp = temp) {
185: xfree(cp->nval);
186: if (freeable(cp))
187: xfree(cp->sval);
188: temp = cp->cnext; /* avoids freeing then using */
1.22 millert 189: free(cp);
1.8 millert 190: tp->nelem--;
1.1 tholo 191: }
1.22 millert 192: tp->tab[i] = NULL;
1.1 tholo 193: }
1.8 millert 194: if (tp->nelem != 0)
195: WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
1.3 kstailey 196: free(tp->tab);
197: free(tp);
1.1 tholo 198: }
199:
1.8 millert 200: void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */
1.1 tholo 201: {
202: Array *tp;
203: Cell *p, *prev = NULL;
204: int h;
1.22 millert 205:
1.1 tholo 206: tp = (Array *) ap->sval;
207: h = hash(s, tp->size);
208: for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
1.3 kstailey 209: if (strcmp(s, p->nval) == 0) {
1.1 tholo 210: if (prev == NULL) /* 1st one */
211: tp->tab[h] = p->cnext;
212: else /* middle somewhere */
213: prev->cnext = p->cnext;
214: if (freeable(p))
215: xfree(p->sval);
216: free(p->nval);
1.3 kstailey 217: free(p);
1.1 tholo 218: tp->nelem--;
219: return;
220: }
221: }
222:
1.8 millert 223: Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
1.1 tholo 224: {
225: int h;
226: Cell *p;
227:
228: if (n != NULL && (p = lookup(n, tp)) != NULL) {
1.29 millert 229: DPRINTF("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
230: (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval);
1.1 tholo 231: return(p);
232: }
1.32 millert 233: p = (Cell *) malloc(sizeof(*p));
1.1 tholo 234: if (p == NULL)
1.6 millert 235: FATAL("out of space for symbol table at %s", n);
1.1 tholo 236: p->nval = tostring(n);
237: p->sval = s ? tostring(s) : tostring("");
238: p->fval = f;
239: p->tval = t;
240: p->csub = CUNK;
241: p->ctype = OCELL;
242: tp->nelem++;
243: if (tp->nelem > FULLTAB * tp->size)
244: rehash(tp);
245: h = hash(n, tp->size);
246: p->cnext = tp->tab[h];
247: tp->tab[h] = p;
1.29 millert 248: DPRINTF("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
249: (void*)p, p->nval, p->sval, p->fval, p->tval);
1.1 tholo 250: return(p);
251: }
252:
1.8 millert 253: int hash(const char *s, int n) /* form hash value for string s */
1.1 tholo 254: {
255: unsigned hashval;
256:
257: for (hashval = 0; *s != '\0'; s++)
258: hashval = (*s + 31 * hashval);
259: return hashval % n;
260: }
261:
262: void rehash(Array *tp) /* rehash items in small table into big one */
263: {
264: int i, nh, nsz;
265: Cell *cp, *op, **np;
266:
267: nsz = GROWTAB * tp->size;
1.32 millert 268: np = (Cell **) calloc(nsz, sizeof(*np));
1.1 tholo 269: if (np == NULL) /* can't do it, but can keep running. */
270: return; /* someone else will run out later. */
271: for (i = 0; i < tp->size; i++) {
272: for (cp = tp->tab[i]; cp; cp = op) {
273: op = cp->cnext;
274: nh = hash(cp->nval, nsz);
275: cp->cnext = np[nh];
276: np[nh] = cp;
277: }
278: }
1.3 kstailey 279: free(tp->tab);
1.1 tholo 280: tp->tab = np;
281: tp->size = nsz;
282: }
283:
1.8 millert 284: Cell *lookup(const char *s, Array *tp) /* look for s in tp */
1.1 tholo 285: {
1.5 millert 286: Cell *p;
1.1 tholo 287: int h;
288:
289: h = hash(s, tp->size);
1.5 millert 290: for (p = tp->tab[h]; p != NULL; p = p->cnext)
1.3 kstailey 291: if (strcmp(s, p->nval) == 0)
1.1 tholo 292: return(p); /* found it */
293: return(NULL); /* not found */
294: }
295:
296: Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
297: {
1.3 kstailey 298: int fldno;
299:
1.19 millert 300: f += 0.0; /* normalise negative zero to positive zero */
1.22 millert 301: if ((vp->tval & (NUM | STR)) == 0)
1.1 tholo 302: funnyvar(vp, "assign to");
1.3 kstailey 303: if (isfld(vp)) {
1.24 millert 304: donerec = false; /* mark $0 invalid */
1.3 kstailey 305: fldno = atoi(vp->nval);
306: if (fldno > *NF)
307: newfld(fldno);
1.29 millert 308: DPRINTF("setting field %d to %g\n", fldno, f);
1.19 millert 309: } else if (&vp->fval == NF) {
1.24 millert 310: donerec = false; /* mark $0 invalid */
1.19 millert 311: setlastfld(f);
1.29 millert 312: DPRINTF("setting NF to %g\n", f);
1.3 kstailey 313: } else if (isrec(vp)) {
1.24 millert 314: donefld = false; /* mark $1... invalid */
315: donerec = true;
1.22 millert 316: savefs();
1.21 millert 317: } else if (vp == ofsloc) {
1.24 millert 318: if (!donerec)
1.21 millert 319: recbld();
1.1 tholo 320: }
1.4 millert 321: if (freeable(vp))
322: xfree(vp->sval); /* free any previous string */
1.19 millert 323: vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */
324: vp->fmt = NULL;
1.1 tholo 325: vp->tval |= NUM; /* mark number ok */
1.18 millert 326: if (f == -0) /* who would have thought this possible? */
327: f = 0;
1.29 millert 328: DPRINTF("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval);
1.1 tholo 329: return vp->fval = f;
330: }
331:
1.8 millert 332: void funnyvar(Cell *vp, const char *rw)
1.1 tholo 333: {
1.3 kstailey 334: if (isarr(vp))
1.6 millert 335: FATAL("can't %s %s; it's an array name.", rw, vp->nval);
1.1 tholo 336: if (vp->tval & FCN)
1.6 millert 337: FATAL("can't %s %s; it's a function.", rw, vp->nval);
338: WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
1.27 millert 339: (void *)vp, vp->nval, vp->sval, vp->fval, vp->tval);
1.1 tholo 340: }
341:
1.8 millert 342: char *setsval(Cell *vp, const char *s) /* set string val of a Cell */
1.1 tholo 343: {
344: char *t;
1.3 kstailey 345: int fldno;
1.19 millert 346: Awkfloat f;
1.1 tholo 347:
1.29 millert 348: DPRINTF("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
349: (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld);
1.1 tholo 350: if ((vp->tval & (NUM | STR)) == 0)
351: funnyvar(vp, "assign to");
1.3 kstailey 352: if (isfld(vp)) {
1.24 millert 353: donerec = false; /* mark $0 invalid */
1.3 kstailey 354: fldno = atoi(vp->nval);
355: if (fldno > *NF)
356: newfld(fldno);
1.31 millert 357: DPRINTF("setting field %d to %s (%p)\n", fldno, s, (const void*)s);
1.3 kstailey 358: } else if (isrec(vp)) {
1.24 millert 359: donefld = false; /* mark $1... invalid */
360: donerec = true;
1.22 millert 361: savefs();
1.21 millert 362: } else if (vp == ofsloc) {
1.24 millert 363: if (!donerec)
1.19 millert 364: recbld();
1.1 tholo 365: }
1.19 millert 366: t = s ? tostring(s) : tostring(""); /* in case it's self-assign */
1.14 jmc 367: if (freeable(vp))
368: xfree(vp->sval);
1.35 millert 369: vp->tval &= ~(NUM|DONTFREE|CONVC|CONVO);
1.1 tholo 370: vp->tval |= STR;
1.19 millert 371: vp->fmt = NULL;
1.29 millert 372: DPRINTF("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
1.31 millert 373: (void*)vp, NN(vp->nval), t, (void*)t, vp->tval, donerec, donefld);
1.19 millert 374: vp->sval = t;
375: if (&vp->fval == NF) {
1.24 millert 376: donerec = false; /* mark $0 invalid */
1.19 millert 377: f = getfval(vp);
378: setlastfld(f);
1.29 millert 379: DPRINTF("setting NF to %g\n", f);
1.19 millert 380: }
381:
382: return(vp->sval);
1.1 tholo 383: }
384:
385: Awkfloat getfval(Cell *vp) /* get float val of a Cell */
386: {
387: if ((vp->tval & (NUM | STR)) == 0)
388: funnyvar(vp, "read value of");
1.24 millert 389: if (isfld(vp) && !donefld)
1.1 tholo 390: fldbld();
1.24 millert 391: else if (isrec(vp) && !donerec)
1.1 tholo 392: recbld();
393: if (!isnum(vp)) { /* not a number */
1.32 millert 394: double fval;
395: bool no_trailing;
396:
397: if (is_valid_number(vp->sval, true, & no_trailing, & fval)) {
398: vp->fval = fval;
399: if (no_trailing && !(vp->tval&CON))
400: vp->tval |= NUM; /* make NUM only sparingly */
401: } else
402: vp->fval = 0.0;
1.1 tholo 403: }
1.29 millert 404: DPRINTF("getfval %p: %s = %g, t=%o\n",
405: (void*)vp, NN(vp->nval), vp->fval, vp->tval);
1.1 tholo 406: return(vp->fval);
407: }
408:
1.34 millert 409: static const char *get_inf_nan(double d)
1.33 millert 410: {
411: if (isinf(d)) {
412: return (d < 0 ? "-inf" : "+inf");
413: } else if (isnan(d)) {
414: return (signbit(d) != 0 ? "-nan" : "+nan");
415: } else
416: return NULL;
417: }
418:
1.11 millert 419: static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
1.1 tholo 420: {
1.13 millert 421: int n;
1.1 tholo 422: double dtemp;
1.34 millert 423: const char *p;
1.1 tholo 424:
425: if ((vp->tval & (NUM | STR)) == 0)
426: funnyvar(vp, "read value of");
1.24 millert 427: if (isfld(vp) && ! donefld)
1.1 tholo 428: fldbld();
1.24 millert 429: else if (isrec(vp) && ! donerec)
1.1 tholo 430: recbld();
1.19 millert 431:
432: /*
433: * ADR: This is complicated and more fragile than is desirable.
434: * Retrieving a string value for a number associates the string
435: * value with the scalar. Previously, the string value was
436: * sticky, meaning if converted via OFMT that became the value
437: * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
438: * changed after a string value was retrieved, the original value
439: * was maintained and used. Also not per POSIX.
440: *
441: * We work around this design by adding two additional flags,
442: * CONVC and CONVO, indicating how the string value was
443: * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
444: * of the pointer to the xFMT format string used for the
445: * conversion. This pointer is only read, **never** dereferenced.
446: * The next time we do a conversion, if it's coming from the same
447: * xFMT as last time, and the pointer value is different, we
448: * know that the xFMT format string changed, and we need to
449: * redo the conversion. If it's the same, we don't have to.
450: *
451: * There are also several cases where we don't do a conversion,
452: * such as for a field (see the checks below).
453: */
454:
455: /* Don't duplicate the code for actually updating the value */
456: #define update_str_val(vp) \
457: { \
458: if (freeable(vp)) \
459: xfree(vp->sval); \
1.33 millert 460: if ((p = get_inf_nan(vp->fval)) != NULL) \
461: n = (vp->sval = strdup(p)) ? 0 : -1; \
462: else if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \
1.19 millert 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: {
569: int c, n;
1.23 millert 570: const uschar *s = (const uschar *) is;
1.7 millert 571: uschar *buf, *bp;
1.1 tholo 572:
1.32 millert 573: if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
1.6 millert 574: FATAL( "out of space in qstring(%s)", s);
1.3 kstailey 575: for (bp = buf; (c = *s) != delim; s++) {
1.1 tholo 576: if (c == '\n')
1.36 ! millert 577: SYNTAX( "newline in string %.20s...", is );
1.1 tholo 578: else if (c != '\\')
1.3 kstailey 579: *bp++ = c;
1.6 millert 580: else { /* \something */
581: c = *++s;
582: if (c == 0) { /* \ at end */
583: *bp++ = '\\';
584: break; /* for loop */
1.22 millert 585: }
1.6 millert 586: switch (c) {
1.3 kstailey 587: case '\\': *bp++ = '\\'; break;
588: case 'n': *bp++ = '\n'; break;
589: case 't': *bp++ = '\t'; break;
590: case 'b': *bp++ = '\b'; break;
591: case 'f': *bp++ = '\f'; break;
592: case 'r': *bp++ = '\r'; break;
1.22 millert 593: case 'v': *bp++ = '\v'; break;
594: case 'a': *bp++ = '\a'; break;
1.1 tholo 595: default:
596: if (!isdigit(c)) {
1.3 kstailey 597: *bp++ = c;
1.1 tholo 598: break;
599: }
600: n = c - '0';
601: if (isdigit(s[1])) {
602: n = 8 * n + *++s - '0';
603: if (isdigit(s[1]))
604: n = 8 * n + *++s - '0';
605: }
1.3 kstailey 606: *bp++ = n;
1.1 tholo 607: break;
608: }
1.3 kstailey 609: }
1.1 tholo 610: }
1.3 kstailey 611: *bp++ = 0;
1.7 millert 612: return (char *) buf;
1.19 millert 613: }
614:
615: const char *flags2str(int flags)
616: {
617: static const struct ftab {
618: const char *name;
619: int value;
620: } flagtab[] = {
621: { "NUM", NUM },
622: { "STR", STR },
623: { "DONTFREE", DONTFREE },
624: { "CON", CON },
625: { "ARR", ARR },
626: { "FCN", FCN },
627: { "FLD", FLD },
628: { "REC", REC },
629: { "CONVC", CONVC },
630: { "CONVO", CONVO },
631: { NULL, 0 }
632: };
633: static char buf[100];
634: int i, len;
635: char *cp = buf;
636:
637: for (i = 0; flagtab[i].name != NULL; i++) {
638: if ((flags & flagtab[i].value) != 0) {
639: len = snprintf(cp, sizeof(buf) - (cp - buf),
640: "%s%s", cp > buf ? "|" : "", flagtab[i].name);
641: if (len < 0 || len >= sizeof(buf) - (cp - buf))
642: FATAL("out of space in flags2str");
643: cp += len;
644: }
645: }
646:
647: return buf;
1.1 tholo 648: }