1*c062391aSmillert /* $OpenBSD: tran.c,v 1.19 2020/06/10 21:00:01 millert Exp $ */ 26ab05f83Stholo /**************************************************************** 307edfa4aSkstailey Copyright (C) Lucent Technologies 1997 46ab05f83Stholo All Rights Reserved 56ab05f83Stholo 66ab05f83Stholo Permission to use, copy, modify, and distribute this software and 76ab05f83Stholo its documentation for any purpose and without fee is hereby 86ab05f83Stholo granted, provided that the above copyright notice appear in all 96ab05f83Stholo copies and that both that the copyright notice and this 106ab05f83Stholo permission notice and warranty disclaimer appear in supporting 1107edfa4aSkstailey documentation, and that the name Lucent Technologies or any of 1207edfa4aSkstailey its entities not be used in advertising or publicity pertaining 1307edfa4aSkstailey to distribution of the software without specific, written prior 1407edfa4aSkstailey permission. 156ab05f83Stholo 1607edfa4aSkstailey LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1707edfa4aSkstailey INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 1807edfa4aSkstailey IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 1907edfa4aSkstailey SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 2007edfa4aSkstailey WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 2107edfa4aSkstailey IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2207edfa4aSkstailey ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 2307edfa4aSkstailey THIS SOFTWARE. 246ab05f83Stholo ****************************************************************/ 256ab05f83Stholo 266ab05f83Stholo #define DEBUG 276ab05f83Stholo #include <stdio.h> 286ab05f83Stholo #include <math.h> 296ab05f83Stholo #include <ctype.h> 306ab05f83Stholo #include <string.h> 316ab05f83Stholo #include <stdlib.h> 326ab05f83Stholo #include "awk.h" 3307edfa4aSkstailey #include "ytab.h" 346ab05f83Stholo 356ab05f83Stholo #define FULLTAB 2 /* rehash when table gets this x full */ 366ab05f83Stholo #define GROWTAB 4 /* grow table by this factor */ 376ab05f83Stholo 386ab05f83Stholo Array *symtab; /* main symbol table */ 396ab05f83Stholo 406ab05f83Stholo char **FS; /* initial field sep */ 416ab05f83Stholo char **RS; /* initial record sep */ 426ab05f83Stholo char **OFS; /* output field sep */ 436ab05f83Stholo char **ORS; /* output record sep */ 446ab05f83Stholo char **OFMT; /* output format for numbers */ 456ab05f83Stholo char **CONVFMT; /* format for conversions in getsval */ 466ab05f83Stholo Awkfloat *NF; /* number of fields in current record */ 476ab05f83Stholo Awkfloat *NR; /* number of current record */ 486ab05f83Stholo Awkfloat *FNR; /* number of current record in current file */ 496ab05f83Stholo char **FILENAME; /* current filename argument */ 506ab05f83Stholo Awkfloat *ARGC; /* number of arguments from command line */ 516ab05f83Stholo char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ 526ab05f83Stholo Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ 536ab05f83Stholo Awkfloat *RLENGTH; /* length of same */ 546ab05f83Stholo 5523cb51abSmillert Cell *fsloc; /* FS */ 566ab05f83Stholo Cell *nrloc; /* NR */ 576ab05f83Stholo Cell *nfloc; /* NF */ 586ab05f83Stholo Cell *fnrloc; /* FNR */ 596ab05f83Stholo Array *ARGVtab; /* symbol table containing ARGV[...] */ 606ab05f83Stholo Array *ENVtab; /* symbol table containing ENVIRON[...] */ 616ab05f83Stholo Cell *rstartloc; /* RSTART */ 626ab05f83Stholo Cell *rlengthloc; /* RLENGTH */ 636ab05f83Stholo Cell *symtabloc; /* SYMTAB */ 646ab05f83Stholo 656ab05f83Stholo Cell *nullloc; /* a guaranteed empty cell */ 666ab05f83Stholo Node *nullnode; /* zero&null, converted into a node for comparisons */ 6707edfa4aSkstailey Cell *literal0; 686ab05f83Stholo 6907edfa4aSkstailey extern Cell **fldtab; 706ab05f83Stholo 71*c062391aSmillert static void 72*c062391aSmillert setfree(Cell *vp) 73*c062391aSmillert { 74*c062391aSmillert if (&vp->sval == FS || &vp->sval == RS || 75*c062391aSmillert &vp->sval == OFS || &vp->sval == ORS || 76*c062391aSmillert &vp->sval == OFMT || &vp->sval == CONVFMT || 77*c062391aSmillert &vp->sval == FILENAME || &vp->sval == SUBSEP) 78*c062391aSmillert vp->tval |= DONTFREE; 79*c062391aSmillert else 80*c062391aSmillert vp->tval &= ~DONTFREE; 81*c062391aSmillert } 82*c062391aSmillert 836ab05f83Stholo void syminit(void) /* initialize symbol table with builtin vars */ 846ab05f83Stholo { 8507edfa4aSkstailey literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 866ab05f83Stholo /* this is used for if(x)... tests: */ 876ab05f83Stholo nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 8807edfa4aSkstailey nullnode = celltonode(nullloc, CCON); 896ab05f83Stholo 9023cb51abSmillert fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab); 9123cb51abSmillert FS = &fsloc->sval; 926ab05f83Stholo RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 936ab05f83Stholo OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval; 946ab05f83Stholo ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 956ab05f83Stholo OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 966ab05f83Stholo CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 97b2698ba9Smillert FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 986ab05f83Stholo nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 996ab05f83Stholo NF = &nfloc->fval; 1006ab05f83Stholo nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 1016ab05f83Stholo NR = &nrloc->fval; 1026ab05f83Stholo fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 1036ab05f83Stholo FNR = &fnrloc->fval; 1046ab05f83Stholo SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval; 1056ab05f83Stholo rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 1066ab05f83Stholo RSTART = &rstartloc->fval; 1076ab05f83Stholo rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 1086ab05f83Stholo RLENGTH = &rlengthloc->fval; 1096ab05f83Stholo symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 1106ab05f83Stholo symtabloc->sval = (char *) symtab; 1116ab05f83Stholo } 1126ab05f83Stholo 11307edfa4aSkstailey void arginit(int ac, char **av) /* set up ARGV and ARGC */ 1146ab05f83Stholo { 1156ab05f83Stholo Cell *cp; 1166ab05f83Stholo int i; 11707edfa4aSkstailey char temp[50]; 1186ab05f83Stholo 1196ab05f83Stholo ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 1206ab05f83Stholo cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 1216ab05f83Stholo ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 1226ab05f83Stholo cp->sval = (char *) ARGVtab; 1236ab05f83Stholo for (i = 0; i < ac; i++) { 1249e405e78Sderaadt snprintf(temp, sizeof temp, "%d", i); 125a4fa8700Smillert if (is_number(*av)) 1266ab05f83Stholo setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 1276ab05f83Stholo else 1286ab05f83Stholo setsymtab(temp, *av, 0.0, STR, ARGVtab); 1296ab05f83Stholo av++; 1306ab05f83Stholo } 1316ab05f83Stholo } 1326ab05f83Stholo 1336ab05f83Stholo void envinit(char **envp) /* set up ENVIRON variable */ 1346ab05f83Stholo { 1356ab05f83Stholo Cell *cp; 1366ab05f83Stholo char *p; 1376ab05f83Stholo 1386ab05f83Stholo cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 1396ab05f83Stholo ENVtab = makesymtab(NSYMTAB); 1406ab05f83Stholo cp->sval = (char *) ENVtab; 1416ab05f83Stholo for ( ; *envp; envp++) { 14207edfa4aSkstailey if ((p = strchr(*envp, '=')) == NULL) 1436ab05f83Stholo continue; 144a27f5228Smillert if( p == *envp ) /* no left hand side name in env string */ 145a27f5228Smillert continue; 1466ab05f83Stholo *p++ = 0; /* split into two strings at = */ 147a4fa8700Smillert if (is_number(p)) 1486ab05f83Stholo setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 1496ab05f83Stholo else 1506ab05f83Stholo setsymtab(*envp, p, 0.0, STR, ENVtab); 1516ab05f83Stholo p[-1] = '='; /* restore in case env is passed down to a shell */ 1526ab05f83Stholo } 1536ab05f83Stholo } 1546ab05f83Stholo 1556ab05f83Stholo Array *makesymtab(int n) /* make a new symbol table */ 1566ab05f83Stholo { 1576ab05f83Stholo Array *ap; 1586ab05f83Stholo Cell **tp; 1596ab05f83Stholo 1606ab05f83Stholo ap = (Array *) malloc(sizeof(Array)); 1616ab05f83Stholo tp = (Cell **) calloc(n, sizeof(Cell *)); 1626ab05f83Stholo if (ap == NULL || tp == NULL) 1637b11b857Smillert FATAL("out of space in makesymtab"); 1646ab05f83Stholo ap->nelem = 0; 1656ab05f83Stholo ap->size = n; 1666ab05f83Stholo ap->tab = tp; 1676ab05f83Stholo return(ap); 1686ab05f83Stholo } 1696ab05f83Stholo 1706ab05f83Stholo void freesymtab(Cell *ap) /* free a symbol table */ 1716ab05f83Stholo { 1726ab05f83Stholo Cell *cp, *temp; 1736ab05f83Stholo Array *tp; 1746ab05f83Stholo int i; 1756ab05f83Stholo 1766ab05f83Stholo if (!isarr(ap)) 1776ab05f83Stholo return; 1786ab05f83Stholo tp = (Array *) ap->sval; 1796ab05f83Stholo if (tp == NULL) 1806ab05f83Stholo return; 1816ab05f83Stholo for (i = 0; i < tp->size; i++) { 1826ab05f83Stholo for (cp = tp->tab[i]; cp != NULL; cp = temp) { 1836ab05f83Stholo xfree(cp->nval); 1846ab05f83Stholo if (freeable(cp)) 1856ab05f83Stholo xfree(cp->sval); 1866ab05f83Stholo temp = cp->cnext; /* avoids freeing then using */ 18707edfa4aSkstailey free(cp); 1889a69093aSmillert tp->nelem--; 1896ab05f83Stholo } 1906ab05f83Stholo tp->tab[i] = 0; 1916ab05f83Stholo } 1929a69093aSmillert if (tp->nelem != 0) 1939a69093aSmillert WARNING("can't happen: inconsistent element count freeing %s", ap->nval); 19407edfa4aSkstailey free(tp->tab); 19507edfa4aSkstailey free(tp); 1966ab05f83Stholo } 1976ab05f83Stholo 1989a69093aSmillert void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ 1996ab05f83Stholo { 2006ab05f83Stholo Array *tp; 2016ab05f83Stholo Cell *p, *prev = NULL; 2026ab05f83Stholo int h; 2036ab05f83Stholo 2046ab05f83Stholo tp = (Array *) ap->sval; 2056ab05f83Stholo h = hash(s, tp->size); 2066ab05f83Stholo for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 20707edfa4aSkstailey if (strcmp(s, p->nval) == 0) { 2086ab05f83Stholo if (prev == NULL) /* 1st one */ 2096ab05f83Stholo tp->tab[h] = p->cnext; 2106ab05f83Stholo else /* middle somewhere */ 2116ab05f83Stholo prev->cnext = p->cnext; 2126ab05f83Stholo if (freeable(p)) 2136ab05f83Stholo xfree(p->sval); 2146ab05f83Stholo free(p->nval); 21507edfa4aSkstailey free(p); 2166ab05f83Stholo tp->nelem--; 2176ab05f83Stholo return; 2186ab05f83Stholo } 2196ab05f83Stholo } 2206ab05f83Stholo 2219a69093aSmillert Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) 2226ab05f83Stholo { 2236ab05f83Stholo int h; 2246ab05f83Stholo Cell *p; 2256ab05f83Stholo 2266ab05f83Stholo if (n != NULL && (p = lookup(n, tp)) != NULL) { 2275dd7c43cSderaadt DPRINTF( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", 228000399a4Smillert (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); 2296ab05f83Stholo return(p); 2306ab05f83Stholo } 2316ab05f83Stholo p = (Cell *) malloc(sizeof(Cell)); 2326ab05f83Stholo if (p == NULL) 2337b11b857Smillert FATAL("out of space for symbol table at %s", n); 2346ab05f83Stholo p->nval = tostring(n); 2356ab05f83Stholo p->sval = s ? tostring(s) : tostring(""); 2366ab05f83Stholo p->fval = f; 2376ab05f83Stholo p->tval = t; 2386ab05f83Stholo p->csub = CUNK; 2396ab05f83Stholo p->ctype = OCELL; 2406ab05f83Stholo tp->nelem++; 2416ab05f83Stholo if (tp->nelem > FULLTAB * tp->size) 2426ab05f83Stholo rehash(tp); 2436ab05f83Stholo h = hash(n, tp->size); 2446ab05f83Stholo p->cnext = tp->tab[h]; 2456ab05f83Stholo tp->tab[h] = p; 2465dd7c43cSderaadt DPRINTF( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", 247000399a4Smillert (void*)p, p->nval, p->sval, p->fval, p->tval) ); 2486ab05f83Stholo return(p); 2496ab05f83Stholo } 2506ab05f83Stholo 2519a69093aSmillert int hash(const char *s, int n) /* form hash value for string s */ 2526ab05f83Stholo { 2536ab05f83Stholo unsigned hashval; 2546ab05f83Stholo 2556ab05f83Stholo for (hashval = 0; *s != '\0'; s++) 2566ab05f83Stholo hashval = (*s + 31 * hashval); 2576ab05f83Stholo return hashval % n; 2586ab05f83Stholo } 2596ab05f83Stholo 2606ab05f83Stholo void rehash(Array *tp) /* rehash items in small table into big one */ 2616ab05f83Stholo { 2626ab05f83Stholo int i, nh, nsz; 2636ab05f83Stholo Cell *cp, *op, **np; 2646ab05f83Stholo 2656ab05f83Stholo nsz = GROWTAB * tp->size; 2666ab05f83Stholo np = (Cell **) calloc(nsz, sizeof(Cell *)); 2676ab05f83Stholo if (np == NULL) /* can't do it, but can keep running. */ 2686ab05f83Stholo return; /* someone else will run out later. */ 2696ab05f83Stholo for (i = 0; i < tp->size; i++) { 2706ab05f83Stholo for (cp = tp->tab[i]; cp; cp = op) { 2716ab05f83Stholo op = cp->cnext; 2726ab05f83Stholo nh = hash(cp->nval, nsz); 2736ab05f83Stholo cp->cnext = np[nh]; 2746ab05f83Stholo np[nh] = cp; 2756ab05f83Stholo } 2766ab05f83Stholo } 27707edfa4aSkstailey free(tp->tab); 2786ab05f83Stholo tp->tab = np; 2796ab05f83Stholo tp->size = nsz; 2806ab05f83Stholo } 2816ab05f83Stholo 2829a69093aSmillert Cell *lookup(const char *s, Array *tp) /* look for s in tp */ 2836ab05f83Stholo { 284271018d0Smillert Cell *p; 2856ab05f83Stholo int h; 2866ab05f83Stholo 2876ab05f83Stholo h = hash(s, tp->size); 288271018d0Smillert for (p = tp->tab[h]; p != NULL; p = p->cnext) 28907edfa4aSkstailey if (strcmp(s, p->nval) == 0) 2906ab05f83Stholo return(p); /* found it */ 2916ab05f83Stholo return(NULL); /* not found */ 2926ab05f83Stholo } 2936ab05f83Stholo 2946ab05f83Stholo Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 2956ab05f83Stholo { 29607edfa4aSkstailey int fldno; 29707edfa4aSkstailey 298*c062391aSmillert f += 0.0; /* normalise negative zero to positive zero */ 2996ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 3006ab05f83Stholo funnyvar(vp, "assign to"); 30107edfa4aSkstailey if (isfld(vp)) { 3026ab05f83Stholo donerec = 0; /* mark $0 invalid */ 30307edfa4aSkstailey fldno = atoi(vp->nval); 30407edfa4aSkstailey if (fldno > *NF) 30507edfa4aSkstailey newfld(fldno); 3065dd7c43cSderaadt DPRINTF( ("setting field %d to %g\n", fldno, f) ); 307*c062391aSmillert } else if (&vp->fval == NF) { 308*c062391aSmillert donerec = 0; /* mark $0 invalid */ 309*c062391aSmillert setlastfld(f); 310*c062391aSmillert DPRINTF( ("setting NF to %g\n", f) ); 31107edfa4aSkstailey } else if (isrec(vp)) { 3126ab05f83Stholo donefld = 0; /* mark $1... invalid */ 3136ab05f83Stholo donerec = 1; 3146ab05f83Stholo } 315a4fa8700Smillert if (freeable(vp)) 316a4fa8700Smillert xfree(vp->sval); /* free any previous string */ 317*c062391aSmillert vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */ 318*c062391aSmillert vp->fmt = NULL; 3196ab05f83Stholo vp->tval |= NUM; /* mark number ok */ 320a8d6f668Smillert if (f == -0) /* who would have thought this possible? */ 321a8d6f668Smillert f = 0; 3225dd7c43cSderaadt DPRINTF( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) ); 3236ab05f83Stholo return vp->fval = f; 3246ab05f83Stholo } 3256ab05f83Stholo 3269a69093aSmillert void funnyvar(Cell *vp, const char *rw) 3276ab05f83Stholo { 32807edfa4aSkstailey if (isarr(vp)) 3297b11b857Smillert FATAL("can't %s %s; it's an array name.", rw, vp->nval); 3306ab05f83Stholo if (vp->tval & FCN) 3317b11b857Smillert FATAL("can't %s %s; it's a function.", rw, vp->nval); 3327b11b857Smillert WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", 3337b11b857Smillert vp, vp->nval, vp->sval, vp->fval, vp->tval); 3346ab05f83Stholo } 3356ab05f83Stholo 3369a69093aSmillert char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ 3376ab05f83Stholo { 3386ab05f83Stholo char *t; 33907edfa4aSkstailey int fldno; 340*c062391aSmillert Awkfloat f; 3416ab05f83Stholo 3425dd7c43cSderaadt DPRINTF( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", 343000399a4Smillert (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); 3446ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 3456ab05f83Stholo funnyvar(vp, "assign to"); 34607edfa4aSkstailey if (isfld(vp)) { 3476ab05f83Stholo donerec = 0; /* mark $0 invalid */ 34807edfa4aSkstailey fldno = atoi(vp->nval); 34907edfa4aSkstailey if (fldno > *NF) 35007edfa4aSkstailey newfld(fldno); 3515dd7c43cSderaadt DPRINTF( ("setting field %d to %s (%p)\n", fldno, s, s) ); 35207edfa4aSkstailey } else if (isrec(vp)) { 3536ab05f83Stholo donefld = 0; /* mark $1... invalid */ 3546ab05f83Stholo donerec = 1; 355*c062391aSmillert } else if (&vp->sval == OFS) { 356*c062391aSmillert if (donerec == 0) 357*c062391aSmillert recbld(); 3586ab05f83Stholo } 359*c062391aSmillert t = s ? tostring(s) : tostring(""); /* in case it's self-assign */ 3606ab05f83Stholo if (freeable(vp)) 3616ab05f83Stholo xfree(vp->sval); 362*c062391aSmillert vp->tval &= ~(NUM|CONVC|CONVO); 3634eb91dacSjmc vp->tval |= STR; 364*c062391aSmillert vp->fmt = NULL; 365*c062391aSmillert setfree(vp); 3665dd7c43cSderaadt DPRINTF( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", 367000399a4Smillert (void*)vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) ); 368*c062391aSmillert vp->sval = t; 369*c062391aSmillert if (&vp->fval == NF) { 370*c062391aSmillert donerec = 0; /* mark $0 invalid */ 371*c062391aSmillert f = getfval(vp); 372*c062391aSmillert setlastfld(f); 373*c062391aSmillert DPRINTF( ("setting NF to %g\n", f) ); 374*c062391aSmillert } 375*c062391aSmillert 376*c062391aSmillert return(vp->sval); 3776ab05f83Stholo } 3786ab05f83Stholo 3796ab05f83Stholo Awkfloat getfval(Cell *vp) /* get float val of a Cell */ 3806ab05f83Stholo { 3816ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 3826ab05f83Stholo funnyvar(vp, "read value of"); 38307edfa4aSkstailey if (isfld(vp) && donefld == 0) 3846ab05f83Stholo fldbld(); 38507edfa4aSkstailey else if (isrec(vp) && donerec == 0) 3866ab05f83Stholo recbld(); 3876ab05f83Stholo if (!isnum(vp)) { /* not a number */ 3886ab05f83Stholo vp->fval = atof(vp->sval); /* best guess */ 389a4fa8700Smillert if (is_number(vp->sval) && !(vp->tval&CON)) 3906ab05f83Stholo vp->tval |= NUM; /* make NUM only sparingly */ 3916ab05f83Stholo } 3925dd7c43cSderaadt DPRINTF( ("getfval %p: %s = %g, t=%o\n", 393000399a4Smillert (void*)vp, NN(vp->nval), vp->fval, vp->tval) ); 3946ab05f83Stholo return(vp->fval); 3956ab05f83Stholo } 3966ab05f83Stholo 3979a69093aSmillert static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ 3986ab05f83Stholo { 399a4a48c73Smillert int n; 4006ab05f83Stholo double dtemp; 4016ab05f83Stholo 4026ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 4036ab05f83Stholo funnyvar(vp, "read value of"); 40407edfa4aSkstailey if (isfld(vp) && donefld == 0) 4056ab05f83Stholo fldbld(); 40607edfa4aSkstailey else if (isrec(vp) && donerec == 0) 4076ab05f83Stholo recbld(); 408*c062391aSmillert 409*c062391aSmillert /* 410*c062391aSmillert * ADR: This is complicated and more fragile than is desirable. 411*c062391aSmillert * Retrieving a string value for a number associates the string 412*c062391aSmillert * value with the scalar. Previously, the string value was 413*c062391aSmillert * sticky, meaning if converted via OFMT that became the value 414*c062391aSmillert * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT 415*c062391aSmillert * changed after a string value was retrieved, the original value 416*c062391aSmillert * was maintained and used. Also not per POSIX. 417*c062391aSmillert * 418*c062391aSmillert * We work around this design by adding two additional flags, 419*c062391aSmillert * CONVC and CONVO, indicating how the string value was 420*c062391aSmillert * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy 421*c062391aSmillert * of the pointer to the xFMT format string used for the 422*c062391aSmillert * conversion. This pointer is only read, **never** dereferenced. 423*c062391aSmillert * The next time we do a conversion, if it's coming from the same 424*c062391aSmillert * xFMT as last time, and the pointer value is different, we 425*c062391aSmillert * know that the xFMT format string changed, and we need to 426*c062391aSmillert * redo the conversion. If it's the same, we don't have to. 427*c062391aSmillert * 428*c062391aSmillert * There are also several cases where we don't do a conversion, 429*c062391aSmillert * such as for a field (see the checks below). 430*c062391aSmillert */ 431*c062391aSmillert 432*c062391aSmillert /* Don't duplicate the code for actually updating the value */ 433*c062391aSmillert #define update_str_val(vp) \ 434*c062391aSmillert { \ 435*c062391aSmillert if (freeable(vp)) \ 436*c062391aSmillert xfree(vp->sval); \ 437*c062391aSmillert if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ 438*c062391aSmillert n = asprintf(&vp->sval, "%.30g", vp->fval); \ 439*c062391aSmillert else \ 440*c062391aSmillert n = asprintf(&vp->sval, *fmt, vp->fval); \ 441*c062391aSmillert if (n == -1) \ 442*c062391aSmillert FATAL("out of space in get_str_val"); \ 443*c062391aSmillert vp->tval &= ~DONTFREE; \ 444*c062391aSmillert vp->tval |= STR; \ 4456ab05f83Stholo } 446*c062391aSmillert 447*c062391aSmillert if (isstr(vp) == 0) { 448*c062391aSmillert update_str_val(vp); 449*c062391aSmillert if (fmt == OFMT) { 450*c062391aSmillert vp->tval &= ~CONVC; 451*c062391aSmillert vp->tval |= CONVO; 452*c062391aSmillert } else { 453*c062391aSmillert /* CONVFMT */ 454*c062391aSmillert vp->tval &= ~CONVO; 455*c062391aSmillert vp->tval |= CONVC; 456*c062391aSmillert } 457*c062391aSmillert vp->fmt = *fmt; 458*c062391aSmillert } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) { 459*c062391aSmillert goto done; 460*c062391aSmillert } else if (isstr(vp)) { 461*c062391aSmillert if (fmt == OFMT) { 462*c062391aSmillert if ((vp->tval & CONVC) != 0 463*c062391aSmillert || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) { 464*c062391aSmillert update_str_val(vp); 465*c062391aSmillert vp->tval &= ~CONVC; 466*c062391aSmillert vp->tval |= CONVO; 467*c062391aSmillert vp->fmt = *fmt; 468*c062391aSmillert } 469*c062391aSmillert } else { 470*c062391aSmillert /* CONVFMT */ 471*c062391aSmillert if ((vp->tval & CONVO) != 0 472*c062391aSmillert || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) { 473*c062391aSmillert update_str_val(vp); 474*c062391aSmillert vp->tval &= ~CONVO; 475*c062391aSmillert vp->tval |= CONVC; 476*c062391aSmillert vp->fmt = *fmt; 477*c062391aSmillert } 478*c062391aSmillert } 479*c062391aSmillert } 480*c062391aSmillert done: 4815dd7c43cSderaadt DPRINTF( ("getsval %p: %s = \"%s (%p)\", t=%o\n", 482000399a4Smillert (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); 4836ab05f83Stholo return(vp->sval); 4846ab05f83Stholo } 4856ab05f83Stholo 4869a69093aSmillert char *getsval(Cell *vp) /* get string val of a Cell */ 4879a69093aSmillert { 4889a69093aSmillert return get_str_val(vp, CONVFMT); 4899a69093aSmillert } 4909a69093aSmillert 4919a69093aSmillert char *getpssval(Cell *vp) /* get string val of a Cell for print */ 4929a69093aSmillert { 4939a69093aSmillert return get_str_val(vp, OFMT); 4949a69093aSmillert } 4959a69093aSmillert 4969a69093aSmillert 4979a69093aSmillert char *tostring(const char *s) /* make a copy of string s */ 4986ab05f83Stholo { 4998055ea94Smillert char *p; 5008055ea94Smillert 5018055ea94Smillert p = strdup(s); 5028055ea94Smillert if (p == NULL) 5038055ea94Smillert FATAL("out of space in tostring on %s", s); 5048055ea94Smillert return p; 5056ab05f83Stholo } 5066ab05f83Stholo 5079a69093aSmillert char *qstring(const char *is, int delim) /* collect string up to next delim */ 5086ab05f83Stholo { 5099a69093aSmillert const char *os = is; 5106ab05f83Stholo int c, n; 511a27f5228Smillert uschar *s = (uschar *) is; 512a27f5228Smillert uschar *buf, *bp; 5136ab05f83Stholo 5149a69093aSmillert if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL) 5157b11b857Smillert FATAL( "out of space in qstring(%s)", s); 51607edfa4aSkstailey for (bp = buf; (c = *s) != delim; s++) { 5176ab05f83Stholo if (c == '\n') 5187b11b857Smillert SYNTAX( "newline in string %.20s...", os ); 5196ab05f83Stholo else if (c != '\\') 52007edfa4aSkstailey *bp++ = c; 52107edfa4aSkstailey else { /* \something */ 5227b11b857Smillert c = *++s; 5237b11b857Smillert if (c == 0) { /* \ at end */ 5247b11b857Smillert *bp++ = '\\'; 5257b11b857Smillert break; /* for loop */ 5267b11b857Smillert } 5277b11b857Smillert switch (c) { 52807edfa4aSkstailey case '\\': *bp++ = '\\'; break; 52907edfa4aSkstailey case 'n': *bp++ = '\n'; break; 53007edfa4aSkstailey case 't': *bp++ = '\t'; break; 5317bcc45acSmillert case 'v': *bp++ = '\v'; break; 53207edfa4aSkstailey case 'b': *bp++ = '\b'; break; 53307edfa4aSkstailey case 'f': *bp++ = '\f'; break; 53407edfa4aSkstailey case 'r': *bp++ = '\r'; break; 5357bcc45acSmillert case 'a': *bp++ = '\007'; break; 5366ab05f83Stholo default: 5376ab05f83Stholo if (!isdigit(c)) { 53807edfa4aSkstailey *bp++ = c; 5396ab05f83Stholo break; 5406ab05f83Stholo } 5416ab05f83Stholo n = c - '0'; 5426ab05f83Stholo if (isdigit(s[1])) { 5436ab05f83Stholo n = 8 * n + *++s - '0'; 5446ab05f83Stholo if (isdigit(s[1])) 5456ab05f83Stholo n = 8 * n + *++s - '0'; 5466ab05f83Stholo } 54707edfa4aSkstailey *bp++ = n; 5486ab05f83Stholo break; 5496ab05f83Stholo } 5506ab05f83Stholo } 55107edfa4aSkstailey } 55207edfa4aSkstailey *bp++ = 0; 553a27f5228Smillert return (char *) buf; 5546ab05f83Stholo } 555*c062391aSmillert 556*c062391aSmillert const char *flags2str(int flags) 557*c062391aSmillert { 558*c062391aSmillert static const struct ftab { 559*c062391aSmillert const char *name; 560*c062391aSmillert int value; 561*c062391aSmillert } flagtab[] = { 562*c062391aSmillert { "NUM", NUM }, 563*c062391aSmillert { "STR", STR }, 564*c062391aSmillert { "DONTFREE", DONTFREE }, 565*c062391aSmillert { "CON", CON }, 566*c062391aSmillert { "ARR", ARR }, 567*c062391aSmillert { "FCN", FCN }, 568*c062391aSmillert { "FLD", FLD }, 569*c062391aSmillert { "REC", REC }, 570*c062391aSmillert { "CONVC", CONVC }, 571*c062391aSmillert { "CONVO", CONVO }, 572*c062391aSmillert { NULL, 0 } 573*c062391aSmillert }; 574*c062391aSmillert static char buf[100]; 575*c062391aSmillert int i, len; 576*c062391aSmillert char *cp = buf; 577*c062391aSmillert 578*c062391aSmillert for (i = 0; flagtab[i].name != NULL; i++) { 579*c062391aSmillert if ((flags & flagtab[i].value) != 0) { 580*c062391aSmillert len = snprintf(cp, sizeof(buf) - (cp - buf), 581*c062391aSmillert "%s%s", cp > buf ? "|" : "", flagtab[i].name); 582*c062391aSmillert if (len < 0 || len >= sizeof(buf) - (cp - buf)) 583*c062391aSmillert FATAL("out of space in flags2str"); 584*c062391aSmillert cp += len; 585*c062391aSmillert } 586*c062391aSmillert } 587*c062391aSmillert 588*c062391aSmillert return buf; 589*c062391aSmillert } 590