1*271018d0Smillert /* $OpenBSD: tran.c,v 1.5 1999/04/20 17:31:31 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 556ab05f83Stholo Cell *nrloc; /* NR */ 566ab05f83Stholo Cell *nfloc; /* NF */ 576ab05f83Stholo Cell *fnrloc; /* FNR */ 586ab05f83Stholo Array *ARGVtab; /* symbol table containing ARGV[...] */ 596ab05f83Stholo Array *ENVtab; /* symbol table containing ENVIRON[...] */ 606ab05f83Stholo Cell *rstartloc; /* RSTART */ 616ab05f83Stholo Cell *rlengthloc; /* RLENGTH */ 626ab05f83Stholo Cell *symtabloc; /* SYMTAB */ 636ab05f83Stholo 646ab05f83Stholo Cell *nullloc; /* a guaranteed empty cell */ 656ab05f83Stholo Node *nullnode; /* zero&null, converted into a node for comparisons */ 6607edfa4aSkstailey Cell *literal0; 676ab05f83Stholo 6807edfa4aSkstailey extern Cell **fldtab; 696ab05f83Stholo 706ab05f83Stholo void syminit(void) /* initialize symbol table with builtin vars */ 716ab05f83Stholo { 7207edfa4aSkstailey literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 736ab05f83Stholo /* this is used for if(x)... tests: */ 746ab05f83Stholo nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 7507edfa4aSkstailey nullnode = celltonode(nullloc, CCON); 766ab05f83Stholo 776ab05f83Stholo FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval; 786ab05f83Stholo RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 796ab05f83Stholo OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval; 806ab05f83Stholo ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 816ab05f83Stholo OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 826ab05f83Stholo CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 83b2698ba9Smillert FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 846ab05f83Stholo nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 856ab05f83Stholo NF = &nfloc->fval; 866ab05f83Stholo nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 876ab05f83Stholo NR = &nrloc->fval; 886ab05f83Stholo fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 896ab05f83Stholo FNR = &fnrloc->fval; 906ab05f83Stholo SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval; 916ab05f83Stholo rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 926ab05f83Stholo RSTART = &rstartloc->fval; 936ab05f83Stholo rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 946ab05f83Stholo RLENGTH = &rlengthloc->fval; 956ab05f83Stholo symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 966ab05f83Stholo symtabloc->sval = (char *) symtab; 976ab05f83Stholo } 986ab05f83Stholo 9907edfa4aSkstailey void arginit(int ac, char **av) /* set up ARGV and ARGC */ 1006ab05f83Stholo { 1016ab05f83Stholo Cell *cp; 1026ab05f83Stholo int i; 10307edfa4aSkstailey char temp[50]; 1046ab05f83Stholo 1056ab05f83Stholo ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 1066ab05f83Stholo cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 1076ab05f83Stholo ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 1086ab05f83Stholo cp->sval = (char *) ARGVtab; 1096ab05f83Stholo for (i = 0; i < ac; i++) { 11007edfa4aSkstailey sprintf(temp, "%d", i); 111a4fa8700Smillert if (is_number(*av)) 1126ab05f83Stholo setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 1136ab05f83Stholo else 1146ab05f83Stholo setsymtab(temp, *av, 0.0, STR, ARGVtab); 1156ab05f83Stholo av++; 1166ab05f83Stholo } 1176ab05f83Stholo } 1186ab05f83Stholo 1196ab05f83Stholo void envinit(char **envp) /* set up ENVIRON variable */ 1206ab05f83Stholo { 1216ab05f83Stholo Cell *cp; 1226ab05f83Stholo char *p; 1236ab05f83Stholo 1246ab05f83Stholo cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 1256ab05f83Stholo ENVtab = makesymtab(NSYMTAB); 1266ab05f83Stholo cp->sval = (char *) ENVtab; 1276ab05f83Stholo for ( ; *envp; envp++) { 12807edfa4aSkstailey if ((p = strchr(*envp, '=')) == NULL) 1296ab05f83Stholo continue; 1306ab05f83Stholo *p++ = 0; /* split into two strings at = */ 131a4fa8700Smillert if (is_number(p)) 1326ab05f83Stholo setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 1336ab05f83Stholo else 1346ab05f83Stholo setsymtab(*envp, p, 0.0, STR, ENVtab); 1356ab05f83Stholo p[-1] = '='; /* restore in case env is passed down to a shell */ 1366ab05f83Stholo } 1376ab05f83Stholo } 1386ab05f83Stholo 1396ab05f83Stholo Array *makesymtab(int n) /* make a new symbol table */ 1406ab05f83Stholo { 1416ab05f83Stholo Array *ap; 1426ab05f83Stholo Cell **tp; 1436ab05f83Stholo 1446ab05f83Stholo ap = (Array *) malloc(sizeof(Array)); 1456ab05f83Stholo tp = (Cell **) calloc(n, sizeof(Cell *)); 1466ab05f83Stholo if (ap == NULL || tp == NULL) 1476ab05f83Stholo ERROR "out of space in makesymtab" FATAL; 1486ab05f83Stholo ap->nelem = 0; 1496ab05f83Stholo ap->size = n; 1506ab05f83Stholo ap->tab = tp; 1516ab05f83Stholo return(ap); 1526ab05f83Stholo } 1536ab05f83Stholo 1546ab05f83Stholo void freesymtab(Cell *ap) /* free a symbol table */ 1556ab05f83Stholo { 1566ab05f83Stholo Cell *cp, *temp; 1576ab05f83Stholo Array *tp; 1586ab05f83Stholo int i; 1596ab05f83Stholo 1606ab05f83Stholo if (!isarr(ap)) 1616ab05f83Stholo return; 1626ab05f83Stholo tp = (Array *) ap->sval; 1636ab05f83Stholo if (tp == NULL) 1646ab05f83Stholo return; 1656ab05f83Stholo for (i = 0; i < tp->size; i++) { 1666ab05f83Stholo for (cp = tp->tab[i]; cp != NULL; cp = temp) { 1676ab05f83Stholo xfree(cp->nval); 1686ab05f83Stholo if (freeable(cp)) 1696ab05f83Stholo xfree(cp->sval); 1706ab05f83Stholo temp = cp->cnext; /* avoids freeing then using */ 17107edfa4aSkstailey free(cp); 1726ab05f83Stholo } 1736ab05f83Stholo tp->tab[i] = 0; 1746ab05f83Stholo } 17507edfa4aSkstailey free(tp->tab); 17607edfa4aSkstailey free(tp); 1776ab05f83Stholo } 1786ab05f83Stholo 1796ab05f83Stholo void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */ 1806ab05f83Stholo { 1816ab05f83Stholo Array *tp; 1826ab05f83Stholo Cell *p, *prev = NULL; 1836ab05f83Stholo int h; 1846ab05f83Stholo 1856ab05f83Stholo tp = (Array *) ap->sval; 1866ab05f83Stholo h = hash(s, tp->size); 1876ab05f83Stholo for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 18807edfa4aSkstailey if (strcmp(s, p->nval) == 0) { 1896ab05f83Stholo if (prev == NULL) /* 1st one */ 1906ab05f83Stholo tp->tab[h] = p->cnext; 1916ab05f83Stholo else /* middle somewhere */ 1926ab05f83Stholo prev->cnext = p->cnext; 1936ab05f83Stholo if (freeable(p)) 1946ab05f83Stholo xfree(p->sval); 1956ab05f83Stholo free(p->nval); 19607edfa4aSkstailey free(p); 1976ab05f83Stholo tp->nelem--; 1986ab05f83Stholo return; 1996ab05f83Stholo } 2006ab05f83Stholo } 2016ab05f83Stholo 2026ab05f83Stholo Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp) 2036ab05f83Stholo { 2046ab05f83Stholo int h; 2056ab05f83Stholo Cell *p; 2066ab05f83Stholo 2076ab05f83Stholo if (n != NULL && (p = lookup(n, tp)) != NULL) { 2086ab05f83Stholo dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", 2096ab05f83Stholo p, p->nval, p->sval, p->fval, p->tval) ); 2106ab05f83Stholo return(p); 2116ab05f83Stholo } 2126ab05f83Stholo p = (Cell *) malloc(sizeof(Cell)); 2136ab05f83Stholo if (p == NULL) 2146ab05f83Stholo ERROR "out of space for symbol table at %s", n FATAL; 2156ab05f83Stholo p->nval = tostring(n); 2166ab05f83Stholo p->sval = s ? tostring(s) : tostring(""); 2176ab05f83Stholo p->fval = f; 2186ab05f83Stholo p->tval = t; 2196ab05f83Stholo p->csub = CUNK; 2206ab05f83Stholo p->ctype = OCELL; 2216ab05f83Stholo tp->nelem++; 2226ab05f83Stholo if (tp->nelem > FULLTAB * tp->size) 2236ab05f83Stholo rehash(tp); 2246ab05f83Stholo h = hash(n, tp->size); 2256ab05f83Stholo p->cnext = tp->tab[h]; 2266ab05f83Stholo tp->tab[h] = p; 2276ab05f83Stholo dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", 2286ab05f83Stholo p, p->nval, p->sval, p->fval, p->tval) ); 2296ab05f83Stholo return(p); 2306ab05f83Stholo } 2316ab05f83Stholo 2326ab05f83Stholo int hash(char *s, int n) /* form hash value for string s */ 2336ab05f83Stholo { 2346ab05f83Stholo unsigned hashval; 2356ab05f83Stholo 2366ab05f83Stholo for (hashval = 0; *s != '\0'; s++) 2376ab05f83Stholo hashval = (*s + 31 * hashval); 2386ab05f83Stholo return hashval % n; 2396ab05f83Stholo } 2406ab05f83Stholo 2416ab05f83Stholo void rehash(Array *tp) /* rehash items in small table into big one */ 2426ab05f83Stholo { 2436ab05f83Stholo int i, nh, nsz; 2446ab05f83Stholo Cell *cp, *op, **np; 2456ab05f83Stholo 2466ab05f83Stholo nsz = GROWTAB * tp->size; 2476ab05f83Stholo np = (Cell **) calloc(nsz, sizeof(Cell *)); 2486ab05f83Stholo if (np == NULL) /* can't do it, but can keep running. */ 2496ab05f83Stholo return; /* someone else will run out later. */ 2506ab05f83Stholo for (i = 0; i < tp->size; i++) { 2516ab05f83Stholo for (cp = tp->tab[i]; cp; cp = op) { 2526ab05f83Stholo op = cp->cnext; 2536ab05f83Stholo nh = hash(cp->nval, nsz); 2546ab05f83Stholo cp->cnext = np[nh]; 2556ab05f83Stholo np[nh] = cp; 2566ab05f83Stholo } 2576ab05f83Stholo } 25807edfa4aSkstailey free(tp->tab); 2596ab05f83Stholo tp->tab = np; 2606ab05f83Stholo tp->size = nsz; 2616ab05f83Stholo } 2626ab05f83Stholo 2636ab05f83Stholo Cell *lookup(char *s, Array *tp) /* look for s in tp */ 2646ab05f83Stholo { 265*271018d0Smillert Cell *p; 2666ab05f83Stholo int h; 2676ab05f83Stholo 2686ab05f83Stholo h = hash(s, tp->size); 269*271018d0Smillert for (p = tp->tab[h]; p != NULL; p = p->cnext) 27007edfa4aSkstailey if (strcmp(s, p->nval) == 0) 2716ab05f83Stholo return(p); /* found it */ 2726ab05f83Stholo return(NULL); /* not found */ 2736ab05f83Stholo } 2746ab05f83Stholo 2756ab05f83Stholo Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 2766ab05f83Stholo { 27707edfa4aSkstailey int fldno; 27807edfa4aSkstailey 2796ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 2806ab05f83Stholo funnyvar(vp, "assign to"); 28107edfa4aSkstailey if (isfld(vp)) { 2826ab05f83Stholo donerec = 0; /* mark $0 invalid */ 28307edfa4aSkstailey fldno = atoi(vp->nval); 28407edfa4aSkstailey if (fldno > *NF) 28507edfa4aSkstailey newfld(fldno); 28607edfa4aSkstailey dprintf( ("setting field %d to %g\n", fldno, f) ); 28707edfa4aSkstailey } else if (isrec(vp)) { 2886ab05f83Stholo donefld = 0; /* mark $1... invalid */ 2896ab05f83Stholo donerec = 1; 2906ab05f83Stholo } 291a4fa8700Smillert if (freeable(vp)) 292a4fa8700Smillert xfree(vp->sval); /* free any previous string */ 2936ab05f83Stholo vp->tval &= ~STR; /* mark string invalid */ 2946ab05f83Stholo vp->tval |= NUM; /* mark number ok */ 2956ab05f83Stholo dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) ); 2966ab05f83Stholo return vp->fval = f; 2976ab05f83Stholo } 2986ab05f83Stholo 2996ab05f83Stholo void funnyvar(Cell *vp, char *rw) 3006ab05f83Stholo { 30107edfa4aSkstailey if (isarr(vp)) 3026ab05f83Stholo ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL; 3036ab05f83Stholo if (vp->tval & FCN) 3046ab05f83Stholo ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL; 3056ab05f83Stholo ERROR "funny variable %p: n=%s s=\"%s\" f=%g t=%o", 3066ab05f83Stholo vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING; 3076ab05f83Stholo } 3086ab05f83Stholo 3096ab05f83Stholo char *setsval(Cell *vp, char *s) /* set string val of a Cell */ 3106ab05f83Stholo { 3116ab05f83Stholo char *t; 31207edfa4aSkstailey int fldno; 3136ab05f83Stholo 31407edfa4aSkstailey dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) ); 3156ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 3166ab05f83Stholo funnyvar(vp, "assign to"); 31707edfa4aSkstailey if (isfld(vp)) { 3186ab05f83Stholo donerec = 0; /* mark $0 invalid */ 31907edfa4aSkstailey fldno = atoi(vp->nval); 32007edfa4aSkstailey if (fldno > *NF) 32107edfa4aSkstailey newfld(fldno); 32207edfa4aSkstailey dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); 32307edfa4aSkstailey } else if (isrec(vp)) { 3246ab05f83Stholo donefld = 0; /* mark $1... invalid */ 3256ab05f83Stholo donerec = 1; 3266ab05f83Stholo } 3276ab05f83Stholo t = tostring(s); /* in case it's self-assign */ 3286ab05f83Stholo vp->tval &= ~NUM; 3296ab05f83Stholo vp->tval |= STR; 3306ab05f83Stholo if (freeable(vp)) 3316ab05f83Stholo xfree(vp->sval); 3326ab05f83Stholo vp->tval &= ~DONTFREE; 3336ab05f83Stholo dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) ); 3346ab05f83Stholo return(vp->sval = t); 3356ab05f83Stholo } 3366ab05f83Stholo 3376ab05f83Stholo Awkfloat getfval(Cell *vp) /* get float val of a Cell */ 3386ab05f83Stholo { 3396ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 3406ab05f83Stholo funnyvar(vp, "read value of"); 34107edfa4aSkstailey if (isfld(vp) && donefld == 0) 3426ab05f83Stholo fldbld(); 34307edfa4aSkstailey else if (isrec(vp) && donerec == 0) 3446ab05f83Stholo recbld(); 3456ab05f83Stholo if (!isnum(vp)) { /* not a number */ 3466ab05f83Stholo vp->fval = atof(vp->sval); /* best guess */ 347a4fa8700Smillert if (is_number(vp->sval) && !(vp->tval&CON)) 3486ab05f83Stholo vp->tval |= NUM; /* make NUM only sparingly */ 3496ab05f83Stholo } 3506ab05f83Stholo dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) ); 3516ab05f83Stholo return(vp->fval); 3526ab05f83Stholo } 3536ab05f83Stholo 3546ab05f83Stholo char *getsval(Cell *vp) /* get string val of a Cell */ 3556ab05f83Stholo { 35607edfa4aSkstailey char s[100]; /* BUG: unchecked */ 3576ab05f83Stholo double dtemp; 3586ab05f83Stholo 3596ab05f83Stholo if ((vp->tval & (NUM | STR)) == 0) 3606ab05f83Stholo funnyvar(vp, "read value of"); 36107edfa4aSkstailey if (isfld(vp) && donefld == 0) 3626ab05f83Stholo fldbld(); 36307edfa4aSkstailey else if (isrec(vp) && donerec == 0) 3646ab05f83Stholo recbld(); 36507edfa4aSkstailey if (isstr(vp) == 0) { 36607edfa4aSkstailey if (freeable(vp)) 3676ab05f83Stholo xfree(vp->sval); 3686ab05f83Stholo if (modf(vp->fval, &dtemp) == 0) /* it's integral */ 36907edfa4aSkstailey sprintf(s, "%.30g", vp->fval); 3706ab05f83Stholo else 37107edfa4aSkstailey sprintf(s, *CONVFMT, vp->fval); 3726ab05f83Stholo vp->sval = tostring(s); 3736ab05f83Stholo vp->tval &= ~DONTFREE; 3746ab05f83Stholo vp->tval |= STR; 3756ab05f83Stholo } 3766ab05f83Stholo dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) ); 3776ab05f83Stholo return(vp->sval); 3786ab05f83Stholo } 3796ab05f83Stholo 3806ab05f83Stholo char *tostring(char *s) /* make a copy of string s */ 3816ab05f83Stholo { 3826ab05f83Stholo char *p; 3836ab05f83Stholo 38407edfa4aSkstailey p = (char *) malloc(strlen(s)+1); 3856ab05f83Stholo if (p == NULL) 3866ab05f83Stholo ERROR "out of space in tostring on %s", s FATAL; 38707edfa4aSkstailey strcpy(p, s); 3886ab05f83Stholo return(p); 3896ab05f83Stholo } 3906ab05f83Stholo 3916ab05f83Stholo char *qstring(char *s, int delim) /* collect string up to next delim */ 3926ab05f83Stholo { 3936ab05f83Stholo int c, n; 39407edfa4aSkstailey char *buf = 0, *bp; 3956ab05f83Stholo 39607edfa4aSkstailey if ((buf = (char *) malloc(strlen(s)+3)) == NULL) 39707edfa4aSkstailey ERROR "out of space in qstring(%s)", s); 39807edfa4aSkstailey for (bp = buf; (c = *s) != delim; s++) { 3996ab05f83Stholo if (c == '\n') 40007edfa4aSkstailey ERROR "newline in string %.10s...", buf SYNTAX; 4016ab05f83Stholo else if (c != '\\') 40207edfa4aSkstailey *bp++ = c; 40307edfa4aSkstailey else { /* \something */ 4046ab05f83Stholo switch (c = *++s) { 40507edfa4aSkstailey case '\\': *bp++ = '\\'; break; 40607edfa4aSkstailey case 'n': *bp++ = '\n'; break; 40707edfa4aSkstailey case 't': *bp++ = '\t'; break; 40807edfa4aSkstailey case 'b': *bp++ = '\b'; break; 40907edfa4aSkstailey case 'f': *bp++ = '\f'; break; 41007edfa4aSkstailey case 'r': *bp++ = '\r'; break; 4116ab05f83Stholo default: 4126ab05f83Stholo if (!isdigit(c)) { 41307edfa4aSkstailey *bp++ = c; 4146ab05f83Stholo break; 4156ab05f83Stholo } 4166ab05f83Stholo n = c - '0'; 4176ab05f83Stholo if (isdigit(s[1])) { 4186ab05f83Stholo n = 8 * n + *++s - '0'; 4196ab05f83Stholo if (isdigit(s[1])) 4206ab05f83Stholo n = 8 * n + *++s - '0'; 4216ab05f83Stholo } 42207edfa4aSkstailey *bp++ = n; 4236ab05f83Stholo break; 4246ab05f83Stholo } 4256ab05f83Stholo } 42607edfa4aSkstailey } 42707edfa4aSkstailey *bp++ = 0; 42807edfa4aSkstailey return buf; 4296ab05f83Stholo } 430