summaryrefslogtreecommitdiff
path: root/usr/src/cmd/awk/lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/awk/lib.c')
-rw-r--r--usr/src/cmd/awk/lib.c810
1 files changed, 457 insertions, 353 deletions
diff --git a/usr/src/cmd/awk/lib.c b/usr/src/cmd/awk/lib.c
index ded064c6c3..bde265e273 100644
--- a/usr/src/cmd/awk/lib.c
+++ b/usr/src/cmd/awk/lib.c
@@ -1,4 +1,28 @@
/*
+ * 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.
+ */
+
+/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
@@ -27,63 +51,131 @@
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* Copyright (c) Lucent Technologies 1997 */
+/* All Rights Reserved */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
#include "awk.h"
#include "y.tab.h"
-uchar *record;
-size_t record_size;
-
-int donefld; /* 1 = implies rec broken into fields */
-int donerec; /* 1 = record is valid (no flds have changed) */
+static FILE *infile = NULL;
+static char *file = "";
+char *record;
+size_t recsize = RECSIZE;
+static char *fields;
+static size_t fieldssize = RECSIZE;
+static char *rtbuf;
+static size_t rtbufsize = RECSIZE;
-static struct fldtab_chunk {
- struct fldtab_chunk *next;
- Cell fields[FLD_INCR];
-} *fldtab_head, *fldtab_tail;
+Cell **fldtab; /* pointers to Cells */
+char inputFS[100] = " ";
-static size_t fldtab_maxidx;
+#define MAXFLD 2
+int nfields = MAXFLD; /* last allocated slot for $i */
-static FILE *infile = NULL;
-static uchar *file = (uchar*) "";
-static uchar *fields;
-static size_t fields_size = LINE_INCR;
+int donefld; /* 1 = implies rec broken into fields */
+int donerec; /* 1 = record is valid (no flds have changed) */
-static int maxfld = 0; /* last used field */
+static int lastfld = 0; /* last used field */
static int argno = 1; /* current input argument number */
-static uchar *getargv(int);
+static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
+static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
+
+static char *getargv(int);
static void cleanfld(int, int);
-static int refldbld(uchar *, uchar *);
+static int refldbld(const char *, const char *);
static void bcheck2(int, int, int);
static void eprint(void);
static void bclass(int);
+void
+recinit(unsigned int n)
+{
+ if ((record = (char *)malloc(n)) == NULL ||
+ (fields = (char *)malloc(n+2)) == NULL ||
+ (fldtab = (Cell **)malloc((nfields+1) * sizeof (Cell *))) == NULL ||
+ (fldtab[0] = (Cell *)malloc(sizeof (Cell))) == NULL)
+ FATAL("out of space for $0 and fields");
+ *fldtab[0] = dollar0;
+ fldtab[0]->sval = record;
+ fldtab[0]->nval = tostring("0");
+ makefields(1, nfields);
+}
+
+void
+makefields(int n1, int n2) /* create $n1..$n2 inclusive */
+{
+ char temp[50];
+ int i;
+
+ for (i = n1; i <= n2; i++) {
+ fldtab[i] = (Cell *)malloc(sizeof (Cell));
+ if (fldtab[i] == NULL)
+ FATAL("out of space in makefields %d", i);
+ *fldtab[i] = dollar1;
+ (void) sprintf(temp, "%d", i);
+ fldtab[i]->nval = tostring(temp);
+ }
+}
+
static void
initgetrec(void)
{
int i;
- uchar *p;
+ char *p;
for (i = 1; i < *ARGC; i++) {
- if (!isclvar(p = getargv(i))) /* find 1st real filename */
+ p = getargv(i); /* find 1st real filename */
+ if (p == NULL || *p == '\0') { /* deleted or zapped */
+ argno++;
+ continue;
+ }
+ if (!isclvar(p)) {
+ (void) setsval(lookup("FILENAME", symtab), p);
return;
+ }
setclvar(p); /* a commandline assignment before filename */
argno++;
}
infile = stdin; /* no filenames, so use stdin */
- /* *FILENAME = file = (uchar*) "-"; */
}
+/*
+ * POSIX specifies that fields are supposed to be evaluated as if they were
+ * split using the value of FS at the time that the record's value ($0) was
+ * read.
+ *
+ * Since field-splitting is done lazily, we save the current value of FS
+ * whenever a new record is read in (implicitly or via getline), or when
+ * a new value is assigned to $0.
+ */
+void
+savefs(void)
+{
+ if (strlen(getsval(fsloc)) >= sizeof (inputFS))
+ FATAL("field separator %.10s... is too long", *FS);
+ (void) strcpy(inputFS, *FS);
+}
+
+static int firsttime = 1;
+
+/*
+ * get next input record
+ * note: cares whether buf == record
+ */
int
-getrec(uchar **bufp, size_t *bufsizep)
+getrec(char **pbuf, size_t *pbufsize, int isrecord)
{
int c;
- static int firsttime = 1;
- uchar_t *buf, *nbuf;
- size_t len;
+ char *buf = *pbuf;
+ uschar saveb0;
+ size_t bufsize = *pbufsize, savebufsize = bufsize;
if (firsttime) {
firsttime = 0;
@@ -91,17 +183,24 @@ getrec(uchar **bufp, size_t *bufsizep)
}
dprintf(("RS=<%s>, FS=<%s>, ARGC=%f, FILENAME=%s\n",
*RS, *FS, *ARGC, *FILENAME));
- donefld = 0;
- donerec = 1;
+ if (isrecord) {
+ donefld = 0;
+ donerec = 1;
+ savefs();
+ }
+ saveb0 = buf[0];
+ buf[0] = '\0';
while (argno < *ARGC || infile == stdin) {
dprintf(("argno=%d, file=|%s|\n", argno, file));
if (infile == NULL) { /* have to open a new file */
file = getargv(argno);
- if (*file == '\0') { /* it's been zapped */
+ if (file == NULL || *file == '\0') {
+ /* deleted or zapped */
argno++;
continue;
}
- if (isclvar(file)) { /* a var=value arg */
+ if (isclvar(file)) {
+ /* a var=value arg */
setclvar(file);
argno++;
continue;
@@ -110,31 +209,28 @@ getrec(uchar **bufp, size_t *bufsizep)
dprintf(("opening file %s\n", file));
if (*file == '-' && *(file+1) == '\0')
infile = stdin;
- else if ((infile = fopen((char *)file, "r")) == NULL)
- ERROR "can't open file %s", file FATAL;
+ else if ((infile = fopen(file, "rF")) == NULL)
+ FATAL("can't open file %s", file);
(void) setfval(fnrloc, 0.0);
}
- c = readrec(&nbuf, &len, infile);
- expand_buf(bufp, bufsizep, len);
- buf = *bufp;
- (void) memcpy(buf, nbuf, len);
- buf[len] = '\0';
- free(nbuf);
+ c = readrec(&buf, &bufsize, infile);
if (c != 0 || buf[0] != '\0') { /* normal record */
- if (bufp == &record) {
- if (!(recloc->tval & DONTFREE))
+ if (isrecord) {
+ if (freeable(recloc))
xfree(recloc->sval);
- recloc->sval = record;
+ recloc->sval = buf; /* buf == record */
recloc->tval = REC | STR | DONTFREE;
if (is_number(recloc->sval)) {
recloc->fval =
- atof((const char *)recloc->sval);
+ atof(recloc->sval);
recloc->tval |= NUM;
}
}
(void) setfval(nrloc, nrloc->fval+1);
(void) setfval(fnrloc, fnrloc->fval+1);
+ *pbuf = buf;
+ *pbufsize = bufsize;
return (1);
}
/* EOF arrived on this file; set up next */
@@ -143,19 +239,36 @@ getrec(uchar **bufp, size_t *bufsizep)
infile = NULL;
argno++;
}
+ buf[0] = saveb0;
+ *pbuf = buf;
+ *pbufsize = savebufsize;
return (0); /* true end of file */
}
+void
+nextfile(void)
+{
+ if (infile != NULL && infile != stdin)
+ (void) fclose(infile);
+ infile = NULL;
+ argno++;
+}
+
int
-readrec(uchar **bufp, size_t *sizep, FILE *inf) /* read one record into buf */
+readrec(char **pbuf, size_t *pbufsize, FILE *inf) /* read one record into buf */
{
int sep, c;
- uchar *buf;
- int count;
- size_t bufsize;
+ char *rr, *rt, *buf = *pbuf;
+ size_t bufsize = *pbufsize;
+ char *rs = getsval(rsloc);
- init_buf(&buf, &bufsize, LINE_INCR);
- if ((sep = **RS) == 0) {
+ if (rtbuf == NULL && (rtbuf = malloc(rtbufsize)) == NULL)
+ FATAL("out of memory in readrec");
+
+ rr = buf;
+ rt = rtbuf;
+
+ if ((sep = *rs) == '\0') {
sep = '\n';
/* skip leading \n's */
while ((c = getc(inf)) == '\n' && c != EOF)
@@ -163,47 +276,90 @@ readrec(uchar **bufp, size_t *sizep, FILE *inf) /* read one record into buf */
if (c != EOF)
(void) ungetc(c, inf);
}
- count = 0;
- for (;;) {
- while ((c = getc(inf)) != sep && c != EOF) {
- expand_buf(&buf, &bufsize, count);
- buf[count++] = c;
+ while ((c = getc(inf)) != EOF) {
+ if (c != sep) {
+ if (rr-buf+1 > bufsize) {
+ (void) adjbuf(&buf, &bufsize,
+ 1+rr-buf, recsize, &rr, "readrec1");
+ }
+ *rr++ = c;
+ continue;
+ }
+
+ /*
+ * Ensure enough space for either a single separator
+ * character, or at least two '\n' chars (when RS is
+ * the empty string).
+ */
+ (void) adjbuf(&rtbuf, &rtbufsize,
+ 2+rt-rtbuf, recsize, &rt, "readrec2");
+
+ if (*rs == sep) {
+ *rt++ = sep;
+ break;
}
- if (**RS == sep || c == EOF)
+
+ if ((c = getc(inf)) == '\n') { /* 2 in a row */
+ *rt++ = '\n';
+ *rt++ = '\n';
+ while ((c = getc(inf)) == '\n' && c != EOF) {
+ /* Read any further \n's and add them to RT. */
+ (void) adjbuf(&rtbuf, &rtbufsize,
+ 1+rt-rtbuf, recsize, &rt, "readrec3");
+ *rt++ = '\n';
+ }
+ if (c != EOF)
+ (void) ungetc(c, inf);
break;
- if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
+ }
+
+ if (c == EOF) {
+ *rt++ = '\n';
break;
- expand_buf(&buf, &bufsize, count + 1);
- buf[count++] = '\n';
- buf[count++] = c;
+ }
+
+ (void) adjbuf(&buf, &bufsize,
+ 2+rr-buf, recsize, &rr, "readrec4");
+ *rr++ = '\n';
+ *rr++ = c;
}
- buf[count] = '\0';
+ (void) adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec5");
+ (void) adjbuf(&rtbuf, &rtbufsize, 1+rt-rtbuf, recsize, &rt, "readrec6");
+ *rr = '\0';
+ *rt = '\0';
dprintf(("readrec saw <%s>, returns %d\n",
- buf, c == EOF && count == 0 ? 0 : 1));
- *bufp = buf;
- *sizep = count;
- return (c == EOF && count == 0 ? 0 : 1);
+ buf, c == EOF && rr == buf ? 0 : 1));
+ *pbuf = buf;
+ *pbufsize = bufsize;
+ if (c == EOF && rr == buf) {
+ return (0);
+ } else {
+ (void) setsval(rtloc, rtbuf);
+ return (1);
+ }
}
/* get ARGV[n] */
-static uchar *
+static char *
getargv(int n)
{
Cell *x;
- uchar *s, temp[11];
+ char *s, temp[50];
extern Array *ARGVtab;
- (void) sprintf((char *)temp, "%d", n);
- x = setsymtab(temp, (uchar *)"", 0.0, STR, ARGVtab);
+ (void) sprintf(temp, "%d", n);
+ if (lookup(temp, ARGVtab) == NULL)
+ return (NULL);
+ x = setsymtab(temp, "", 0.0, STR, ARGVtab);
s = getsval(x);
dprintf(("getargv(%d) returns |%s|\n", n, s));
return (s);
}
void
-setclvar(uchar *s) /* set var=value from s */
+setclvar(char *s) /* set var=value from s */
{
- uchar *p;
+ char *p;
Cell *q;
for (p = s; *p != '='; p++)
@@ -213,7 +369,7 @@ setclvar(uchar *s) /* set var=value from s */
q = setsymtab(s, p, 0.0, STR, symtab);
(void) setsval(q, p);
if (is_number(q->sval)) {
- q->fval = atof((const char *)q->sval);
+ q->fval = atof(q->sval);
q->tval |= NUM;
}
dprintf(("command line set %s to |%s|\n", s, p));
@@ -221,236 +377,232 @@ setclvar(uchar *s) /* set var=value from s */
}
void
-fldbld(void)
+fldbld(void) /* create fields from current record */
{
- uchar *r, *fr, sep;
+ /* this relies on having fields[] the same length as $0 */
+ /* the fields are all stored in this one array with \0's */
+ /* possibly with a final trailing \0 not associated with any field */
+ char *r, *fr, sep;
Cell *p;
- int i;
- size_t len;
+ int i, j, n;
if (donefld)
return;
- if (!(recloc->tval & STR))
- (void) getsval(recloc);
- r = recloc->sval; /* was record! */
-
- /* make sure fields is always allocated */
- adjust_buf(&fields, fields_size);
-
- /*
- * make sure fields has enough size. We don't expand the buffer
- * in the middle of the loop, since p->sval has already pointed
- * the address in the fields.
- */
- len = strlen((char *)r) + 1;
- expand_buf(&fields, &fields_size, len);
+ if (!isstr(fldtab[0]))
+ (void) getsval(fldtab[0]);
+ r = fldtab[0]->sval;
+ n = strlen(r);
+ if (n > fieldssize) {
+ xfree(fields);
+ /* possibly 2 final \0s */
+ if ((fields = (char *)malloc(n + 2)) == NULL)
+ FATAL("out of space for fields in fldbld %d", n);
+ fieldssize = n;
+ }
fr = fields;
i = 0; /* number of fields accumulated here */
- if (strlen((char *)*FS) > 1) { /* it's a regular expression */
- i = refldbld(r, *FS);
- } else if ((sep = **FS) == ' ') {
+ if (strlen(inputFS) > 1) { /* it's a regular expression */
+ i = refldbld(r, inputFS);
+ } else if ((sep = *inputFS) == ' ') { /* default whitespace */
for (i = 0; ; ) {
while (*r == ' ' || *r == '\t' || *r == '\n')
r++;
- if (*r == 0)
+ if (*r == '\0')
break;
i++;
- p = getfld(i);
- if (!(p->tval & DONTFREE))
- xfree(p->sval);
- p->sval = fr;
- p->tval = FLD | STR | DONTFREE;
+ if (i > nfields)
+ growfldtab(i);
+ if (freeable(fldtab[i]))
+ xfree(fldtab[i]->sval);
+ fldtab[i]->sval = fr;
+ fldtab[i]->tval = FLD | STR | DONTFREE;
do
*fr++ = *r++;
while (*r != ' ' && *r != '\t' && *r != '\n' &&
*r != '\0')
;
- *fr++ = 0;
+ *fr++ = '\0';
+ }
+ *fr = '\0';
+ } else if ((sep = *inputFS) == '\0') {
+ /* new: FS="" => 1 char/field */
+ for (i = 0; *r != '\0'; r++) {
+ char buf[2];
+ i++;
+ if (i > nfields)
+ growfldtab(i);
+ if (freeable(fldtab[i]))
+ xfree(fldtab[i]->sval);
+ buf[0] = *r;
+ buf[1] = '\0';
+ fldtab[i]->sval = tostring(buf);
+ fldtab[i]->tval = FLD | STR;
}
- *fr = 0;
- } else if (*r != 0) { /* if 0, it's a null field */
+ *fr = '\0';
+ } else if (*r != '\0') { /* if 0, it's a null field */
+ /*
+ * subtlecase : if length(FS) == 1 && length(RS > 0)
+ * \n is NOT a field separator (cf awk book 61,84).
+ * this variable is tested in the inner while loop.
+ */
+ int rtest = '\n'; /* normal case */
+ if (strlen(*RS) > 0)
+ rtest = '\0';
for (;;) {
i++;
- p = getfld(i);
- if (!(p->tval & DONTFREE))
- xfree(p->sval);
- p->sval = fr;
- p->tval = FLD | STR | DONTFREE;
- /* \n always a separator */
- while (*r != sep && *r != '\n' && *r != '\0')
+ if (i > nfields)
+ growfldtab(i);
+ if (freeable(fldtab[i]))
+ xfree(fldtab[i]->sval);
+ fldtab[i]->sval = fr;
+ fldtab[i]->tval = FLD | STR | DONTFREE;
+ /* \n is always a separator */
+ while (*r != sep && *r != rtest && *r != '\0')
*fr++ = *r++;
- *fr++ = 0;
- if (*r++ == 0)
+ *fr++ = '\0';
+ if (*r++ == '\0')
break;
}
- *fr = 0;
+ *fr = '\0';
}
+ if (i > nfields)
+ FATAL("record `%.30s...' has too many fields; can't happen", r);
/* clean out junk from previous record */
- cleanfld(i, maxfld);
- maxfld = i;
+ cleanfld(i+1, lastfld);
+ lastfld = i;
donefld = 1;
- for (i = 1; i <= maxfld; i++) {
- p = getfld(i);
+ for (j = 1; j <= lastfld; j++) {
+ p = fldtab[j];
if (is_number(p->sval)) {
- p->fval = atof((const char *)p->sval);
+ p->fval = atof(p->sval);
p->tval |= NUM;
}
}
-
- (void) setfval(nfloc, (Awkfloat) maxfld);
+ (void) setfval(nfloc, (Awkfloat)lastfld);
+ donerec = 1; /* restore */
if (dbg) {
- for (i = 0; i <= maxfld; i++) {
- p = getfld(i);
- (void) printf("field %d: |%s|\n", i, p->sval);
+ for (j = 0; j <= lastfld; j++) {
+ p = fldtab[j];
+ (void) printf("field %d (%s): |%s|\n",
+ j, p->nval, p->sval);
}
}
}
+/* clean out fields n1 .. n2 inclusive; nvals remain intact */
static void
-cleanfld(int n1, int n2) /* clean out fields n1..n2 inclusive */
+cleanfld(int n1, int n2)
{
- static uchar *nullstat = (uchar *) "";
Cell *p;
- int i;
+ int i;
- for (i = n2; i > n1; i--) {
- p = getfld(i);
- if (!(p->tval & DONTFREE))
+ for (i = n1; i <= n2; i++) {
+ p = fldtab[i];
+ if (freeable(p))
xfree(p->sval);
+ p->sval = "";
p->tval = FLD | STR | DONTFREE;
- p->sval = nullstat;
}
}
void
-newfld(int n) /* add field n (after end) */
+newfld(int n) /* add field n after end of existing lastfld */
{
- if (n < 0)
- ERROR "accessing invalid field", record FATAL;
- (void) getfld(n);
- cleanfld(maxfld, n);
- maxfld = n;
- (void) setfval(nfloc, (Awkfloat) n);
+ if (n > nfields)
+ growfldtab(n);
+ cleanfld(lastfld+1, n);
+ lastfld = n;
+ (void) setfval(nfloc, (Awkfloat)n);
}
-/*
- * allocate field table. We don't reallocate the table since there
- * might be somewhere recording the address of the table.
- */
-static void
-morefld(void)
+void
+setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
{
- int i;
- struct fldtab_chunk *fldcp;
- Cell *newfld;
-
- if ((fldcp = calloc(sizeof (struct fldtab_chunk), 1)) == NULL)
- ERROR "out of space in morefld" FATAL;
-
- newfld = &fldcp->fields[0];
- for (i = 0; i < FLD_INCR; i++) {
- newfld[i].ctype = OCELL;
- newfld[i].csub = CFLD;
- newfld[i].nval = NULL;
- newfld[i].sval = (uchar *)"";
- newfld[i].fval = 0.0;
- newfld[i].tval = FLD|STR|DONTFREE;
- newfld[i].cnext = NULL;
- }
- /*
- * link this field chunk
- */
- if (fldtab_head == NULL)
- fldtab_head = fldcp;
+ if (n < 0)
+ FATAL("cannot set NF to a negative value");
+ if (n > nfields)
+ growfldtab(n);
+
+ if (lastfld < n)
+ cleanfld(lastfld+1, n);
else
- fldtab_tail->next = fldcp;
- fldtab_tail = fldcp;
- fldcp->next = NULL;
+ cleanfld(n+1, lastfld);
- fldtab_maxidx += FLD_INCR;
+ lastfld = n;
}
Cell *
-getfld(int idx)
+fieldadr(int n) /* get nth field */
{
- struct fldtab_chunk *fldcp;
- int cbase;
-
- if (idx < 0)
- ERROR "trying to access field %d", idx FATAL;
- while (idx >= fldtab_maxidx)
- morefld();
- cbase = 0;
- for (fldcp = fldtab_head; fldcp != NULL; fldcp = fldcp->next) {
- if (idx < (cbase + FLD_INCR))
- return (&fldcp->fields[idx - cbase]);
- cbase += FLD_INCR;
- }
- /* should never happen */
- ERROR "trying to access invalid field %d", idx FATAL;
- return (NULL);
+ if (n < 0)
+ FATAL("trying to access out of range field %d", n);
+ if (n > nfields) /* fields after NF are empty */
+ growfldtab(n); /* but does not increase NF */
+ return (fldtab[n]);
}
-int
-fldidx(Cell *vp)
+void
+growfldtab(int n) /* make new fields up to at least $n */
{
- struct fldtab_chunk *fldcp;
- Cell *tbl;
- int cbase;
-
- cbase = 0;
- for (fldcp = fldtab_head; fldcp != NULL; fldcp = fldcp->next) {
- tbl = &fldcp->fields[0];
- if (vp >= tbl && vp < (tbl + FLD_INCR))
- return (cbase + (vp - tbl));
- cbase += FLD_INCR;
- }
- /* should never happen */
- ERROR "trying to access unknown field" FATAL;
- return (0);
+ int nf = 2 * nfields;
+ size_t s;
+
+ if (n > nf)
+ nf = n;
+ s = (nf+1) * (sizeof (Cell *)); /* freebsd: how much do we need? */
+ if (s / sizeof (Cell *) - 1 == nf) /* didn't overflow */
+ fldtab = (Cell **)realloc(fldtab, s);
+ else /* overflow sizeof int */
+ xfree(fldtab); /* make it null */
+ if (fldtab == NULL)
+ FATAL("out of space creating %d fields", nf);
+ makefields(nfields+1, nf);
+ nfields = nf;
}
+/* build fields from reg expr in FS */
static int
-refldbld(uchar *rec, uchar *fs) /* build fields from reg expr in FS */
+refldbld(const char *rec, const char *fs)
{
- uchar *fr;
- int i, tempstat;
+ /* this relies on having fields[] the same length as $0 */
+ /* the fields are all stored in this one array with \0's */
+ char *fr;
+ int i, tempstat, n;
fa *pfa;
- Cell *p;
- size_t len;
- /* make sure fields is allocated */
- adjust_buf(&fields, fields_size);
+ n = strlen(rec);
+ if (n > fieldssize) {
+ xfree(fields);
+ if ((fields = (char *)malloc(n+1)) == NULL)
+ FATAL("out of space for fields in refldbld %d", n);
+ fieldssize = n;
+ }
fr = fields;
*fr = '\0';
if (*rec == '\0')
return (0);
-
- len = strlen((char *)rec) + 1;
- expand_buf(&fields, &fields_size, len);
- fr = fields;
-
pfa = makedfa(fs, 1);
dprintf(("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs));
tempstat = pfa->initstat;
for (i = 1; ; i++) {
- p = getfld(i);
- if (!(p->tval & DONTFREE))
- xfree(p->sval);
- p->tval = FLD | STR | DONTFREE;
- p->sval = fr;
+ if (i > nfields)
+ growfldtab(i);
+ if (freeable(fldtab[i]))
+ xfree(fldtab[i]->sval);
+ fldtab[i]->tval = FLD | STR | DONTFREE;
+ fldtab[i]->sval = fr;
dprintf(("refldbld: i=%d\n", i));
if (nematch(pfa, rec)) {
- pfa->initstat = 2;
+ pfa->initstat = 2; /* horrible coupling to b.c */
dprintf(("match %s (%d chars)\n", patbeg, patlen));
- (void) strncpy((char *)fr, (char *)rec, patbeg-rec);
+ (void) strncpy(fr, rec, patbeg-rec);
fr += patbeg - rec + 1;
*(fr-1) = '\0';
rec = patbeg + patlen;
} else {
dprintf(("no match %s\n", rec));
- (void) strcpy((char *)fr, (char *)rec);
+ (void) strcpy(fr, rec);
pfa->initstat = tempstat;
break;
}
@@ -459,71 +611,74 @@ refldbld(uchar *rec, uchar *fs) /* build fields from reg expr in FS */
}
void
-recbld(void)
+recbld(void) /* create $0 from $1..$NF if necessary */
{
int i;
- uchar *p;
+ char *p;
size_t cnt, len, olen;
+ char *sep = getsval(ofsloc);
if (donerec == 1)
return;
cnt = 0;
- olen = strlen((char *)*OFS);
+ olen = strlen(sep);
for (i = 1; i <= *NF; i++) {
- p = getsval(getfld(i));
- len = strlen((char *)p);
- expand_buf(&record, &record_size, cnt + len + olen);
+ p = getsval(fldtab[i]);
+ len = strlen(p);
+ expand_buf(&record, &recsize, cnt + len + olen);
(void) memcpy(&record[cnt], p, len);
cnt += len;
if (i < *NF) {
- (void) memcpy(&record[cnt], *OFS, olen);
+ (void) memcpy(&record[cnt], sep, olen);
cnt += olen;
}
}
record[cnt] = '\0';
- dprintf(("in recbld FS=%o, recloc=%p\n", **FS, (void *)recloc));
- if (!(recloc->tval & DONTFREE))
+ dprintf(("in recbld inputFS=%s, recloc=%p\n", inputFS, (void *)recloc));
+ if (freeable(recloc))
xfree(recloc->sval);
recloc->tval = REC | STR | DONTFREE;
recloc->sval = record;
- dprintf(("in recbld FS=%o, recloc=%p\n", **FS, (void *)recloc));
+ dprintf(("in recbld inputFS=%s, recloc=%p\n", inputFS, (void *)recloc));
dprintf(("recbld = |%s|\n", record));
donerec = 1;
}
-Cell *
-fieldadr(int n)
+int errorflag = 0;
+
+void
+yyerror(const char *s)
{
- if (n < 0)
- ERROR "trying to access field %d", n FATAL;
- return (getfld(n));
+ SYNTAX("%s", s);
}
-int errorflag = 0;
-char errbuf[200];
-
void
-yyerror(char *s)
+SYNTAX(const char *fmt, ...)
{
- extern uchar *cmdname, *curfname;
+ extern char *cmdname, *curfname;
static int been_here = 0;
+ va_list varg;
if (been_here++ > 2)
return;
- (void) fprintf(stderr, "%s: %s", cmdname, s);
- (void) fprintf(stderr, gettext(" at source line %lld"), lineno);
+ (void) fprintf(stderr, "%s: ", cmdname);
+ va_start(varg, fmt);
+ (void) vfprintf(stderr, fmt, varg);
+ va_end(varg);
+ (void) fprintf(stderr, " at source line %lld", lineno);
if (curfname != NULL)
- (void) fprintf(stderr, gettext(" in function %s"), curfname);
+ (void) fprintf(stderr, " in function %s", curfname);
+ if (compile_time == 1 && cursource() != NULL)
+ (void) fprintf(stderr, " source file %s", cursource());
(void) fprintf(stderr, "\n");
errorflag = 2;
eprint();
}
-/*ARGSUSED*/
void
-fpecatch(int sig)
+fpecatch(int n)
{
- ERROR "floating point exception" FATAL;
+ FATAL("floating point exception %d", n);
}
extern int bracecnt, brackcnt, parencnt;
@@ -558,47 +713,74 @@ bcheck2(int n, int c1, int c2)
}
void
-error(int f, char *s)
+FATAL(const char *fmt, ...)
{
- extern Node *curnode;
- extern uchar *cmdname;
+ extern char *cmdname;
+ va_list varg;
+
+ (void) fflush(stdout);
+ (void) fprintf(stderr, "%s: ", cmdname);
+ va_start(varg, fmt);
+ (void) vfprintf(stderr, fmt, varg);
+ va_end(varg);
+ error();
+ if (dbg > 1) /* core dump if serious debugging on */
+ abort();
+ exit(2);
+}
+
+void
+WARNING(const char *fmt, ...)
+{
+ extern char *cmdname;
+ va_list varg;
(void) fflush(stdout);
(void) fprintf(stderr, "%s: ", cmdname);
- (void) fprintf(stderr, "%s", s);
+ va_start(varg, fmt);
+ (void) vfprintf(stderr, fmt, varg);
+ va_end(varg);
+ error();
+}
+
+void
+error(void)
+{
+ extern Node *curnode;
+
(void) fprintf(stderr, "\n");
if (compile_time != 2 && NR && *NR > 0) {
(void) fprintf(stderr,
gettext(" input record number %g"), *FNR);
- if (strcmp((char *)*FILENAME, "-") != 0)
+ if (strcmp(*FILENAME, "-") != 0)
(void) fprintf(stderr, gettext(", file %s"), *FILENAME);
(void) fprintf(stderr, "\n");
}
if (compile_time != 2 && curnode)
- (void) fprintf(stderr, gettext(" source line number %lld\n"),
+ (void) fprintf(stderr, gettext(" source line number %lld"),
curnode->lineno);
else if (compile_time != 2 && lineno) {
(void) fprintf(stderr,
- gettext(" source line number %lld\n"), lineno);
+ gettext(" source line number %lld"), lineno);
}
+ if (compile_time == 1 && cursource() != NULL)
+ (void) fprintf(stderr, gettext(" source file %s"), cursource());
+ (void) fprintf(stderr, "\n");
eprint();
- if (f) {
- if (dbg)
- abort();
- exit(2);
- }
}
static void
eprint(void) /* try to print context around error */
{
- uchar *p, *q;
+ char *p, *q;
int c;
static int been_here = 0;
- extern uchar ebuf[300], *ep;
+ extern char ebuf[], *ep;
if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
return;
+ if (ebuf == ep)
+ return;
p = ep - 1;
if (p > ebuf && *p == '\n')
p--;
@@ -640,30 +822,22 @@ bclass(int c)
}
double
-errcheck(double x, char *s)
+errcheck(double x, const char *s)
{
- extern int errno;
-
if (errno == EDOM) {
errno = 0;
- ERROR "%s argument out of domain", s WARNING;
+ WARNING("%s argument out of domain", s);
x = 1;
} else if (errno == ERANGE) {
errno = 0;
- ERROR "%s result out of range", s WARNING;
+ WARNING("%s result out of range", s);
x = 1;
}
return (x);
}
-void
-PUTS(uchar *s)
-{
- dprintf(("%s\n", s));
-}
-
int
-isclvar(uchar *s) /* is s of form var=something? */
+isclvar(const char *s) /* is s of form var=something ? */
{
if (s != NULL) {
@@ -686,88 +860,28 @@ isclvar(uchar *s) /* is s of form var=something? */
return (0);
}
-#define MAXEXPON 38 /* maximum exponent for fp number */
-
+#include <math.h>
int
-is_number(uchar *s)
+is_number(const char *s)
{
- int d1, d2;
- int point;
- uchar *es;
- extern char radixpoint;
-
- d1 = d2 = point = 0;
- while (*s == ' ' || *s == '\t' || *s == '\n')
- s++;
- if (*s == '\0')
- return (0); /* empty stuff isn't number */
- if (*s == '+' || *s == '-')
- s++;
- if (!isdigit(*s) && *s != radixpoint)
- return (0);
- if (isdigit(*s)) {
- do {
- d1++;
- s++;
- } while (isdigit(*s));
- }
- if (d1 >= MAXEXPON)
- return (0); /* too many digits to convert */
- if (*s == radixpoint) {
- point++;
- s++;
- }
- if (isdigit(*s)) {
- d2++;
- do {
- s++;
- } while (isdigit(*s));
- }
- if (!(d1 || point && d2))
+ double r;
+ char *ep;
+ errno = 0;
+ r = strtod(s, &ep);
+ if (ep == s || r == HUGE_VAL || errno == ERANGE)
return (0);
- if (*s == 'e' || *s == 'E') {
- s++;
- if (*s == '+' || *s == '-')
- s++;
- if (!isdigit(*s))
- return (0);
- es = s;
- do {
- s++;
- } while (isdigit(*s));
- if (s - es > 2) {
- return (0);
- } else if (s - es == 2 &&
- (int)(10 * (*es-'0') + *(es+1)-'0') >= MAXEXPON) {
- return (0);
- }
- }
- while (*s == ' ' || *s == '\t' || *s == '\n')
- s++;
- if (*s == '\0')
+ while (*ep == ' ' || *ep == '\t' || *ep == '\n')
+ ep++;
+ if (*ep == '\0')
return (1);
else
return (0);
}
void
-init_buf(uchar **optr, size_t *sizep, size_t amt)
+r_expand_buf(char **optr, size_t *sizep, size_t req)
{
- uchar *nptr = NULL;
-
- if ((nptr = malloc(amt)) == NULL)
- ERROR "out of space in init_buf" FATAL;
- /* initial buffer should have NULL terminated */
- *nptr = '\0';
- if (sizep != NULL)
- *sizep = amt;
- *optr = nptr;
-}
-
-void
-r_expand_buf(uchar **optr, size_t *sizep, size_t req)
-{
- uchar *nptr;
+ char *nptr;
size_t amt, size = *sizep;
if (size != 0 && req < (size - 1))
@@ -776,20 +890,10 @@ r_expand_buf(uchar **optr, size_t *sizep, size_t req)
amt = (amt / LINE_INCR + 1) * LINE_INCR;
if ((nptr = realloc(*optr, size + amt)) == NULL)
- ERROR "out of space in expand_buf" FATAL;
+ FATAL("out of space in expand_buf");
/* initial buffer should have NULL terminated */
if (size == 0)
*nptr = '\0';
*sizep += amt;
*optr = nptr;
}
-
-void
-adjust_buf(uchar **optr, size_t size)
-{
- uchar *nptr;
-
- if ((nptr = realloc(*optr, size)) == NULL)
- ERROR "out of space in adjust_buf" FATAL;
- *optr = nptr;
-}