601 lines
13 KiB
C
Executable File
601 lines
13 KiB
C
Executable File
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ident "@(#)lib.c 1.8 93/10/19 SMI" /* SVr4.0 2.13 */
|
|
|
|
#define DEBUG
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <libintl.h>
|
|
#include "awk.h"
|
|
#include "y.tab.h"
|
|
|
|
#define getfval(p) (((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
|
|
#define getsval(p) (((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
|
|
|
|
extern Awkfloat r_getfval();
|
|
extern uchar *r_getsval();
|
|
|
|
FILE *infile = NULL;
|
|
uchar *file = (uchar*) "";
|
|
uchar recdata[RECSIZE];
|
|
uchar *record = recdata;
|
|
uchar fields[RECSIZE];
|
|
|
|
#define MAXFLD 200
|
|
int donefld; /* 1 = implies rec broken into fields */
|
|
int donerec; /* 1 = record is valid (no flds have changed) */
|
|
|
|
#define FINIT { OCELL, CFLD, NULL, (uchar*) "", 0.0, FLD|STR|DONTFREE }
|
|
|
|
Cell fldtab[MAXFLD] = { /* room for fields */
|
|
{ OCELL, CFLD, (uchar*) "$0", recdata, 0.0, REC|STR|DONTFREE},
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
|
|
};
|
|
int maxfld = 0; /* last used field */
|
|
int argno = 1; /* current input argument number */
|
|
extern Awkfloat *ARGC;
|
|
extern uchar *getargv();
|
|
|
|
initgetrec()
|
|
{
|
|
int i;
|
|
uchar *p;
|
|
|
|
for (i = 1; i < *ARGC; i++) {
|
|
if (!isclvar(p = getargv(i))) /* find 1st real filename */
|
|
return;
|
|
setclvar(p); /* a commandline assignment before filename */
|
|
argno++;
|
|
}
|
|
infile = stdin; /* no filenames, so use stdin */
|
|
/* *FILENAME = file = (uchar*) "-"; */
|
|
}
|
|
|
|
getrec(buf)
|
|
uchar *buf;
|
|
{
|
|
int c;
|
|
static int firsttime = 1;
|
|
|
|
if (firsttime) {
|
|
firsttime = 0;
|
|
initgetrec();
|
|
}
|
|
dprintf( ("RS=<%s>, FS=<%s>, ARGC=%d, FILENAME=%s\n",
|
|
*RS, *FS, *ARGC, *FILENAME) );
|
|
donefld = 0;
|
|
donerec = 1;
|
|
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 */
|
|
argno++;
|
|
continue;
|
|
}
|
|
if (isclvar(file)) { /* a var=value arg */
|
|
setclvar(file);
|
|
argno++;
|
|
continue;
|
|
}
|
|
*FILENAME = file;
|
|
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;
|
|
setfval(fnrloc, 0.0);
|
|
}
|
|
c = readrec(buf, RECSIZE, infile);
|
|
if (c != 0 || buf[0] != '\0') { /* normal record */
|
|
if (buf == record) {
|
|
if (!(recloc->tval & DONTFREE))
|
|
xfree(recloc->sval);
|
|
recloc->sval = record;
|
|
recloc->tval = REC | STR | DONTFREE;
|
|
if (isnumber(recloc->sval)) {
|
|
recloc->fval = atof(recloc->sval);
|
|
recloc->tval |= NUM;
|
|
}
|
|
}
|
|
setfval(nrloc, nrloc->fval+1);
|
|
setfval(fnrloc, fnrloc->fval+1);
|
|
return 1;
|
|
}
|
|
/* EOF arrived on this file; set up next */
|
|
if (infile != stdin)
|
|
fclose(infile);
|
|
infile = NULL;
|
|
argno++;
|
|
}
|
|
return 0; /* true end of file */
|
|
}
|
|
|
|
readrec(buf, bufsize, inf) /* read one record into buf */
|
|
uchar *buf;
|
|
int bufsize;
|
|
FILE *inf;
|
|
{
|
|
register int sep, c;
|
|
register uchar *rr;
|
|
int count;
|
|
|
|
if ((sep = **RS) == 0) {
|
|
sep = '\n';
|
|
while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
|
|
;
|
|
if (c != EOF)
|
|
ungetc(c, inf);
|
|
}
|
|
for (rr = buf, count = 0; ; ) {
|
|
while ((c=getc(inf)) != sep && c != EOF) {
|
|
count++;
|
|
if (count > bufsize)
|
|
ERROR "input record `%.20s...' too long",
|
|
buf FATAL;
|
|
*rr++ = c;
|
|
}
|
|
if (**RS == sep || c == EOF)
|
|
break;
|
|
if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
|
|
break;
|
|
count += 2;
|
|
if (count > bufsize)
|
|
ERROR "input record `%.20s...' too long", buf FATAL;
|
|
*rr++ = '\n';
|
|
*rr++ = c;
|
|
}
|
|
*rr = 0;
|
|
dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
|
|
return c == EOF && rr == buf ? 0 : 1;
|
|
}
|
|
|
|
uchar *getargv(n) /* get ARGV[n] */
|
|
int n;
|
|
{
|
|
Cell *x;
|
|
uchar *s, temp[10];
|
|
extern Array *ARGVtab;
|
|
|
|
sprintf((char *)temp, "%d", n);
|
|
x = setsymtab(temp, "", 0.0, STR, ARGVtab);
|
|
s = getsval(x);
|
|
dprintf( ("getargv(%d) returns |%s|\n", n, s) );
|
|
return s;
|
|
}
|
|
|
|
setclvar(s) /* set var=value from s */
|
|
uchar *s;
|
|
{
|
|
uchar *p;
|
|
Cell *q;
|
|
|
|
for (p=s; *p != '='; p++)
|
|
;
|
|
*p++ = 0;
|
|
p = qstring(p, '\0');
|
|
q = setsymtab(s, p, 0.0, STR, symtab);
|
|
setsval(q, p);
|
|
if (isnumber(q->sval)) {
|
|
q->fval = atof(q->sval);
|
|
q->tval |= NUM;
|
|
}
|
|
dprintf( ("command line set %s to |%s|\n", s, p) );
|
|
}
|
|
|
|
|
|
fldbld()
|
|
{
|
|
register uchar *r, *fr, sep;
|
|
Cell *p;
|
|
int i;
|
|
|
|
if (donefld)
|
|
return;
|
|
if (!(recloc->tval & STR))
|
|
getsval(recloc);
|
|
r = recloc->sval; /* was record! */
|
|
fr = fields;
|
|
i = 0; /* number of fields accumulated here */
|
|
if (strlen(*FS) > 1) { /* it's a regular expression */
|
|
i = refldbld(r, *FS);
|
|
} else if ((sep = **FS) == ' ') {
|
|
for (i = 0; ; ) {
|
|
while (*r == ' ' || *r == '\t' || *r == '\n')
|
|
r++;
|
|
if (*r == 0)
|
|
break;
|
|
i++;
|
|
if (i >= MAXFLD)
|
|
break;
|
|
if (!(fldtab[i].tval & DONTFREE))
|
|
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;
|
|
} else if (*r != 0) { /* if 0, it's a null field */
|
|
for (;;) {
|
|
i++;
|
|
if (i >= MAXFLD)
|
|
break;
|
|
if (!(fldtab[i].tval & DONTFREE))
|
|
xfree(fldtab[i].sval);
|
|
fldtab[i].sval = fr;
|
|
fldtab[i].tval = FLD | STR | DONTFREE;
|
|
while (*r != sep && *r != '\n' && *r != '\0') /* \n always a separator */
|
|
*fr++ = *r++;
|
|
*fr++ = 0;
|
|
if (*r++ == 0)
|
|
break;
|
|
}
|
|
*fr = 0;
|
|
}
|
|
if (i >= MAXFLD)
|
|
ERROR "record `%.20s...' has too many fields", record FATAL;
|
|
/* clean out junk from previous record */
|
|
cleanfld(i, maxfld);
|
|
maxfld = i;
|
|
donefld = 1;
|
|
for (p = fldtab+1; p <= fldtab+maxfld; p++) {
|
|
if(isnumber(p->sval)) {
|
|
p->fval = atof(p->sval);
|
|
p->tval |= NUM;
|
|
}
|
|
}
|
|
setfval(nfloc, (Awkfloat) maxfld);
|
|
if (dbg)
|
|
for (p = fldtab; p <= fldtab+maxfld; p++)
|
|
printf("field %d: |%s|\n", p-fldtab, p->sval);
|
|
}
|
|
|
|
cleanfld(n1, n2) /* clean out fields n1..n2 inclusive */
|
|
{
|
|
static uchar *nullstat = (uchar *) "";
|
|
register Cell *p, *q;
|
|
|
|
for (p = &fldtab[n2], q = &fldtab[n1]; p > q; p--) {
|
|
if (!(p->tval & DONTFREE))
|
|
xfree(p->sval);
|
|
p->tval = FLD | STR | DONTFREE;
|
|
p->sval = nullstat;
|
|
}
|
|
}
|
|
|
|
newfld(n) /* add field n (after end) */
|
|
{
|
|
if (n >= MAXFLD)
|
|
ERROR "creating too many fields", record FATAL;
|
|
cleanfld(maxfld, n);
|
|
maxfld = n;
|
|
setfval(nfloc, (Awkfloat) n);
|
|
}
|
|
|
|
refldbld(rec, fs) /* build fields from reg expr in FS */
|
|
uchar *rec, *fs;
|
|
{
|
|
fa *makedfa();
|
|
uchar *fr;
|
|
int i, tempstat;
|
|
fa *pfa;
|
|
|
|
fr = fields;
|
|
*fr = '\0';
|
|
if (*rec == '\0')
|
|
return 0;
|
|
pfa = makedfa(fs, 1);
|
|
dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
|
|
tempstat = pfa->initstat;
|
|
for (i = 1; i < MAXFLD; i++) {
|
|
if (!(fldtab[i].tval & DONTFREE))
|
|
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;
|
|
dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
|
|
strncpy(fr, rec, patbeg-rec);
|
|
fr += patbeg - rec + 1;
|
|
*(fr-1) = '\0';
|
|
rec = patbeg + patlen;
|
|
} else {
|
|
dprintf( ("no match %s\n", rec) );
|
|
strcpy(fr, rec);
|
|
pfa->initstat = tempstat;
|
|
break;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
recbld()
|
|
{
|
|
int i;
|
|
register uchar *r, *p;
|
|
static uchar rec[RECSIZE];
|
|
|
|
if (donerec == 1)
|
|
return;
|
|
r = rec;
|
|
for (i = 1; i <= *NF; i++) {
|
|
p = getsval(&fldtab[i]);
|
|
while (*r = *p++)
|
|
r++;
|
|
if (i < *NF)
|
|
for (p = *OFS; *r = *p++; )
|
|
r++;
|
|
}
|
|
*r = '\0';
|
|
dprintf( ("in recbld FS=%o, recloc=%o\n", **FS, recloc) );
|
|
recloc->tval = REC | STR | DONTFREE;
|
|
recloc->sval = record = rec;
|
|
dprintf( ("in recbld FS=%o, recloc=%o\n", **FS, recloc) );
|
|
if (r > record + RECSIZE)
|
|
ERROR "built giant record `%.20s...'", record FATAL;
|
|
dprintf( ("recbld = |%s|\n", record) );
|
|
donerec = 1;
|
|
}
|
|
|
|
Cell *fieldadr(n)
|
|
{
|
|
if (n < 0 || n >= MAXFLD)
|
|
ERROR "trying to access field %d", n FATAL;
|
|
return(&fldtab[n]);
|
|
}
|
|
|
|
int errorflag = 0;
|
|
char errbuf[200];
|
|
|
|
yyerror(s)
|
|
uchar *s;
|
|
{
|
|
extern uchar *cmdname, *curfname;
|
|
static int been_here = 0;
|
|
|
|
if (been_here++ > 2)
|
|
return;
|
|
fprintf(stderr, "%s: %s", cmdname, s);
|
|
fprintf(stderr, gettext(" at source line %d"), lineno);
|
|
if (curfname != NULL)
|
|
fprintf(stderr, gettext(" in function %s"), curfname);
|
|
fprintf(stderr, "\n");
|
|
errorflag = 2;
|
|
eprint();
|
|
}
|
|
|
|
fpecatch()
|
|
{
|
|
ERROR "floating point exception" FATAL;
|
|
}
|
|
|
|
extern int bracecnt, brackcnt, parencnt;
|
|
|
|
bracecheck()
|
|
{
|
|
int c;
|
|
static int beenhere = 0;
|
|
|
|
if (beenhere++)
|
|
return;
|
|
while ((c = input()) != EOF && c != '\0')
|
|
bclass(c);
|
|
bcheck2(bracecnt, '{', '}');
|
|
bcheck2(brackcnt, '[', ']');
|
|
bcheck2(parencnt, '(', ')');
|
|
}
|
|
|
|
bcheck2(n, c1, c2)
|
|
{
|
|
if (n == 1)
|
|
fprintf(stderr, gettext("\tmissing %c\n"), c2);
|
|
else if (n > 1)
|
|
fprintf(stderr, gettext("\t%d missing %c's\n"), n, c2);
|
|
else if (n == -1)
|
|
fprintf(stderr, gettext("\textra %c\n"), c2);
|
|
else if (n < -1)
|
|
fprintf(stderr, gettext("\t%d extra %c's\n"), -n, c2);
|
|
}
|
|
|
|
error(f, s)
|
|
int f;
|
|
char *s;
|
|
{
|
|
extern Node *curnode;
|
|
extern uchar *cmdname;
|
|
|
|
fflush(stdout);
|
|
fprintf(stderr, "%s: ", cmdname);
|
|
fprintf(stderr, "%s", s);
|
|
fprintf(stderr, "\n");
|
|
if (compile_time != 2 && NR && *NR > 0) {
|
|
fprintf(stderr, gettext(" input record number %g"), *FNR);
|
|
if (strcmp(*FILENAME, "-") != 0)
|
|
fprintf(stderr, gettext(", file %s"), *FILENAME);
|
|
fprintf(stderr, "\n");
|
|
}
|
|
if (compile_time != 2 && curnode)
|
|
fprintf(stderr, gettext(" source line number %d\n"),
|
|
curnode->lineno);
|
|
else if (compile_time != 2 && lineno)
|
|
fprintf(stderr, gettext(" source line number %d\n"), lineno);
|
|
eprint();
|
|
if (f) {
|
|
if (dbg)
|
|
abort();
|
|
exit(2);
|
|
}
|
|
}
|
|
|
|
eprint() /* try to print context around error */
|
|
{
|
|
uchar *p, *q;
|
|
int c;
|
|
static int been_here = 0;
|
|
extern uchar ebuf[300], *ep;
|
|
|
|
if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
|
|
return;
|
|
p = ep - 1;
|
|
if (p > ebuf && *p == '\n')
|
|
p--;
|
|
for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
|
|
;
|
|
while (*p == '\n')
|
|
p++;
|
|
fprintf(stderr, gettext(" context is\n\t"));
|
|
for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
|
|
;
|
|
for ( ; p < q; p++)
|
|
if (*p)
|
|
putc(*p, stderr);
|
|
fprintf(stderr, " >>> ");
|
|
for ( ; p < ep; p++)
|
|
if (*p)
|
|
putc(*p, stderr);
|
|
fprintf(stderr, " <<< ");
|
|
if (*ep)
|
|
while ((c = input()) != '\n' && c != '\0' && c != EOF) {
|
|
putc(c, stderr);
|
|
bclass(c);
|
|
}
|
|
putc('\n', stderr);
|
|
ep = ebuf;
|
|
}
|
|
|
|
bclass(c)
|
|
{
|
|
switch (c) {
|
|
case '{': bracecnt++; break;
|
|
case '}': bracecnt--; break;
|
|
case '[': brackcnt++; break;
|
|
case ']': brackcnt--; break;
|
|
case '(': parencnt++; break;
|
|
case ')': parencnt--; break;
|
|
}
|
|
}
|
|
|
|
double errcheck(x, s)
|
|
double x;
|
|
uchar *s;
|
|
{
|
|
extern int errno;
|
|
|
|
if (errno == EDOM) {
|
|
errno = 0;
|
|
ERROR "%s argument out of domain", s WARNING;
|
|
x = 1;
|
|
} else if (errno == ERANGE) {
|
|
errno = 0;
|
|
ERROR "%s result out of range", s WARNING;
|
|
x = 1;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
PUTS(s) uchar *s; {
|
|
dprintf( ("%s\n", s) );
|
|
}
|
|
|
|
isclvar(s) /* is s of form var=something? */
|
|
char *s;
|
|
{
|
|
char *os = s;
|
|
|
|
for ( ; *s; s++)
|
|
if (!(isalnum(*s) || *s == '_'))
|
|
break;
|
|
return *s == '=' && s > os && *(s+1) != '=';
|
|
}
|
|
|
|
#define MAXEXPON 38 /* maximum exponent for fp number */
|
|
|
|
isnumber(s)
|
|
register uchar *s;
|
|
{
|
|
register int d1, d2;
|
|
int point;
|
|
uchar *es;
|
|
|
|
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 != '.')
|
|
return(0);
|
|
if (isdigit(*s)) {
|
|
do {
|
|
d1++;
|
|
s++;
|
|
} while (isdigit(*s));
|
|
}
|
|
if(d1 >= MAXEXPON)
|
|
return(0); /* too many digits to convert */
|
|
if (*s == '.') {
|
|
point++;
|
|
s++;
|
|
}
|
|
if (isdigit(*s)) {
|
|
d2++;
|
|
do {
|
|
s++;
|
|
} while (isdigit(*s));
|
|
}
|
|
if (!(d1 || point && d2))
|
|
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')
|
|
return(1);
|
|
else
|
|
return(0);
|
|
}
|