Annotation of src/usr.bin/awk/tran.c, Revision 1.38
1.38 ! millert 1: /* $OpenBSD: tran.c,v 1.37 2023/09/17 14:49:44 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.38 ! millert 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.37 millert 312: DPRINTF("setfval: 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.37 millert 352: if (CSV && (vp == rsloc))
353: WARNING("danger: don't set RS when --csv is in effect");
354: if (CSV && (vp == fsloc))
355: WARNING("danger: don't set FS when --csv is in effect");
1.3 kstailey 356: if (isfld(vp)) {
1.24 millert 357: donerec = false; /* mark $0 invalid */
1.3 kstailey 358: fldno = atoi(vp->nval);
359: if (fldno > *NF)
360: newfld(fldno);
1.31 millert 361: DPRINTF("setting field %d to %s (%p)\n", fldno, s, (const void*)s);
1.3 kstailey 362: } else if (isrec(vp)) {
1.24 millert 363: donefld = false; /* mark $1... invalid */
364: donerec = true;
1.22 millert 365: savefs();
1.21 millert 366: } else if (vp == ofsloc) {
1.24 millert 367: if (!donerec)
1.19 millert 368: recbld();
1.1 tholo 369: }
1.19 millert 370: t = s ? tostring(s) : tostring(""); /* in case it's self-assign */
1.14 jmc 371: if (freeable(vp))
372: xfree(vp->sval);
1.35 millert 373: vp->tval &= ~(NUM|DONTFREE|CONVC|CONVO);
1.1 tholo 374: vp->tval |= STR;
1.19 millert 375: vp->fmt = NULL;
1.29 millert 376: DPRINTF("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
1.31 millert 377: (void*)vp, NN(vp->nval), t, (void*)t, vp->tval, donerec, donefld);
1.19 millert 378: vp->sval = t;
379: if (&vp->fval == NF) {
1.24 millert 380: donerec = false; /* mark $0 invalid */
1.19 millert 381: f = getfval(vp);
382: setlastfld(f);
1.37 millert 383: DPRINTF("setsval: setting NF to %g\n", f);
1.19 millert 384: }
385:
386: return(vp->sval);
1.1 tholo 387: }
388:
389: Awkfloat getfval(Cell *vp) /* get float val of a Cell */
390: {
391: if ((vp->tval & (NUM | STR)) == 0)
392: funnyvar(vp, "read value of");
1.24 millert 393: if (isfld(vp) && !donefld)
1.1 tholo 394: fldbld();
1.24 millert 395: else if (isrec(vp) && !donerec)
1.1 tholo 396: recbld();
397: if (!isnum(vp)) { /* not a number */
1.32 millert 398: double fval;
399: bool no_trailing;
400:
401: if (is_valid_number(vp->sval, true, & no_trailing, & fval)) {
402: vp->fval = fval;
403: if (no_trailing && !(vp->tval&CON))
404: vp->tval |= NUM; /* make NUM only sparingly */
405: } else
406: vp->fval = 0.0;
1.1 tholo 407: }
1.29 millert 408: DPRINTF("getfval %p: %s = %g, t=%o\n",
409: (void*)vp, NN(vp->nval), vp->fval, vp->tval);
1.1 tholo 410: return(vp->fval);
411: }
412:
1.34 millert 413: static const char *get_inf_nan(double d)
1.33 millert 414: {
415: if (isinf(d)) {
416: return (d < 0 ? "-inf" : "+inf");
417: } else if (isnan(d)) {
418: return (signbit(d) != 0 ? "-nan" : "+nan");
419: } else
420: return NULL;
421: }
422:
1.11 millert 423: static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
1.1 tholo 424: {
1.13 millert 425: int n;
1.1 tholo 426: double dtemp;
1.34 millert 427: const char *p;
1.1 tholo 428:
429: if ((vp->tval & (NUM | STR)) == 0)
430: funnyvar(vp, "read value of");
1.24 millert 431: if (isfld(vp) && ! donefld)
1.1 tholo 432: fldbld();
1.24 millert 433: else if (isrec(vp) && ! donerec)
1.1 tholo 434: recbld();
1.19 millert 435:
436: /*
437: * ADR: This is complicated and more fragile than is desirable.
438: * Retrieving a string value for a number associates the string
439: * value with the scalar. Previously, the string value was
440: * sticky, meaning if converted via OFMT that became the value
441: * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
442: * changed after a string value was retrieved, the original value
443: * was maintained and used. Also not per POSIX.
444: *
445: * We work around this design by adding two additional flags,
446: * CONVC and CONVO, indicating how the string value was
447: * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
448: * of the pointer to the xFMT format string used for the
449: * conversion. This pointer is only read, **never** dereferenced.
450: * The next time we do a conversion, if it's coming from the same
451: * xFMT as last time, and the pointer value is different, we
452: * know that the xFMT format string changed, and we need to
453: * redo the conversion. If it's the same, we don't have to.
454: *
455: * There are also several cases where we don't do a conversion,
456: * such as for a field (see the checks below).
457: */
458:
459: /* Don't duplicate the code for actually updating the value */
460: #define update_str_val(vp) \
461: { \
462: if (freeable(vp)) \
463: xfree(vp->sval); \
1.33 millert 464: if ((p = get_inf_nan(vp->fval)) != NULL) \
465: n = (vp->sval = strdup(p)) ? 0 : -1; \
466: else if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \
1.19 millert 467: n = asprintf(&vp->sval, "%.30g", vp->fval); \
468: else \
469: n = asprintf(&vp->sval, *fmt, vp->fval); \
470: if (n == -1) \
471: FATAL("out of space in get_str_val"); \
472: vp->tval &= ~DONTFREE; \
473: vp->tval |= STR; \
474: }
475:
1.3 kstailey 476: if (isstr(vp) == 0) {
1.19 millert 477: update_str_val(vp);
478: if (fmt == OFMT) {
479: vp->tval &= ~CONVC;
480: vp->tval |= CONVO;
481: } else {
482: /* CONVFMT */
483: vp->tval &= ~CONVO;
484: vp->tval |= CONVC;
485: }
486: vp->fmt = *fmt;
487: } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
488: goto done;
489: } else if (isstr(vp)) {
490: if (fmt == OFMT) {
491: if ((vp->tval & CONVC) != 0
492: || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
493: update_str_val(vp);
494: vp->tval &= ~CONVC;
495: vp->tval |= CONVO;
496: vp->fmt = *fmt;
497: }
498: } else {
499: /* CONVFMT */
500: if ((vp->tval & CONVO) != 0
501: || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
502: update_str_val(vp);
503: vp->tval &= ~CONVO;
504: vp->tval |= CONVC;
505: vp->fmt = *fmt;
506: }
507: }
1.1 tholo 508: }
1.19 millert 509: done:
1.29 millert 510: DPRINTF("getsval %p: %s = \"%s (%p)\", t=%o\n",
1.31 millert 511: (void*)vp, NN(vp->nval), vp->sval, (void*)vp->sval, vp->tval);
1.1 tholo 512: return(vp->sval);
513: }
514:
1.8 millert 515: char *getsval(Cell *vp) /* get string val of a Cell */
516: {
517: return get_str_val(vp, CONVFMT);
518: }
519:
520: char *getpssval(Cell *vp) /* get string val of a Cell for print */
521: {
522: return get_str_val(vp, OFMT);
523: }
524:
525:
526: char *tostring(const char *s) /* make a copy of string s */
1.1 tholo 527: {
1.23 millert 528: char *p = strdup(s);
1.12 millert 529: if (p == NULL)
530: FATAL("out of space in tostring on %s", s);
1.27 millert 531: return(p);
532: }
533:
534: char *tostringN(const char *s, size_t n) /* make a copy of string s */
535: {
536: char *p;
537:
1.32 millert 538: p = (char *) malloc(n);
1.27 millert 539: if (p == NULL)
1.28 millert 540: FATAL("out of space in tostringN %zu", n);
541: if (strlcpy(p, s, n) >= n)
542: FATAL("out of space in tostringN on %s", s);
1.23 millert 543: return(p);
1.1 tholo 544: }
545:
1.22 millert 546: Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
547: {
548: Cell *c;
549: char *p;
550: char *sa = getsval(a);
551: char *sb = getsval(b);
552: size_t l = strlen(sa) + strlen(sb) + 1;
1.32 millert 553: p = (char *) malloc(l);
1.22 millert 554: if (p == NULL)
555: FATAL("out of space concatenating %s and %s", sa, sb);
556: snprintf(p, l, "%s%s", sa, sb);
1.26 millert 557:
558: l++; // add room for ' '
1.32 millert 559: char *newbuf = (char *) malloc(l);
1.25 millert 560: if (newbuf == NULL)
561: FATAL("out of space concatenating %s and %s", sa, sb);
562: // See string() in lex.c; a string "xx" is stored in the symbol
563: // table as "xx ".
1.26 millert 564: snprintf(newbuf, l, "%s ", p);
1.25 millert 565: c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab);
1.22 millert 566: free(p);
1.25 millert 567: free(newbuf);
1.22 millert 568: return c;
569: }
570:
1.8 millert 571: char *qstring(const char *is, int delim) /* collect string up to next delim */
1.1 tholo 572: {
573: int c, n;
1.23 millert 574: const uschar *s = (const uschar *) is;
1.7 millert 575: uschar *buf, *bp;
1.1 tholo 576:
1.32 millert 577: if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
1.6 millert 578: FATAL( "out of space in qstring(%s)", s);
1.3 kstailey 579: for (bp = buf; (c = *s) != delim; s++) {
1.1 tholo 580: if (c == '\n')
1.36 millert 581: SYNTAX( "newline in string %.20s...", is );
1.1 tholo 582: else if (c != '\\')
1.3 kstailey 583: *bp++ = c;
1.6 millert 584: else { /* \something */
585: c = *++s;
586: if (c == 0) { /* \ at end */
587: *bp++ = '\\';
588: break; /* for loop */
1.22 millert 589: }
1.6 millert 590: switch (c) {
1.3 kstailey 591: case '\\': *bp++ = '\\'; break;
592: case 'n': *bp++ = '\n'; break;
593: case 't': *bp++ = '\t'; break;
594: case 'b': *bp++ = '\b'; break;
595: case 'f': *bp++ = '\f'; break;
596: case 'r': *bp++ = '\r'; break;
1.22 millert 597: case 'v': *bp++ = '\v'; break;
598: case 'a': *bp++ = '\a'; break;
1.1 tholo 599: default:
600: if (!isdigit(c)) {
1.3 kstailey 601: *bp++ = c;
1.1 tholo 602: break;
603: }
604: n = c - '0';
605: if (isdigit(s[1])) {
606: n = 8 * n + *++s - '0';
607: if (isdigit(s[1]))
608: n = 8 * n + *++s - '0';
609: }
1.3 kstailey 610: *bp++ = n;
1.1 tholo 611: break;
612: }
1.3 kstailey 613: }
1.1 tholo 614: }
1.3 kstailey 615: *bp++ = 0;
1.7 millert 616: return (char *) buf;
1.19 millert 617: }
618:
619: const char *flags2str(int flags)
620: {
621: static const struct ftab {
622: const char *name;
623: int value;
624: } flagtab[] = {
625: { "NUM", NUM },
626: { "STR", STR },
627: { "DONTFREE", DONTFREE },
628: { "CON", CON },
629: { "ARR", ARR },
630: { "FCN", FCN },
631: { "FLD", FLD },
632: { "REC", REC },
633: { "CONVC", CONVC },
634: { "CONVO", CONVO },
635: { NULL, 0 }
636: };
637: static char buf[100];
638: int i, len;
639: char *cp = buf;
640:
641: for (i = 0; flagtab[i].name != NULL; i++) {
642: if ((flags & flagtab[i].value) != 0) {
643: len = snprintf(cp, sizeof(buf) - (cp - buf),
644: "%s%s", cp > buf ? "|" : "", flagtab[i].name);
645: if (len < 0 || len >= sizeof(buf) - (cp - buf))
646: FATAL("out of space in flags2str");
647: cp += len;
648: }
649: }
650:
651: return buf;
1.1 tholo 652: }