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);
}