1*4eb91dacSjmc /* $OpenBSD: tran.c,v 1.14 2006/11/04 19:10:15 jmc 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 716ab05f83Stholo void syminit(void) /* initialize symbol table with builtin vars */ 726ab05f83Stholo { 7307edfa4aSkstailey literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 746ab05f83Stholo /* this is used for if(x)... tests: */ 756ab05f83Stholo nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 7607edfa4aSkstailey nullnode = celltonode(nullloc, CCON); 776ab05f83Stholo 7823cb51abSmillert fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab); 7923cb51abSmillert FS = &fsloc->sval; 806ab05f83Stholo RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 816ab05f83Stholo OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval; 826ab05f83Stholo ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 836ab05f83Stholo OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 846ab05f83Stholo CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 85b2698ba9Smillert FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 866ab05f83Stholo nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 876ab05f83Stholo NF = &nfloc->fval; 886ab05f83Stholo nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 896ab05f83Stholo NR = &nrloc->fval; 906ab05f83Stholo fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 916ab05f83Stholo FNR = &fnrloc->fval; 926ab05f83Stholo SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval; 936ab05f83Stholo rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 946ab05f83Stholo RSTART = &rstartloc->fval; 956ab05f83Stholo rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 966ab05f83Stholo RLENGTH = &rlengthloc->fval; 976ab05f83Stholo symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 986ab05f83Stholo symtabloc->sval = (char *) symtab; 996ab05f83Stholo } 1006ab05f83Stholo 10107edfa4aSkstailey void arginit(int ac, char **av) /* set up ARGV and ARGC */ 1026ab05f83Stholo { 1036ab05f83Stholo Cell *cp; 1046ab05f83Stholo int i; 10507edfa4aSkstailey char temp[50]; 1066ab05f83Stholo 1076ab05f83Stholo ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 1086ab05f83Stholo cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 1096ab05f83Stholo ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 1106ab05f83Stholo cp->sval = (char *) ARGVtab; 1116ab05f83Stholo for (i = 0; i < ac; i++) { 1129e405e78Sderaadt snprintf(temp, sizeof temp, "%d", i); 113a4fa8700Smillert if (is_number(*av)) 1146ab05f83Stholo setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 1156ab05f83Stholo else 1166ab05f83Stholo setsymtab(temp, *av, 0.0, STR, ARGVtab); 1176ab05f83Stholo av++; 1186ab05f83Stholo } 1196ab05f83Stholo } 1206ab05f83Stholo 1216ab05f83Stholo void envinit(char **envp) /* set up ENVIRON variable */ 1226ab05f83Stholo { 1236ab05f83Stholo Cell *cp; 1246ab05f83Stholo char *p; 1256ab05f83Stholo 1266ab05f83Stholo cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 1276ab05f83Stholo ENVtab = makesymtab(NSYMTAB); 1286ab05f83Stholo cp->sval = (char *) ENVtab; 1296ab05f83Stholo for ( ; *envp; envp++) { 13007edfa4aSkstailey if ((p = strchr(*envp, '=')) == NULL) 1316ab05f83Stholo continue; 132a27f5228Smillert if( p == *envp ) /* no left hand side name in env string */ 133a27f5228Smillert continue; 1346ab05f83Stholo *p++ = 0; /* split into two strings at = */ 135a4fa8700Smillert if (is_number(p)) 1366ab05f83Stholo setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 1376ab05f83Stholo else 1386ab05f83Stholo setsymtab(*envp, p, 0.0, STR, ENVtab); 1396ab05f83Stholo p[-1] = '='; /* restore in case env is passed down to a shell */ 1406ab05f83Stholo } 1416ab05f83Stholo } 1426ab05f83Stholo 1436ab05f83Stholo Array *makesymtab(int n) /* make a new symbol table */ 1446ab05f83Stholo { 1456ab05f83Stholo Array *ap; 1466ab05f83Stholo Cell **tp; 1476ab05f83Stholo 1486ab05f83Stholo ap = (Array *) malloc(sizeof(Array)); 1496ab05f83Stholo tp = (Cell **) calloc(n, sizeof(Cell *)); 1506ab05f83Stholo if (ap == NULL || tp == NULL) 1517b11b857Smillert FATAL("out of space in makesymtab"); 1526ab05f83Stholo ap->nelem = 0; 1536ab05f83Stholo ap->size = n; 1546ab05f83Stholo ap->tab = tp; 1556ab05f83Stholo return(ap); 1566ab05f83Stholo } 1576ab05f83Stholo 1586ab05f83Stholo void freesymtab(Cell *ap) /* free a symbol table */ 1596ab05f83Stholo { 1606ab05f83Stholo Cell *cp, *temp; 1616ab05f83Stholo Array *tp; 1626ab05f83Stholo int i; 1636ab05f83Stholo 1646ab05f83Stholo if (!isarr(ap)) 1656ab05f83Stholo return; 1666ab05f83Stholo tp = (Array *) ap->sval; 1676ab05f83Stholo if (tp == NULL) 1686ab05f83Stholo return; 1696ab05f83Stholo for (i = 0; i < tp->size; i++) { 1706ab05f83Stholo for (cp = tp->tab[i]; cp != NULL; cp = temp) { 1716ab05f83Stholo xfree(cp->nval); 1726ab05f83Stholo if (freeable(cp)) 1736ab05f83Stholo xfree(cp->sval); 1746ab05f83Stholo temp = cp->cnext; /* avoids freeing then using */ 17507edfa4aSkstailey free(cp); 1769a69093aSmillert tp->nelem--; 1776ab05f83Stholo } 1786ab05f83Stholo tp->tab[i] = 0; 1796ab05f83Stholo } 1809a69093aSmillert if (tp->nelem != 0) 1819a69093aSmillert WARNING("can't happen: inconsistent element count freeing %s", ap->nval); 18207edfa4aSkstailey free(tp->tab); 18307edfa4aSkstailey free(tp); 1846ab05f83Stholo } 1856ab05f83Stholo 1869a69093aSmillert void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ 1876ab05f83Stholo { 1886ab05f83Stholo Array *tp; 1896ab05f83Stholo Cell *p, *prev = NULL; 1906ab05f83Stholo int h; 1916ab05f83Stholo 1926ab05f83Stholo tp = (Array *) ap->sval; 1936ab05f83Stholo h = hash(s, tp->size); 1946ab05f83Stholo for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 19507edfa4aSkstailey if (strcmp(s, p->nval) == 0) { 1966ab05f83Stholo if (prev == NULL) /* 1st one */ 1976ab05f83Stholo tp->tab[h] = p->cnext; 1986ab05f83Stholo else /* middle somewhere */ 1996ab05f83Stholo prev->cnext = p->cnext; 2006ab05f83Stholo if (freeable(p)) 2016ab05f83Stholo xfree(p->sval); 2026ab05f83Stholo free(p->nval); 20307edfa4aSkstailey free(p); 2046ab05f83Stholo tp->nelem--; 2056ab05f83Stholo return; 2066ab05f83Stholo } 2076ab05f83Stholo } 2086ab05f83Stholo 2099a69093aSmillert Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) 2106ab05f83Stholo { 2116ab05f83Stholo int h; 2126ab05f83Stholo Cell *p; 2136ab05f83Stholo 2146ab05f83Stholo if (n != NULL && (p = lookup(n, tp)) != NULL) { 2156ab05f83Stholo dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", 2169a69093aSmillert p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); 2176ab05f83Stholo return(p); 2186ab05f83Stholo } 2196ab05f83Stholo p = (Cell *) malloc(sizeof(Cell)); 2206ab05f83Stholo if (p == NULL) 2217b11b857Smillert FATAL("out of space for symbol table at %s", n); 2226ab05f83Stholo p->nval = tostring(n); 2236ab05f83Stholo p->sval = s ? tostring(s) : tostring(""); 2246ab05f83Stholo p->fval = f; 2256ab05f83Stholo p->tval = t; 2266ab05f83Stholo p->csub = CUNK; 2276ab05f83Stholo p->ctype = OCELL; 2286ab05f83Stholo tp->nelem++; 2296ab05f83Stholo if (tp->nelem > FULLTAB * tp->size) 2306ab05f83Stholo rehash(tp); 2316ab05f83Stholo h = hash(n, tp->size); 2326ab05f83Stholo p->cnext = tp->tab[h]; 2336ab05f83Stholo tp->tab[h] = p; 2346ab05f83Stholo dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", 2356ab05f83Stholo p, p->nval, p->sval, p->fval, p->tval) ); 2366ab05f83Stholo return(p); 2376ab05f83Stholo } 2386ab05f83Stholo 2399a69093aSmillert int hash(const char *s, int n) /* form hash value for string s */ 2406ab05f83Stholo { 2416ab05f83Stholo unsigned hashval; 2426ab05f83Stholo 2436ab05f83Stholo for (hashval = 0; *s != '\0'; s++) 2446ab05f83Stholo hashval = (*s + 31 * hashval); 2456ab05f83Stholo return hashval % n; 2466ab05f83Stholo } 2476ab05f83Stholo 2486ab05f83Stholo void rehash(Array *tp) /* rehash items in small table into big one */ 2496ab05f83Stholo { 2506ab05f83Stholo int i, nh, nsz; 2516ab05f83Stholo Cell *cp, *op, **np; 2526ab05f83Stholo 2536ab05f83Stholo nsz = GROWTAB * tp->size; 2546ab05f83Stholo np = (Cell **) calloc(nsz, sizeof(Cell *)); 2556ab05f83Stholo if (np == NULL) /* can't do it, but can keep running. */ 2566ab05f83Stholo return; /* someone else will run out later. */ 2576ab05f83Stholo for (i = 0; i < tp->size; i++) { 2586ab05f83Stholo for (cp = tp->tab[i]; cp; cp = op) { 2596ab05f83Stholo op = cp->cnext; 2606ab05f83Stholo nh = hash(cp->nval, nsz); 2616ab05f83Stholo cp->cnext = np[nh]; 2626ab05f83Stholo np[nh] = cp; 2636ab05f83Stholo } 2646ab05f83Stholo } 26507edfa4aSkstailey free(tp->tab); 2666ab05f83Stholo tp->tab = np; 2676ab05f83Stholo tp->size = nsz; 2686ab05f83Stholo } 2696ab05f83Stholo 2709a69093aSmillert Cell *lookup(const char *s, Array *tp) /* look for s in tp */ 2716ab05f83Stholo { 272271018d0Smillert Cell *p; 2736ab05f83Stholo int h; 2746ab05f83Stholo 2756ab05f83Stholo h = hash(s, tp->size); 276271018d0Smillert for (p = tp->tab[h]; p != NULL; p = p->cnext) 27707edfa4aSkstailey if (strcmp(s, p->nval) == 0) 2786ab05f83Stholo return(p); /* found it */ 2796ab05f83Stholo return(NULL); /* not found */ 2806ab05f83Stholo } 2816ab05f83Stholo 2826ab05f83Stholo Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 2836ab05f83Stholo { 28407edfa4aSkstailey int fldno; 28507edfa4aSkstailey 2866ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 2876ab05f83Stholo funnyvar(vp, "assign to"); 28807edfa4aSkstailey if (isfld(vp)) { 2896ab05f83Stholo donerec = 0; /* mark $0 invalid */ 29007edfa4aSkstailey fldno = atoi(vp->nval); 29107edfa4aSkstailey if (fldno > *NF) 29207edfa4aSkstailey newfld(fldno); 29307edfa4aSkstailey dprintf( ("setting field %d to %g\n", fldno, f) ); 29407edfa4aSkstailey } else if (isrec(vp)) { 2956ab05f83Stholo donefld = 0; /* mark $1... invalid */ 2966ab05f83Stholo donerec = 1; 2976ab05f83Stholo } 298a4fa8700Smillert if (freeable(vp)) 299a4fa8700Smillert xfree(vp->sval); /* free any previous string */ 3006ab05f83Stholo vp->tval &= ~STR; /* mark string invalid */ 3016ab05f83Stholo vp->tval |= NUM; /* mark number ok */ 3029a69093aSmillert dprintf( ("setfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), f, vp->tval) ); 3036ab05f83Stholo return vp->fval = f; 3046ab05f83Stholo } 3056ab05f83Stholo 3069a69093aSmillert void funnyvar(Cell *vp, const char *rw) 3076ab05f83Stholo { 30807edfa4aSkstailey if (isarr(vp)) 3097b11b857Smillert FATAL("can't %s %s; it's an array name.", rw, vp->nval); 3106ab05f83Stholo if (vp->tval & FCN) 3117b11b857Smillert FATAL("can't %s %s; it's a function.", rw, vp->nval); 3127b11b857Smillert WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", 3137b11b857Smillert vp, vp->nval, vp->sval, vp->fval, vp->tval); 3146ab05f83Stholo } 3156ab05f83Stholo 3169a69093aSmillert char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ 3176ab05f83Stholo { 3186ab05f83Stholo char *t; 31907edfa4aSkstailey int fldno; 3206ab05f83Stholo 32123cb51abSmillert dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", 32223cb51abSmillert vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); 3236ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 3246ab05f83Stholo funnyvar(vp, "assign to"); 32507edfa4aSkstailey if (isfld(vp)) { 3266ab05f83Stholo donerec = 0; /* mark $0 invalid */ 32707edfa4aSkstailey fldno = atoi(vp->nval); 32807edfa4aSkstailey if (fldno > *NF) 32907edfa4aSkstailey newfld(fldno); 33007edfa4aSkstailey dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); 33107edfa4aSkstailey } else if (isrec(vp)) { 3326ab05f83Stholo donefld = 0; /* mark $1... invalid */ 3336ab05f83Stholo donerec = 1; 3346ab05f83Stholo } 3356ab05f83Stholo t = tostring(s); /* in case it's self-assign */ 3366ab05f83Stholo if (freeable(vp)) 3376ab05f83Stholo xfree(vp->sval); 338*4eb91dacSjmc vp->tval &= ~NUM; 339*4eb91dacSjmc vp->tval |= STR; 3406ab05f83Stholo vp->tval &= ~DONTFREE; 34123cb51abSmillert dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", 34223cb51abSmillert vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) ); 3436ab05f83Stholo return(vp->sval = t); 3446ab05f83Stholo } 3456ab05f83Stholo 3466ab05f83Stholo Awkfloat getfval(Cell *vp) /* get float val of a Cell */ 3476ab05f83Stholo { 3486ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 3496ab05f83Stholo funnyvar(vp, "read value of"); 35007edfa4aSkstailey if (isfld(vp) && donefld == 0) 3516ab05f83Stholo fldbld(); 35207edfa4aSkstailey else if (isrec(vp) && donerec == 0) 3536ab05f83Stholo recbld(); 3546ab05f83Stholo if (!isnum(vp)) { /* not a number */ 3556ab05f83Stholo vp->fval = atof(vp->sval); /* best guess */ 356a4fa8700Smillert if (is_number(vp->sval) && !(vp->tval&CON)) 3576ab05f83Stholo vp->tval |= NUM; /* make NUM only sparingly */ 3586ab05f83Stholo } 3599a69093aSmillert dprintf( ("getfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), vp->fval, vp->tval) ); 3606ab05f83Stholo return(vp->fval); 3616ab05f83Stholo } 3626ab05f83Stholo 3639a69093aSmillert static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ 3646ab05f83Stholo { 365a4a48c73Smillert int n; 3666ab05f83Stholo double dtemp; 3676ab05f83Stholo 3686ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 3696ab05f83Stholo funnyvar(vp, "read value of"); 37007edfa4aSkstailey if (isfld(vp) && donefld == 0) 3716ab05f83Stholo fldbld(); 37207edfa4aSkstailey else if (isrec(vp) && donerec == 0) 3736ab05f83Stholo recbld(); 37407edfa4aSkstailey if (isstr(vp) == 0) { 37507edfa4aSkstailey if (freeable(vp)) 3766ab05f83Stholo xfree(vp->sval); 3776ab05f83Stholo if (modf(vp->fval, &dtemp) == 0) /* it's integral */ 378a4a48c73Smillert n = asprintf(&vp->sval, "%.30g", vp->fval); 3796ab05f83Stholo else 380a4a48c73Smillert n = asprintf(&vp->sval, *fmt, vp->fval); 381a4a48c73Smillert if (n == -1) 382a4a48c73Smillert FATAL("out of space in get_str_val"); 3836ab05f83Stholo vp->tval &= ~DONTFREE; 3846ab05f83Stholo vp->tval |= STR; 3856ab05f83Stholo } 3869a69093aSmillert dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); 3876ab05f83Stholo return(vp->sval); 3886ab05f83Stholo } 3896ab05f83Stholo 3909a69093aSmillert char *getsval(Cell *vp) /* get string val of a Cell */ 3919a69093aSmillert { 3929a69093aSmillert return get_str_val(vp, CONVFMT); 3939a69093aSmillert } 3949a69093aSmillert 3959a69093aSmillert char *getpssval(Cell *vp) /* get string val of a Cell for print */ 3969a69093aSmillert { 3979a69093aSmillert return get_str_val(vp, OFMT); 3989a69093aSmillert } 3999a69093aSmillert 4009a69093aSmillert 4019a69093aSmillert char *tostring(const char *s) /* make a copy of string s */ 4026ab05f83Stholo { 4038055ea94Smillert char *p; 4048055ea94Smillert 4058055ea94Smillert p = strdup(s); 4068055ea94Smillert if (p == NULL) 4078055ea94Smillert FATAL("out of space in tostring on %s", s); 4088055ea94Smillert return p; 4096ab05f83Stholo } 4106ab05f83Stholo 4119a69093aSmillert char *qstring(const char *is, int delim) /* collect string up to next delim */ 4126ab05f83Stholo { 4139a69093aSmillert const char *os = is; 4146ab05f83Stholo int c, n; 415a27f5228Smillert uschar *s = (uschar *) is; 416a27f5228Smillert uschar *buf, *bp; 4176ab05f83Stholo 4189a69093aSmillert if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL) 4197b11b857Smillert FATAL( "out of space in qstring(%s)", s); 42007edfa4aSkstailey for (bp = buf; (c = *s) != delim; s++) { 4216ab05f83Stholo if (c == '\n') 4227b11b857Smillert SYNTAX( "newline in string %.20s...", os ); 4236ab05f83Stholo else if (c != '\\') 42407edfa4aSkstailey *bp++ = c; 42507edfa4aSkstailey else { /* \something */ 4267b11b857Smillert c = *++s; 4277b11b857Smillert if (c == 0) { /* \ at end */ 4287b11b857Smillert *bp++ = '\\'; 4297b11b857Smillert break; /* for loop */ 4307b11b857Smillert } 4317b11b857Smillert switch (c) { 43207edfa4aSkstailey case '\\': *bp++ = '\\'; break; 43307edfa4aSkstailey case 'n': *bp++ = '\n'; break; 43407edfa4aSkstailey case 't': *bp++ = '\t'; break; 43507edfa4aSkstailey case 'b': *bp++ = '\b'; break; 43607edfa4aSkstailey case 'f': *bp++ = '\f'; break; 43707edfa4aSkstailey case 'r': *bp++ = '\r'; break; 4386ab05f83Stholo default: 4396ab05f83Stholo if (!isdigit(c)) { 44007edfa4aSkstailey *bp++ = c; 4416ab05f83Stholo break; 4426ab05f83Stholo } 4436ab05f83Stholo n = c - '0'; 4446ab05f83Stholo if (isdigit(s[1])) { 4456ab05f83Stholo n = 8 * n + *++s - '0'; 4466ab05f83Stholo if (isdigit(s[1])) 4476ab05f83Stholo n = 8 * n + *++s - '0'; 4486ab05f83Stholo } 44907edfa4aSkstailey *bp++ = n; 4506ab05f83Stholo break; 4516ab05f83Stholo } 4526ab05f83Stholo } 45307edfa4aSkstailey } 45407edfa4aSkstailey *bp++ = 0; 455a27f5228Smillert return (char *) buf; 4566ab05f83Stholo } 457