Print this page
3731 Update nawk to version 20121220

*** 22,41 **** /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ ! /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ ! /* All Rights Reserved */ ! ! #pragma ident "%Z%%M% %I% %E% SMI" #define DEBUG ! #include <stdio.h> ! #include <stdlib.h> ! #include <ctype.h> ! #include <string.h> #include "awk.h" #include "y.tab.h" #define FULLTAB 2 /* rehash when table gets this x full */ #define GROWTAB 4 /* grow table by this factor */ --- 22,57 ---- /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ ! /* ! * Copyright (C) Lucent Technologies 1997 ! * All Rights Reserved ! * ! * Permission to use, copy, modify, and distribute this software and ! * its documentation for any purpose and without fee is hereby ! * granted, provided that the above copyright notice appear in all ! * copies and that both that the copyright notice and this ! * permission notice and warranty disclaimer appear in supporting ! * documentation, and that the name Lucent Technologies or any of ! * its entities not be used in advertising or publicity pertaining ! * to distribution of the software without specific, written prior ! * permission. ! * ! * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, ! * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. ! * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY ! * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER ! * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF ! * THIS SOFTWARE. ! */ #define DEBUG ! #include <math.h> #include "awk.h" #include "y.tab.h" #define FULLTAB 2 /* rehash when table gets this x full */ #define GROWTAB 4 /* grow table by this factor */
*** 45,106 **** uchar **FS; /* initial field sep */ uchar **RS; /* initial record sep */ uchar **OFS; /* output field sep */ uchar **ORS; /* output record sep */ uchar **OFMT; /* output format for numbers */ Awkfloat *NF; /* number of fields in current record */ Awkfloat *NR; /* number of current record */ Awkfloat *FNR; /* number of current record in current file */ uchar **FILENAME; /* current filename argument */ Awkfloat *ARGC; /* number of arguments from command line */ uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ Awkfloat *RLENGTH; /* length of same */ ! Cell *recloc; /* location of record */ Cell *nrloc; /* NR */ Cell *nfloc; /* NF */ Cell *fnrloc; /* FNR */ Array *ARGVtab; /* symbol table containing ARGV[...] */ Array *ENVtab; /* symbol table containing ENVIRON[...] */ Cell *rstartloc; /* RSTART */ Cell *rlengthloc; /* RLENGTH */ Cell *symtabloc; /* SYMTAB */ ! Cell *nullloc; Node *nullnode; /* zero&null, converted into a node for comparisons */ static void rehash(Array *); void ! syminit(void) { ! init_buf(&record, &record_size, LINE_INCR); ! ! /* initialize $0 */ ! recloc = getfld(0); ! recloc->nval = (uchar *)"$0"; ! recloc->sval = record; ! recloc->tval = REC|STR|DONTFREE; ! ! symtab = makesymtab(NSYMTAB); ! (void) setsymtab((uchar *)"0", (uchar *)"0", 0.0, NUM|STR|CON|DONTFREE, symtab); /* this is used for if(x)... tests: */ nullloc = setsymtab((uchar *)"$zero&null", (uchar *)"", 0.0, NUM|STR|CON|DONTFREE, symtab); ! nullnode = valtonode(nullloc, CCON); ! FS = &setsymtab((uchar *)"FS", (uchar *)" ", 0.0, ! STR|DONTFREE, symtab)->sval; RS = &setsymtab((uchar *)"RS", (uchar *)"\n", 0.0, STR|DONTFREE, symtab)->sval; OFS = &setsymtab((uchar *)"OFS", (uchar *)" ", 0.0, STR|DONTFREE, symtab)->sval; ORS = &setsymtab((uchar *)"ORS", (uchar *)"\n", 0.0, STR|DONTFREE, symtab)->sval; OFMT = &setsymtab((uchar *)"OFMT", (uchar *)"%.6g", 0.0, STR|DONTFREE, symtab)->sval; FILENAME = &setsymtab((uchar *)"FILENAME", (uchar *)"-", 0.0, STR|DONTFREE, symtab)->sval; nfloc = setsymtab((uchar *)"NF", (uchar *)"", 0.0, NUM, symtab); NF = &nfloc->fval; nrloc = setsymtab((uchar *)"NR", (uchar *)"", 0.0, NUM, symtab); --- 61,119 ---- uchar **FS; /* initial field sep */ uchar **RS; /* initial record sep */ uchar **OFS; /* output field sep */ uchar **ORS; /* output record sep */ uchar **OFMT; /* output format for numbers */ + uchar **CONVFMT; /* format for conversions in getsval */ Awkfloat *NF; /* number of fields in current record */ Awkfloat *NR; /* number of current record */ Awkfloat *FNR; /* number of current record in current file */ uchar **FILENAME; /* current filename argument */ Awkfloat *ARGC; /* number of arguments from command line */ uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ Awkfloat *RLENGTH; /* length of same */ ! Cell *fsloc; /* FS */ Cell *nrloc; /* NR */ Cell *nfloc; /* NF */ Cell *fnrloc; /* FNR */ Array *ARGVtab; /* symbol table containing ARGV[...] */ Array *ENVtab; /* symbol table containing ENVIRON[...] */ Cell *rstartloc; /* RSTART */ Cell *rlengthloc; /* RLENGTH */ Cell *symtabloc; /* SYMTAB */ ! Cell *nullloc; /* a guaranteed empty cell */ Node *nullnode; /* zero&null, converted into a node for comparisons */ + Cell *literal0; static void rehash(Array *); void ! syminit(void) /* initialize symbol table with builtin vars */ { ! literal0 = setsymtab((uchar *)"0", (uchar *)"0", 0.0, NUM|STR|CON|DONTFREE, symtab); /* this is used for if(x)... tests: */ nullloc = setsymtab((uchar *)"$zero&null", (uchar *)"", 0.0, NUM|STR|CON|DONTFREE, symtab); ! nullnode = celltonode(nullloc, CCON); ! ! fsloc = setsymtab((uchar *)"FS", (uchar *)" ", 0.0, ! STR|DONTFREE, symtab); ! FS = &fsloc->sval; RS = &setsymtab((uchar *)"RS", (uchar *)"\n", 0.0, STR|DONTFREE, symtab)->sval; OFS = &setsymtab((uchar *)"OFS", (uchar *)" ", 0.0, STR|DONTFREE, symtab)->sval; ORS = &setsymtab((uchar *)"ORS", (uchar *)"\n", 0.0, STR|DONTFREE, symtab)->sval; OFMT = &setsymtab((uchar *)"OFMT", (uchar *)"%.6g", 0.0, STR|DONTFREE, symtab)->sval; + CONVFMT = &setsymtab((uchar *)"CONVFMT", (uchar *)"%.6g", 0.0, + STR|DONTFREE, symtab)->sval; FILENAME = &setsymtab((uchar *)"FILENAME", (uchar *)"-", 0.0, STR|DONTFREE, symtab)->sval; nfloc = setsymtab((uchar *)"NF", (uchar *)"", 0.0, NUM, symtab); NF = &nfloc->fval; nrloc = setsymtab((uchar *)"NR", (uchar *)"", 0.0, NUM, symtab);
*** 118,146 **** symtabloc = setsymtab((uchar *)"SYMTAB", (uchar *)"", 0.0, ARR, symtab); symtabloc->sval = (uchar *)symtab; } void ! arginit(int ac, uchar *av[]) { Cell *cp; int i; ! uchar temp[11]; - /* first make FILENAME first real argument */ - for (i = 1; i < ac; i++) { - if (!isclvar(av[i])) { - (void) setsval(lookup((uchar *)"FILENAME", symtab), - av[i]); - break; - } - } ARGC = &setsymtab((uchar *)"ARGC", (uchar *)"", (Awkfloat)ac, NUM, symtab)->fval; cp = setsymtab((uchar *)"ARGV", (uchar *)"", 0.0, ARR, symtab); ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ ! cp->sval = (uchar *) ARGVtab; for (i = 0; i < ac; i++) { (void) sprintf((char *)temp, "%d", i); if (is_number(*av)) { (void) setsymtab(temp, *av, atof((const char *)*av), STR|NUM, ARGVtab); --- 131,151 ---- symtabloc = setsymtab((uchar *)"SYMTAB", (uchar *)"", 0.0, ARR, symtab); symtabloc->sval = (uchar *)symtab; } void ! arginit(int ac, uchar *av[]) /* set up ARGV and ARGC */ { Cell *cp; int i; ! uchar temp[50]; ARGC = &setsymtab((uchar *)"ARGC", (uchar *)"", (Awkfloat)ac, NUM, symtab)->fval; cp = setsymtab((uchar *)"ARGV", (uchar *)"", 0.0, ARR, symtab); ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ ! cp->sval = (uchar *)ARGVtab; for (i = 0; i < ac; i++) { (void) sprintf((char *)temp, "%d", i); if (is_number(*av)) { (void) setsymtab(temp, *av, atof((const char *)*av), STR|NUM, ARGVtab);
*** 150,170 **** av++; } } void ! envinit(uchar *envp[]) { Cell *cp; uchar *p; cp = setsymtab((uchar *)"ENVIRON", (uchar *)"", 0.0, ARR, symtab); ENVtab = makesymtab(NSYMTAB); ! cp->sval = (uchar *) ENVtab; for (; *envp; envp++) { if ((p = (uchar *)strchr((char *)*envp, '=')) == NULL) continue; *p++ = 0; /* split into two strings at = */ if (is_number(p)) { (void) setsymtab(*envp, p, atof((const char *)p), STR|NUM, ENVtab); } else { --- 155,177 ---- av++; } } void ! envinit(uchar **envp) /* set up ENVIRON variable */ { Cell *cp; uchar *p; cp = setsymtab((uchar *)"ENVIRON", (uchar *)"", 0.0, ARR, symtab); ENVtab = makesymtab(NSYMTAB); ! cp->sval = (uchar *)ENVtab; for (; *envp; envp++) { if ((p = (uchar *)strchr((char *)*envp, '=')) == NULL) continue; + if (p == *envp) /* no left hand side name in env string */ + continue; *p++ = 0; /* split into two strings at = */ if (is_number(p)) { (void) setsymtab(*envp, p, atof((const char *)p), STR|NUM, ENVtab); } else {
*** 174,226 **** p[-1] = '='; } } Array * ! makesymtab(int n) { Array *ap; Cell **tp; ap = (Array *)malloc(sizeof (Array)); tp = (Cell **)calloc(n, sizeof (Cell *)); if (ap == NULL || tp == NULL) ! ERROR "out of space in makesymtab" FATAL; ap->nelem = 0; ap->size = n; ap->tab = tp; return (ap); } void freesymtab(Cell *ap) /* free symbol table */ { ! Cell *cp, *next; Array *tp; int i; if (!isarr(ap)) return; /*LINTED align*/ tp = (Array *)ap->sval; if (tp == NULL) return; for (i = 0; i < tp->size; i++) { ! for (cp = tp->tab[i]; cp != NULL; cp = next) { ! next = cp->cnext; xfree(cp->nval); if (freeable(cp)) xfree(cp->sval); free(cp); } } free(tp->tab); free(tp); } void ! freeelem(Cell *ap, uchar *s) /* free elem s from ap (i.e., ap["s"] */ { Array *tp; Cell *p, *prev = NULL; int h; --- 181,239 ---- p[-1] = '='; } } Array * ! makesymtab(int n) /* make a new symbol table */ { Array *ap; Cell **tp; ap = (Array *)malloc(sizeof (Array)); tp = (Cell **)calloc(n, sizeof (Cell *)); if (ap == NULL || tp == NULL) ! FATAL("out of space in makesymtab"); ap->nelem = 0; ap->size = n; ap->tab = tp; return (ap); } void freesymtab(Cell *ap) /* free symbol table */ { ! Cell *cp, *temp; Array *tp; int i; if (!isarr(ap)) return; /*LINTED align*/ tp = (Array *)ap->sval; if (tp == NULL) return; for (i = 0; i < tp->size; i++) { ! for (cp = tp->tab[i]; cp != NULL; cp = temp) { xfree(cp->nval); if (freeable(cp)) xfree(cp->sval); + /* avoids freeing then using */ + temp = cp->cnext; free(cp); + tp->nelem--; } + tp->tab[i] = 0; } + if (tp->nelem != 0) + WARNING("can't happen: inconsistent element count freeing %s", + ap->nval); free(tp->tab); free(tp); } void ! freeelem(Cell *ap, const uchar *s) /* free elem s from ap (i.e., ap["s"] */ { Array *tp; Cell *p, *prev = NULL; int h;
*** 241,285 **** return; } } Cell * ! setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned int t, Array *tp) { ! register int h; ! register Cell *p; if (n != NULL && (p = lookup(n, tp)) != NULL) { ! dprintf(("setsymtab found %p: n=%s", (void *)p, p->nval)); ! dprintf((" s=\"%s\" f=%g t=%p\n", ! p->sval, p->fval, (void *)p->tval)); return (p); } p = (Cell *)malloc(sizeof (Cell)); if (p == NULL) ! ERROR "symbol table overflow at %s", n FATAL; p->nval = tostring(n); p->sval = s ? tostring(s) : tostring((uchar *)""); p->fval = f; p->tval = t; ! p->csub = 0; ! tp->nelem++; if (tp->nelem > FULLTAB * tp->size) rehash(tp); h = hash(n, tp->size); p->cnext = tp->tab[h]; tp->tab[h] = p; ! dprintf(("setsymtab set %p: n=%s", (void *)p, p->nval)); ! dprintf((" s=\"%s\" f=%g t=%p\n", p->sval, p->fval, (void *)p->tval)); return (p); } int ! hash(uchar *s, int n) /* form hash value for string s */ { ! register unsigned hashval; for (hashval = 0; *s != '\0'; s++) hashval = (*s + 31 * hashval); return (hashval % n); } --- 254,298 ---- return; } } Cell * ! setsymtab(const uchar *n, const uchar *s, Awkfloat f, unsigned int t, ! Array *tp) { ! int h; ! Cell *p; if (n != NULL && (p = lookup(n, tp)) != NULL) { ! dprintf(("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", ! (void *)p, p->nval, p->sval, p->fval, p->tval)); return (p); } p = (Cell *)malloc(sizeof (Cell)); if (p == NULL) ! FATAL("out of space for symbol table at %s", n); p->nval = tostring(n); p->sval = s ? tostring(s) : tostring((uchar *)""); p->fval = f; p->tval = t; ! p->csub = CUNK; ! p->ctype = OCELL; tp->nelem++; if (tp->nelem > FULLTAB * tp->size) rehash(tp); h = hash(n, tp->size); p->cnext = tp->tab[h]; tp->tab[h] = p; ! dprintf(("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", ! (void *)p, p->nval, p->sval, p->fval, p->tval)); return (p); } int ! hash(const uchar *s, int n) /* form hash value for string s */ { ! unsigned hashval; for (hashval = 0; *s != '\0'; s++) hashval = (*s + 31 * hashval); return (hashval % n); }
*** 290,301 **** int i, nh, nsz; Cell *cp, *op, **np; nsz = GROWTAB * tp->size; np = (Cell **)calloc(nsz, sizeof (Cell *)); ! if (np == NULL) ! ERROR "out of space in rehash" FATAL; for (i = 0; i < tp->size; i++) { for (cp = tp->tab[i]; cp; cp = op) { op = cp->cnext; nh = hash(cp->nval, nsz); cp->cnext = np[nh]; --- 303,314 ---- int i, nh, nsz; Cell *cp, *op, **np; nsz = GROWTAB * tp->size; np = (Cell **)calloc(nsz, sizeof (Cell *)); ! if (np == NULL) /* can't do it, but can keep running. */ ! return; /* someone else will run out later. */ for (i = 0; i < tp->size; i++) { for (cp = tp->tab[i]; cp; cp = op) { op = cp->cnext; nh = hash(cp->nval, nsz); cp->cnext = np[nh];
*** 306,318 **** tp->tab = np; tp->size = nsz; } Cell * ! lookup(uchar *s, Array *tp) /* look for s in tp */ { ! register Cell *p; int h; h = hash(s, tp->size); for (p = tp->tab[h]; p != NULL; p = p->cnext) { if (strcmp((char *)s, (char *)p->nval) == 0) --- 319,331 ---- tp->tab = np; tp->size = nsz; } Cell * ! lookup(const uchar *s, Array *tp) /* look for s in tp */ { ! Cell *p; int h; h = hash(s, tp->size); for (p = tp->tab[h]; p != NULL; p = p->cnext) { if (strcmp((char *)s, (char *)p->nval) == 0)
*** 320,499 **** } return (NULL); /* not found */ } Awkfloat ! setfval(Cell *vp, Awkfloat f) { ! int i; if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "assign to"); ! if (vp->tval & FLD) { donerec = 0; /* mark $0 invalid */ ! i = fldidx(vp); ! if (i > *NF) ! newfld(i); ! dprintf(("setting field %d to %g\n", i, f)); ! } else if (vp->tval & REC) { donefld = 0; /* mark $1... invalid */ donerec = 1; } vp->tval &= ~STR; /* mark string invalid */ vp->tval |= NUM; /* mark number ok */ ! dprintf(("setfval %p: %s = %g, t=%p\n", (void *)vp, ! vp->nval ? vp->nval : (unsigned char *)"NULL", ! f, (void *)vp->tval)); return (vp->fval = f); } void funnyvar(Cell *vp, char *rw) { ! if (vp->tval & ARR) ! ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL; if (vp->tval & FCN) ! ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL; ! ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o", ! vp, vp->nval, vp->sval, vp->fval, vp->tval CONT; } uchar * ! setsval(Cell *vp, uchar *s) { ! int i; if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "assign to"); ! if (vp->tval & FLD) { donerec = 0; /* mark $0 invalid */ ! i = fldidx(vp); ! if (i > *NF) ! newfld(i); ! dprintf(("setting field %d to %s\n", i, s)); ! } else if (vp->tval & REC) { donefld = 0; /* mark $1... invalid */ donerec = 1; } ! vp->tval &= ~NUM; ! vp->tval |= STR; if (freeable(vp)) xfree(vp->sval); vp->tval &= ~DONTFREE; ! dprintf(("setsval %p: %s = \"%s\", t=%p\n", ! (void *)vp, ! vp->nval ? (char *)vp->nval : "", ! s, ! (void *)(vp->tval ? (char *)vp->tval : ""))); ! return (vp->sval = tostring(s)); } Awkfloat ! r_getfval(Cell *vp) { if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "read value of"); ! if ((vp->tval & FLD) && donefld == 0) fldbld(); ! else if ((vp->tval & REC) && donerec == 0) recbld(); if (!isnum(vp)) { /* not a number */ vp->fval = atof((const char *)vp->sval); /* best guess */ ! if (is_number(vp->sval) && !(vp->tval&CON)) vp->tval |= NUM; /* make NUM only sparingly */ } ! dprintf(("getfval %p: %s = %g, t=%p\n", ! (void *)vp, vp->nval, vp->fval, (void *)vp->tval)); return (vp->fval); } ! uchar * ! r_getsval(Cell *vp) { ! uchar s[256]; if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "read value of"); ! if ((vp->tval & FLD) && donefld == 0) fldbld(); ! else if ((vp->tval & REC) && donerec == 0) recbld(); ! if ((vp->tval & STR) == 0) { ! if (!(vp->tval&DONTFREE)) xfree(vp->sval); ! if ((long long)vp->fval == vp->fval) { (void) snprintf((char *)s, sizeof (s), ! "%.20g", vp->fval); } else { /*LINTED*/ (void) snprintf((char *)s, sizeof (s), ! (char *)*OFMT, vp->fval); } vp->sval = tostring(s); vp->tval &= ~DONTFREE; vp->tval |= STR; } ! dprintf(("getsval %p: %s = \"%s\", t=%p\n", ! (void *)vp, ! vp->nval ? (char *)vp->nval : "", ! vp->sval ? (char *)vp->sval : "", ! (void *)vp->tval)); return (vp->sval); } uchar * ! tostring(uchar *s) { ! register uchar *p; p = (uchar *)malloc(strlen((char *)s)+1); if (p == NULL) ! ERROR "out of space in tostring on %s", s FATAL; (void) strcpy((char *)p, (char *)s); return (p); } uchar * ! qstring(uchar *s, int delim) /* collect string up to delim */ { ! uchar *cbuf, *ret; int c, n; ! size_t cbufsz, cnt; ! ! init_buf(&cbuf, &cbufsz, LINE_INCR); ! for (cnt = 0; (c = *s) != delim; s++) { if (c == '\n') { ! ERROR "newline in string %.10s...", cbuf SYNTAX; } else if (c != '\\') { ! expand_buf(&cbuf, &cbufsz, cnt); ! cbuf[cnt++] = c; } else { /* \something */ ! expand_buf(&cbuf, &cbufsz, cnt); ! switch (c = *++s) { ! case '\\': cbuf[cnt++] = '\\'; break; ! case 'n': cbuf[cnt++] = '\n'; break; ! case 't': cbuf[cnt++] = '\t'; break; ! case 'b': cbuf[cnt++] = '\b'; break; ! case 'f': cbuf[cnt++] = '\f'; break; ! case 'r': cbuf[cnt++] = '\r'; break; default: if (!isdigit(c)) { ! cbuf[cnt++] = c; break; } n = c - '0'; if (isdigit(s[1])) { n = 8 * n + *++s - '0'; if (isdigit(s[1])) n = 8 * n + *++s - '0'; } ! cbuf[cnt++] = n; break; } } } ! cbuf[cnt] = '\0'; ! ret = tostring(cbuf); ! free(cbuf); ! return (ret); } --- 333,529 ---- } return (NULL); /* not found */ } Awkfloat ! setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ { ! int fldno; if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "assign to"); ! if (isfld(vp)) { donerec = 0; /* mark $0 invalid */ ! fldno = atoi((char *)vp->nval); ! if (fldno > *NF) ! newfld(fldno); ! dprintf(("setting field %d to %g\n", fldno, f)); ! } else if (isrec(vp)) { donefld = 0; /* mark $1... invalid */ donerec = 1; } + if (freeable(vp)) + xfree(vp->sval); /* free any previous string */ vp->tval &= ~STR; /* mark string invalid */ vp->tval |= NUM; /* mark number ok */ ! if (f == -0) /* who would have thought this possible? */ ! f = 0; ! dprintf(("setfval %p: %s = %g, t=%o\n", (void *)vp, ! vp->nval, f, vp->tval)); return (vp->fval = f); } void funnyvar(Cell *vp, char *rw) { ! if (isarr(vp)) ! FATAL("can't %s %s; it's an array name.", rw, vp->nval); if (vp->tval & FCN) ! FATAL("can't %s %s; it's a function.", rw, vp->nval); ! WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", ! vp, vp->nval, vp->sval, vp->fval, vp->tval); } uchar * ! setsval(Cell *vp, const uchar *s) /* set string val of a Cell */ { ! uchar *t; ! int fldno; + dprintf(("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", + (void*)vp, vp->nval, s, vp->tval, donerec, donefld)); if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "assign to"); ! if (isfld(vp)) { donerec = 0; /* mark $0 invalid */ ! fldno = atoi((const char *)vp->nval); ! if (fldno > *NF) ! newfld(fldno); ! dprintf(("setting field %d to %s (%p)\n", fldno, s, (void *)s)); ! } else if (isrec(vp)) { donefld = 0; /* mark $1... invalid */ donerec = 1; } ! t = tostring(s); /* in case it's self-assign */ if (freeable(vp)) xfree(vp->sval); + vp->tval &= ~NUM; + vp->tval |= STR; vp->tval &= ~DONTFREE; ! dprintf(("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", ! (void *)vp, vp->nval, t, (void *)t, vp->tval, donerec, donefld)); ! return (vp->sval = t); } Awkfloat ! getfval(Cell *vp) /* get float val of a Cell */ { if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "read value of"); ! if (isfld(vp) && donefld == 0) fldbld(); ! else if (isrec(vp) && donerec == 0) recbld(); if (!isnum(vp)) { /* not a number */ vp->fval = atof((const char *)vp->sval); /* best guess */ ! if (is_number(vp->sval) && !(vp->tval & CON)) vp->tval |= NUM; /* make NUM only sparingly */ } ! dprintf(("getfval %p: %s = %g, t=%o\n", ! (void *)vp, vp->nval, vp->fval, vp->tval)); return (vp->fval); } ! static uchar * ! get_str_val(Cell *vp, uchar **fmt) /* get string val of a Cell */ { ! uchar s[100]; /* BUG: unchecked */ ! double dtemp; if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "read value of"); ! if (isfld(vp) && donefld == 0) fldbld(); ! else if (isrec(vp) && donerec == 0) recbld(); ! if (isstr(vp) == 0) { ! if (freeable(vp)) xfree(vp->sval); ! /* it's integral */ ! if (modf((long long)vp->fval, &dtemp) == 0) { (void) snprintf((char *)s, sizeof (s), ! "%.30g", vp->fval); } else { /*LINTED*/ (void) snprintf((char *)s, sizeof (s), ! (char *)*fmt, vp->fval); } vp->sval = tostring(s); vp->tval &= ~DONTFREE; vp->tval |= STR; } ! dprintf(("getsval %p: %s = \"%s (%p)\", t=%o\n", ! (void *)vp, vp->nval, vp->sval, (void *)vp->sval, vp->tval)); return (vp->sval); } uchar * ! getsval(Cell *vp) /* get string val of a Cell */ { ! return (get_str_val(vp, CONVFMT)); ! } ! ! uchar * ! getpssval(Cell *vp) /* get string val of a Cell for print */ ! { ! return (get_str_val(vp, OFMT)); ! } ! ! uchar * ! tostring(const uchar *s) /* make a copy of string s */ ! { ! uchar *p; p = (uchar *)malloc(strlen((char *)s)+1); if (p == NULL) ! FATAL("out of space in tostring on %s", s); (void) strcpy((char *)p, (char *)s); return (p); } uchar * ! qstring(const uchar *is, int delim) /* collect string up to delim */ { ! const uchar *os = is; int c, n; ! uchar *s = (uchar *)is; ! uchar *buf, *bp; ! if ((buf = (uchar *)malloc(strlen((char *)is)+3)) == NULL) ! FATAL("out of space in qstring(%s)", s); ! for (bp = buf; (c = *s) != delim; s++) { if (c == '\n') { ! SYNTAX("newline in string %.20s...", os); } else if (c != '\\') { ! *bp++ = c; } else { /* \something */ ! c = *++s; ! if (c == 0) { /* \ at end */ ! *bp++ = '\\'; ! break; /* for loop */ ! } ! switch (c) { ! case '\\': *bp++ = '\\'; break; ! case 'n': *bp++ = '\n'; break; ! case 't': *bp++ = '\t'; break; ! case 'b': *bp++ = '\b'; break; ! case 'f': *bp++ = '\f'; break; ! case 'r': *bp++ = '\r'; break; default: if (!isdigit(c)) { ! *bp++ = c; break; } n = c - '0'; if (isdigit(s[1])) { n = 8 * n + *++s - '0'; if (isdigit(s[1])) n = 8 * n + *++s - '0'; } ! *bp++ = n; break; } } } ! *bp++ = 0; ! return (buf); }