blob: 4efaa21a1922bea7c29e9afed5fc03ef6e0d7c65 [file] [log] [blame]
Brian Kernighan87b94932012-12-22 10:35:39 -05001/****************************************************************
2Copyright (C) Lucent Technologies 1997
3All Rights Reserved
4
5Permission to use, copy, modify, and distribute this software and
6its documentation for any purpose and without fee is hereby
7granted, provided that the above copyright notice appear in all
8copies and that both that the copyright notice and this
9permission notice and warranty disclaimer appear in supporting
10documentation, and that the name Lucent Technologies or any of
11its entities not be used in advertising or publicity pertaining
12to distribution of the software without specific, written prior
13permission.
14
15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22THIS SOFTWARE.
23****************************************************************/
24
25#define DEBUG
26#include <stdio.h>
27#include <math.h>
28#include <ctype.h>
29#include <string.h>
30#include <stdlib.h>
31#include "awk.h"
32#include "ytab.h"
33
34#define FULLTAB 2 /* rehash when table gets this x full */
35#define GROWTAB 4 /* grow table by this factor */
36
37Array *symtab; /* main symbol table */
38
39char **FS; /* initial field sep */
40char **RS; /* initial record sep */
41char **OFS; /* output field sep */
42char **ORS; /* output record sep */
43char **OFMT; /* output format for numbers */
44char **CONVFMT; /* format for conversions in getsval */
45Awkfloat *NF; /* number of fields in current record */
46Awkfloat *NR; /* number of current record */
47Awkfloat *FNR; /* number of current record in current file */
48char **FILENAME; /* current filename argument */
49Awkfloat *ARGC; /* number of arguments from command line */
50char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
51Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
52Awkfloat *RLENGTH; /* length of same */
53
54Cell *fsloc; /* FS */
55Cell *nrloc; /* NR */
56Cell *nfloc; /* NF */
57Cell *fnrloc; /* FNR */
Cody Peter Mello52566c02018-09-18 15:45:55 -070058Cell *ofsloc; /* OFS */
59Cell *orsloc; /* ORS */
60Cell *rsloc; /* RS */
Brian Kernighan87b94932012-12-22 10:35:39 -050061Array *ARGVtab; /* symbol table containing ARGV[...] */
62Array *ENVtab; /* symbol table containing ENVIRON[...] */
63Cell *rstartloc; /* RSTART */
64Cell *rlengthloc; /* RLENGTH */
Cody Peter Mello97a4b7e2018-09-17 11:59:04 -070065Cell *subseploc; /* SUBSEP */
Brian Kernighan87b94932012-12-22 10:35:39 -050066Cell *symtabloc; /* SYMTAB */
67
68Cell *nullloc; /* a guaranteed empty cell */
69Node *nullnode; /* zero&null, converted into a node for comparisons */
70Cell *literal0;
71
72extern Cell **fldtab;
73
Arnold D. Robbins32093f52018-08-22 20:40:26 +030074static void
75setfree(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
Brian Kernighan87b94932012-12-22 10:35:39 -050086void syminit(void) /* initialize symbol table with builtin vars */
87{
88 literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
89 /* this is used for if(x)... tests: */
90 nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
91 nullnode = celltonode(nullloc, CCON);
92
93 fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
94 FS = &fsloc->sval;
Cody Peter Mello52566c02018-09-18 15:45:55 -070095 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;
Brian Kernighan87b94932012-12-22 10:35:39 -0500101 OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
102 CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
103 FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
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;
Cody Peter Mello97a4b7e2018-09-17 11:59:04 -0700110 subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab);
111 SUBSEP = &subseploc->sval;
Brian Kernighan87b94932012-12-22 10:35:39 -0500112 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);
Arnold D. Robbins3358f3f2020-01-01 22:42:20 +0200117 free(symtabloc->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -0500118 symtabloc->sval = (char *) symtab;
119}
120
121void arginit(int ac, char **av) /* set up ARGV and ARGC */
122{
123 Cell *cp;
124 int i;
125 char temp[50];
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 */
Arnold D. Robbins3358f3f2020-01-01 22:42:20 +0200130 free(cp->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -0500131 cp->sval = (char *) ARGVtab;
132 for (i = 0; i < ac; i++) {
133 sprintf(temp, "%d", i);
134 if (is_number(*av))
135 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
136 else
137 setsymtab(temp, *av, 0.0, STR, ARGVtab);
138 av++;
139 }
140}
141
142void 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);
Arnold D. Robbins3358f3f2020-01-01 22:42:20 +0200149 free(cp->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -0500150 cp->sval = (char *) ENVtab;
151 for ( ; *envp; envp++) {
152 if ((p = strchr(*envp, '=')) == NULL)
153 continue;
154 if( p == *envp ) /* no left hand side name in env string */
155 continue;
156 *p++ = 0; /* split into two strings at = */
157 if (is_number(p))
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
165Array *makesymtab(int n) /* make a new symbol table */
166{
167 Array *ap;
168 Cell **tp;
169
zoulasc65892082019-10-24 09:40:15 -0400170 ap = malloc(sizeof(*ap));
171 tp = calloc(n, sizeof(*tp));
Brian Kernighan87b94932012-12-22 10:35:39 -0500172 if (ap == NULL || tp == NULL)
173 FATAL("out of space in makesymtab");
174 ap->nelem = 0;
175 ap->size = n;
176 ap->tab = tp;
177 return(ap);
178}
179
180void 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 */
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600197 free(cp);
Brian Kernighan87b94932012-12-22 10:35:39 -0500198 tp->nelem--;
199 }
pfg52421942016-06-03 21:23:11 +0000200 tp->tab[i] = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500201 }
202 if (tp->nelem != 0)
203 WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
204 free(tp->tab);
205 free(tp);
206}
207
208void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */
209{
210 Array *tp;
211 Cell *p, *prev = NULL;
212 int h;
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600213
Brian Kernighan87b94932012-12-22 10:35:39 -0500214 tp = (Array *) ap->sval;
215 h = hash(s, tp->size);
216 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
217 if (strcmp(s, p->nval) == 0) {
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);
225 free(p);
226 tp->nelem--;
227 return;
228 }
229}
230
231Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
232{
233 int h;
234 Cell *p;
235
236 if (n != NULL && (p = lookup(n, tp)) != NULL) {
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) );
239 return(p);
240 }
zoulasc65892082019-10-24 09:40:15 -0400241 p = malloc(sizeof(*p));
Brian Kernighan87b94932012-12-22 10:35:39 -0500242 if (p == NULL)
243 FATAL("out of space for symbol table at %s", n);
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;
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) );
258 return(p);
259}
260
261int hash(const char *s, int n) /* form hash value for string s */
262{
263 unsigned hashval;
264
265 for (hashval = 0; *s != '\0'; s++)
266 hashval = (*s + 31 * hashval);
267 return hashval % n;
268}
269
270void 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;
zoulasc65892082019-10-24 09:40:15 -0400276 np = calloc(nsz, sizeof(*np));
Brian Kernighan87b94932012-12-22 10:35:39 -0500277 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 }
287 free(tp->tab);
288 tp->tab = np;
289 tp->size = nsz;
290}
291
292Cell *lookup(const char *s, Array *tp) /* look for s in tp */
293{
294 Cell *p;
295 int h;
296
297 h = hash(s, tp->size);
298 for (p = tp->tab[h]; p != NULL; p = p->cnext)
299 if (strcmp(s, p->nval) == 0)
300 return(p); /* found it */
301 return(NULL); /* not found */
302}
303
304Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
305{
306 int fldno;
307
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300308 f += 0.0; /* normalise negative zero to positive zero */
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600309 if ((vp->tval & (NUM | STR)) == 0)
Brian Kernighan87b94932012-12-22 10:35:39 -0500310 funnyvar(vp, "assign to");
311 if (isfld(vp)) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200312 donerec = false; /* mark $0 invalid */
Brian Kernighan87b94932012-12-22 10:35:39 -0500313 fldno = atoi(vp->nval);
314 if (fldno > *NF)
315 newfld(fldno);
316 dprintf( ("setting field %d to %g\n", fldno, f) );
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300317 } else if (&vp->fval == NF) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200318 donerec = false; /* mark $0 invalid */
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300319 setlastfld(f);
320 dprintf( ("setting NF to %g\n", f) );
Brian Kernighan87b94932012-12-22 10:35:39 -0500321 } else if (isrec(vp)) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200322 donefld = false; /* mark $1... invalid */
323 donerec = true;
Cody Peter Mellob4636802018-10-19 15:07:53 -0700324 savefs();
Cody Peter Mello52566c02018-09-18 15:45:55 -0700325 } else if (vp == ofsloc) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200326 if (!donerec)
Cody Peter Mello52566c02018-09-18 15:45:55 -0700327 recbld();
Brian Kernighan87b94932012-12-22 10:35:39 -0500328 }
329 if (freeable(vp))
330 xfree(vp->sval); /* free any previous string */
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300331 vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */
332 vp->fmt = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500333 vp->tval |= NUM; /* mark number ok */
334 if (f == -0) /* who would have thought this possible? */
335 f = 0;
336 dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
337 return vp->fval = f;
338}
339
340void funnyvar(Cell *vp, const char *rw)
341{
342 if (isarr(vp))
343 FATAL("can't %s %s; it's an array name.", rw, vp->nval);
344 if (vp->tval & FCN)
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",
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200347 (void *)vp, vp->nval, vp->sval, vp->fval, vp->tval);
Brian Kernighan87b94932012-12-22 10:35:39 -0500348}
349
350char *setsval(Cell *vp, const char *s) /* set string val of a Cell */
351{
352 char *t;
353 int fldno;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300354 Awkfloat f;
Brian Kernighan87b94932012-12-22 10:35:39 -0500355
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600356 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
Brian Kernighan87b94932012-12-22 10:35:39 -0500357 (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
358 if ((vp->tval & (NUM | STR)) == 0)
359 funnyvar(vp, "assign to");
360 if (isfld(vp)) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200361 donerec = false; /* mark $0 invalid */
Brian Kernighan87b94932012-12-22 10:35:39 -0500362 fldno = atoi(vp->nval);
363 if (fldno > *NF)
364 newfld(fldno);
zoulasc65892082019-10-24 09:40:15 -0400365 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
Brian Kernighan87b94932012-12-22 10:35:39 -0500366 } else if (isrec(vp)) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200367 donefld = false; /* mark $1... invalid */
368 donerec = true;
Cody Peter Mellob4636802018-10-19 15:07:53 -0700369 savefs();
Cody Peter Mello52566c02018-09-18 15:45:55 -0700370 } else if (vp == ofsloc) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200371 if (!donerec)
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300372 recbld();
Brian Kernighan87b94932012-12-22 10:35:39 -0500373 }
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300374 t = s ? tostring(s) : tostring(""); /* in case it's self-assign */
Brian Kernighan87b94932012-12-22 10:35:39 -0500375 if (freeable(vp))
376 xfree(vp->sval);
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300377 vp->tval &= ~(NUM|CONVC|CONVO);
Brian Kernighan87b94932012-12-22 10:35:39 -0500378 vp->tval |= STR;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300379 vp->fmt = NULL;
380 setfree(vp);
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600381 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
zoulasc65892082019-10-24 09:40:15 -0400382 (void*)vp, NN(vp->nval), t, t, vp->tval, donerec, donefld) );
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300383 vp->sval = t;
384 if (&vp->fval == NF) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200385 donerec = false; /* mark $0 invalid */
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300386 f = getfval(vp);
387 setlastfld(f);
388 dprintf( ("setting NF to %g\n", f) );
389 }
390
391 return(vp->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -0500392}
393
394Awkfloat getfval(Cell *vp) /* get float val of a Cell */
395{
396 if ((vp->tval & (NUM | STR)) == 0)
397 funnyvar(vp, "read value of");
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200398 if (isfld(vp) && !donefld)
Brian Kernighan87b94932012-12-22 10:35:39 -0500399 fldbld();
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200400 else if (isrec(vp) && !donerec)
Brian Kernighan87b94932012-12-22 10:35:39 -0500401 recbld();
402 if (!isnum(vp)) { /* not a number */
403 vp->fval = atof(vp->sval); /* best guess */
404 if (is_number(vp->sval) && !(vp->tval&CON))
405 vp->tval |= NUM; /* make NUM only sparingly */
406 }
407 dprintf( ("getfval %p: %s = %g, t=%o\n",
408 (void*)vp, NN(vp->nval), vp->fval, vp->tval) );
409 return(vp->fval);
410}
411
412static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
413{
Cody Peter Melloe059b3b2018-09-14 19:56:34 -0700414 char s[256];
Brian Kernighan87b94932012-12-22 10:35:39 -0500415 double dtemp;
416
417 if ((vp->tval & (NUM | STR)) == 0)
418 funnyvar(vp, "read value of");
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200419 if (isfld(vp) && ! donefld)
Brian Kernighan87b94932012-12-22 10:35:39 -0500420 fldbld();
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200421 else if (isrec(vp) && ! donerec)
Brian Kernighan87b94932012-12-22 10:35:39 -0500422 recbld();
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300423
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 */ \
Cody Peter Melloe059b3b2018-09-14 19:56:34 -0700453 snprintf(s, sizeof (s), "%.30g", vp->fval); \
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300454 else \
Cody Peter Melloe059b3b2018-09-14 19:56:34 -0700455 snprintf(s, sizeof (s), *fmt, vp->fval); \
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300456 vp->sval = tostring(s); \
457 vp->tval &= ~DONTFREE; \
458 vp->tval |= STR; \
Brian Kernighan87b94932012-12-22 10:35:39 -0500459 }
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300460
461 if (isstr(vp) == 0) {
462 update_str_val(vp);
463 if (fmt == OFMT) {
464 vp->tval &= ~CONVC;
465 vp->tval |= CONVO;
466 } else {
467 /* CONVFMT */
468 vp->tval &= ~CONVO;
469 vp->tval |= CONVC;
470 }
471 vp->fmt = *fmt;
472 } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
473 goto done;
474 } else if (isstr(vp)) {
475 if (fmt == OFMT) {
476 if ((vp->tval & CONVC) != 0
477 || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
478 update_str_val(vp);
479 vp->tval &= ~CONVC;
480 vp->tval |= CONVO;
481 vp->fmt = *fmt;
482 }
483 } else {
484 /* CONVFMT */
485 if ((vp->tval & CONVO) != 0
486 || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
487 update_str_val(vp);
488 vp->tval &= ~CONVO;
489 vp->tval |= CONVC;
490 vp->fmt = *fmt;
491 }
492 }
493 }
494done:
Brian Kernighan87b94932012-12-22 10:35:39 -0500495 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
zoulasc65892082019-10-24 09:40:15 -0400496 (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
Brian Kernighan87b94932012-12-22 10:35:39 -0500497 return(vp->sval);
498}
499
500char *getsval(Cell *vp) /* get string val of a Cell */
501{
502 return get_str_val(vp, CONVFMT);
503}
504
505char *getpssval(Cell *vp) /* get string val of a Cell for print */
506{
507 return get_str_val(vp, OFMT);
508}
509
510
511char *tostring(const char *s) /* make a copy of string s */
512{
zoulasc65892082019-10-24 09:40:15 -0400513 char *p = strdup(s);
Brian Kernighan87b94932012-12-22 10:35:39 -0500514 if (p == NULL)
515 FATAL("out of space in tostring on %s", s);
Brian Kernighan87b94932012-12-22 10:35:39 -0500516 return(p);
517}
518
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200519char *tostringN(const char *s, size_t n) /* make a copy of string s */
520{
521 char *p;
522
523 p = malloc(n);
524 if (p == NULL)
525 FATAL("out of space in tostring on %s", s);
526 strcpy(p, s);
527 return(p);
528}
529
Arnold D. Robbinsc95b9602019-07-28 20:09:24 +0300530Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
531{
532 Cell *c;
533 char *p;
534 char *sa = getsval(a);
535 char *sb = getsval(b);
536 size_t l = strlen(sa) + strlen(sb) + 1;
537 p = malloc(l);
538 if (p == NULL)
539 FATAL("out of space concatenating %s and %s", sa, sb);
540 snprintf(p, l, "%s%s", sa, sb);
Arnold D. Robbins944989b2020-01-06 00:01:46 -0700541
542 l++; // add room for ' '
543 char *newbuf = malloc(l);
Arnold D. Robbinsc7eeb572020-01-05 21:18:36 +0200544 if (newbuf == NULL)
545 FATAL("out of space concatenating %s and %s", sa, sb);
546 // See string() in lex.c; a string "xx" is stored in the symbol
547 // table as "xx ".
Arnold D. Robbins944989b2020-01-06 00:01:46 -0700548 snprintf(newbuf, l, "%s ", p);
Arnold D. Robbinsc7eeb572020-01-05 21:18:36 +0200549 c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab);
Arnold D. Robbinsc95b9602019-07-28 20:09:24 +0300550 free(p);
Arnold D. Robbinsc7eeb572020-01-05 21:18:36 +0200551 free(newbuf);
Arnold D. Robbinsc95b9602019-07-28 20:09:24 +0300552 return c;
553}
554
Brian Kernighan87b94932012-12-22 10:35:39 -0500555char *qstring(const char *is, int delim) /* collect string up to next delim */
556{
557 const char *os = is;
558 int c, n;
zoulasc65892082019-10-24 09:40:15 -0400559 const uschar *s = (const uschar *) is;
Brian Kernighan87b94932012-12-22 10:35:39 -0500560 uschar *buf, *bp;
561
zoulasc65892082019-10-24 09:40:15 -0400562 if ((buf = malloc(strlen(is)+3)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500563 FATAL( "out of space in qstring(%s)", s);
564 for (bp = buf; (c = *s) != delim; s++) {
565 if (c == '\n')
566 SYNTAX( "newline in string %.20s...", os );
567 else if (c != '\\')
568 *bp++ = c;
569 else { /* \something */
570 c = *++s;
571 if (c == 0) { /* \ at end */
572 *bp++ = '\\';
573 break; /* for loop */
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600574 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500575 switch (c) {
576 case '\\': *bp++ = '\\'; break;
577 case 'n': *bp++ = '\n'; break;
578 case 't': *bp++ = '\t'; break;
579 case 'b': *bp++ = '\b'; break;
580 case 'f': *bp++ = '\f'; break;
581 case 'r': *bp++ = '\r'; break;
Martijn Dekker5b602ca2019-07-26 10:46:58 +0200582 case 'v': *bp++ = '\v'; break;
583 case 'a': *bp++ = '\a'; break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500584 default:
585 if (!isdigit(c)) {
586 *bp++ = c;
587 break;
588 }
589 n = c - '0';
590 if (isdigit(s[1])) {
591 n = 8 * n + *++s - '0';
592 if (isdigit(s[1]))
593 n = 8 * n + *++s - '0';
594 }
595 *bp++ = n;
596 break;
597 }
598 }
599 }
600 *bp++ = 0;
601 return (char *) buf;
602}
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300603
604const char *flags2str(int flags)
605{
606 static const struct ftab {
607 const char *name;
608 int value;
609 } flagtab[] = {
610 { "NUM", NUM },
611 { "STR", STR },
612 { "DONTFREE", DONTFREE },
613 { "CON", CON },
614 { "ARR", ARR },
615 { "FCN", FCN },
616 { "FLD", FLD },
617 { "REC", REC },
618 { "CONVC", CONVC },
619 { "CONVO", CONVO },
620 { NULL, 0 }
621 };
622 static char buf[100];
623 int i;
624 char *cp = buf;
625
626 for (i = 0; flagtab[i].name != NULL; i++) {
627 if ((flags & flagtab[i].value) != 0) {
628 if (cp > buf)
629 *cp++ = '|';
630 strcpy(cp, flagtab[i].name);
631 cp += strlen(cp);
632 }
633 }
634
635 return buf;
636}