[BACK]Return to tran.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / awk

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: }