Annotation of src/usr.bin/awk/tran.c, Revision 1.33
1.33 ! millert 1: /* $OpenBSD: tran.c,v 1.32 2020/12/09 20:00:11 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.33 ! millert 422: static char *get_inf_nan(double d)
! 423: {
! 424: if (isinf(d)) {
! 425: return (d < 0 ? "-inf" : "+inf");
! 426: } else if (isnan(d)) {
! 427: return (signbit(d) != 0 ? "-nan" : "+nan");
! 428: } else
! 429: return NULL;
! 430: }
! 431:
1.11 millert 432: static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
1.1 tholo 433: {
1.13 millert 434: int n;
1.1 tholo 435: double dtemp;
1.33 ! millert 436: char *p;
1.1 tholo 437:
438: if ((vp->tval & (NUM | STR)) == 0)
439: funnyvar(vp, "read value of");
1.24 millert 440: if (isfld(vp) && ! donefld)
1.1 tholo 441: fldbld();
1.24 millert 442: else if (isrec(vp) && ! donerec)
1.1 tholo 443: recbld();
1.19 millert 444:
445: /*
446: * ADR: This is complicated and more fragile than is desirable.
447: * Retrieving a string value for a number associates the string
448: * value with the scalar. Previously, the string value was
449: * sticky, meaning if converted via OFMT that became the value
450: * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
451: * changed after a string value was retrieved, the original value
452: * was maintained and used. Also not per POSIX.
453: *
454: * We work around this design by adding two additional flags,
455: * CONVC and CONVO, indicating how the string value was
456: * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
457: * of the pointer to the xFMT format string used for the
458: * conversion. This pointer is only read, **never** dereferenced.
459: * The next time we do a conversion, if it's coming from the same
460: * xFMT as last time, and the pointer value is different, we
461: * know that the xFMT format string changed, and we need to
462: * redo the conversion. If it's the same, we don't have to.
463: *
464: * There are also several cases where we don't do a conversion,
465: * such as for a field (see the checks below).
466: */
467:
468: /* Don't duplicate the code for actually updating the value */
469: #define update_str_val(vp) \
470: { \
471: if (freeable(vp)) \
472: xfree(vp->sval); \
1.33 ! millert 473: if ((p = get_inf_nan(vp->fval)) != NULL) \
! 474: n = (vp->sval = strdup(p)) ? 0 : -1; \
! 475: else if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \
1.19 millert 476: n = asprintf(&vp->sval, "%.30g", vp->fval); \
477: else \
478: n = asprintf(&vp->sval, *fmt, vp->fval); \
479: if (n == -1) \
480: FATAL("out of space in get_str_val"); \
481: vp->tval &= ~DONTFREE; \
482: vp->tval |= STR; \
483: }
484:
1.3 kstailey 485: if (isstr(vp) == 0) {
1.19 millert 486: update_str_val(vp);
487: if (fmt == OFMT) {
488: vp->tval &= ~CONVC;
489: vp->tval |= CONVO;
490: } else {
491: /* CONVFMT */
492: vp->tval &= ~CONVO;
493: vp->tval |= CONVC;
494: }
495: vp->fmt = *fmt;
496: } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
497: goto done;
498: } else if (isstr(vp)) {
499: if (fmt == OFMT) {
500: if ((vp->tval & CONVC) != 0
501: || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
502: update_str_val(vp);
503: vp->tval &= ~CONVC;
504: vp->tval |= CONVO;
505: vp->fmt = *fmt;
506: }
507: } else {
508: /* CONVFMT */
509: if ((vp->tval & CONVO) != 0
510: || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
511: update_str_val(vp);
512: vp->tval &= ~CONVO;
513: vp->tval |= CONVC;
514: vp->fmt = *fmt;
515: }
516: }
1.1 tholo 517: }
1.19 millert 518: done:
1.29 millert 519: DPRINTF("getsval %p: %s = \"%s (%p)\", t=%o\n",
1.31 millert 520: (void*)vp, NN(vp->nval), vp->sval, (void*)vp->sval, vp->tval);
1.1 tholo 521: return(vp->sval);
522: }
523:
1.8 millert 524: char *getsval(Cell *vp) /* get string val of a Cell */
525: {
526: return get_str_val(vp, CONVFMT);
527: }
528:
529: char *getpssval(Cell *vp) /* get string val of a Cell for print */
530: {
531: return get_str_val(vp, OFMT);
532: }
533:
534:
535: char *tostring(const char *s) /* make a copy of string s */
1.1 tholo 536: {
1.23 millert 537: char *p = strdup(s);
1.12 millert 538: if (p == NULL)
539: FATAL("out of space in tostring on %s", s);
1.27 millert 540: return(p);
541: }
542:
543: char *tostringN(const char *s, size_t n) /* make a copy of string s */
544: {
545: char *p;
546:
1.32 millert 547: p = (char *) malloc(n);
1.27 millert 548: if (p == NULL)
1.28 millert 549: FATAL("out of space in tostringN %zu", n);
550: if (strlcpy(p, s, n) >= n)
551: FATAL("out of space in tostringN on %s", s);
1.23 millert 552: return(p);
1.1 tholo 553: }
554:
1.22 millert 555: Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
556: {
557: Cell *c;
558: char *p;
559: char *sa = getsval(a);
560: char *sb = getsval(b);
561: size_t l = strlen(sa) + strlen(sb) + 1;
1.32 millert 562: p = (char *) malloc(l);
1.22 millert 563: if (p == NULL)
564: FATAL("out of space concatenating %s and %s", sa, sb);
565: snprintf(p, l, "%s%s", sa, sb);
1.26 millert 566:
567: l++; // add room for ' '
1.32 millert 568: char *newbuf = (char *) malloc(l);
1.25 millert 569: if (newbuf == NULL)
570: FATAL("out of space concatenating %s and %s", sa, sb);
571: // See string() in lex.c; a string "xx" is stored in the symbol
572: // table as "xx ".
1.26 millert 573: snprintf(newbuf, l, "%s ", p);
1.25 millert 574: c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab);
1.22 millert 575: free(p);
1.25 millert 576: free(newbuf);
1.22 millert 577: return c;
578: }
579:
1.8 millert 580: char *qstring(const char *is, int delim) /* collect string up to next delim */
1.1 tholo 581: {
1.8 millert 582: const char *os = is;
1.1 tholo 583: int c, n;
1.23 millert 584: const uschar *s = (const uschar *) is;
1.7 millert 585: uschar *buf, *bp;
1.1 tholo 586:
1.32 millert 587: if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
1.6 millert 588: FATAL( "out of space in qstring(%s)", s);
1.3 kstailey 589: for (bp = buf; (c = *s) != delim; s++) {
1.1 tholo 590: if (c == '\n')
1.6 millert 591: SYNTAX( "newline in string %.20s...", os );
1.1 tholo 592: else if (c != '\\')
1.3 kstailey 593: *bp++ = c;
1.6 millert 594: else { /* \something */
595: c = *++s;
596: if (c == 0) { /* \ at end */
597: *bp++ = '\\';
598: break; /* for loop */
1.22 millert 599: }
1.6 millert 600: switch (c) {
1.3 kstailey 601: case '\\': *bp++ = '\\'; break;
602: case 'n': *bp++ = '\n'; break;
603: case 't': *bp++ = '\t'; break;
604: case 'b': *bp++ = '\b'; break;
605: case 'f': *bp++ = '\f'; break;
606: case 'r': *bp++ = '\r'; break;
1.22 millert 607: case 'v': *bp++ = '\v'; break;
608: case 'a': *bp++ = '\a'; break;
1.1 tholo 609: default:
610: if (!isdigit(c)) {
1.3 kstailey 611: *bp++ = c;
1.1 tholo 612: break;
613: }
614: n = c - '0';
615: if (isdigit(s[1])) {
616: n = 8 * n + *++s - '0';
617: if (isdigit(s[1]))
618: n = 8 * n + *++s - '0';
619: }
1.3 kstailey 620: *bp++ = n;
1.1 tholo 621: break;
622: }
1.3 kstailey 623: }
1.1 tholo 624: }
1.3 kstailey 625: *bp++ = 0;
1.7 millert 626: return (char *) buf;
1.19 millert 627: }
628:
629: const char *flags2str(int flags)
630: {
631: static const struct ftab {
632: const char *name;
633: int value;
634: } flagtab[] = {
635: { "NUM", NUM },
636: { "STR", STR },
637: { "DONTFREE", DONTFREE },
638: { "CON", CON },
639: { "ARR", ARR },
640: { "FCN", FCN },
641: { "FLD", FLD },
642: { "REC", REC },
643: { "CONVC", CONVC },
644: { "CONVO", CONVO },
645: { NULL, 0 }
646: };
647: static char buf[100];
648: int i, len;
649: char *cp = buf;
650:
651: for (i = 0; flagtab[i].name != NULL; i++) {
652: if ((flags & flagtab[i].value) != 0) {
653: len = snprintf(cp, sizeof(buf) - (cp - buf),
654: "%s%s", cp > buf ? "|" : "", flagtab[i].name);
655: if (len < 0 || len >= sizeof(buf) - (cp - buf))
656: FATAL("out of space in flags2str");
657: cp += len;
658: }
659: }
660:
661: return buf;
1.1 tholo 662: }