version 1.12, 1997/04/07 15:59:56 |
version 1.13, 1997/08/25 16:17:14 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/**************************************************************** |
/**************************************************************** |
Copyright (C) AT&T and Lucent Technologies 1996 |
Copyright (C) Lucent Technologies 1997 |
All Rights Reserved |
All Rights Reserved |
|
|
Permission to use, copy, modify, and distribute this software and |
Permission to use, copy, modify, and distribute this software and |
|
|
granted, provided that the above copyright notice appear in all |
granted, provided that the above copyright notice appear in all |
copies and that both that the copyright notice and this |
copies and that both that the copyright notice and this |
permission notice and warranty disclaimer appear in supporting |
permission notice and warranty disclaimer appear in supporting |
documentation, and that the names of AT&T or Lucent Technologies |
documentation, and that the name Lucent Technologies or any of |
or any of their entities not be used in advertising or publicity |
its entities not be used in advertising or publicity pertaining |
pertaining to distribution of the software without specific, |
to distribution of the software without specific, written prior |
written prior permission. |
permission. |
|
|
AT&T AND LUCENT DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. |
FITNESS. IN NO EVENT SHALL AT&T OR LUCENT OR ANY OF THEIR |
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY |
ENTITIES BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL |
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER |
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR |
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE |
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF |
USE OR PERFORMANCE OF THIS SOFTWARE. |
THIS SOFTWARE. |
****************************************************************/ |
****************************************************************/ |
|
|
#define DEBUG |
#define DEBUG |
|
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <time.h> |
#include <time.h> |
#include "awk.h" |
#include "awk.h" |
#include "awkgram.h" |
#include "ytab.h" |
|
|
#define tempfree(x) if (istemp(x)) tfree(x); else |
#define tempfree(x) if (istemp(x)) tfree(x); else |
|
|
|
|
#endif |
#endif |
|
|
jmp_buf env; |
jmp_buf env; |
|
extern int pairstack[]; |
|
|
#define PA2NUM 29 /* max number of pat,pat patterns allowed */ |
|
int paircnt; /* number of them in use */ |
|
int pairstack[PA2NUM]; /* state of each pat,pat */ |
|
|
|
Node *winner = NULL; /* root of parse tree */ |
Node *winner = NULL; /* root of parse tree */ |
Cell *tmps; /* free temporary cells for execution */ |
Cell *tmps; /* free temporary cells for execution */ |
|
|
|
|
Cell *jexit = &exitcell; |
Cell *jexit = &exitcell; |
static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM }; |
static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM }; |
Cell *jret = &retcell; |
Cell *jret = &retcell; |
static Cell tempcell ={ OCELL, CTEMP, 0, 0, 0.0, NUM }; |
static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE }; |
|
|
Node *curnode = NULL; /* the node being executed, for debugging */ |
Node *curnode = NULL; /* the node being executed, for debugging */ |
|
|
|
/* buffer memory management */ |
|
int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr, |
|
char *whatrtn) |
|
/* pbuf: address of pointer to buffer being managed |
|
* psiz: address of buffer size variable |
|
* minlen: minimum length of buffer needed |
|
* quantum: buffer size quantum |
|
* pbptr: address of movable pointer into buffer, or 0 if none |
|
* whatrtn: name of the calling routine if failure should cause fatal error |
|
* |
|
* return 0 for realloc failure, !=0 for success |
|
*/ |
|
{ |
|
if (minlen > *psiz) { |
|
char *tbuf; |
|
int rminlen = quantum ? minlen % quantum : 0; |
|
int boff = pbptr ? *pbptr - *pbuf : 0; |
|
/* round up to next multiple of quantum */ |
|
if (rminlen) |
|
minlen += quantum - rminlen; |
|
tbuf = realloc(*pbuf, minlen); |
|
if (tbuf == NULL) { |
|
if (whatrtn) |
|
ERROR "out of memory in %s", whatrtn FATAL; |
|
return 0; |
|
} |
|
*pbuf = tbuf; |
|
*psiz = minlen; |
|
if (pbptr) |
|
*pbptr = tbuf + boff; |
|
} |
|
return 1; |
|
} |
|
|
void run(Node *a) /* execution of parse tree starts here */ |
void run(Node *a) /* execution of parse tree starts here */ |
{ |
{ |
execute(a); |
execute(a); |
|
|
curnode = a; |
curnode = a; |
if (isvalue(a)) { |
if (isvalue(a)) { |
x = (Cell *) (a->narg[0]); |
x = (Cell *) (a->narg[0]); |
if ((x->tval & FLD) && !donefld) |
if (isfld(x) && !donefld) |
fldbld(); |
fldbld(); |
else if ((x->tval & REC) && !donerec) |
else if (isrec(x) && !donerec) |
recbld(); |
recbld(); |
return(x); |
return(x); |
} |
} |
|
|
ERROR "illegal statement" FATAL; |
ERROR "illegal statement" FATAL; |
proc = proctab[a->nobj-FIRSTTOKEN]; |
proc = proctab[a->nobj-FIRSTTOKEN]; |
x = (*proc)(a->narg, a->nobj); |
x = (*proc)(a->narg, a->nobj); |
if ((x->tval & FLD) && !donefld) |
if (isfld(x) && !donefld) |
fldbld(); |
fldbld(); |
else if ((x->tval & REC) && !donerec) |
else if (isrec(x) && !donerec) |
recbld(); |
recbld(); |
if (isexpr(a)) |
if (isexpr(a)) |
return(x); |
return(x); |
|
|
tempfree(x); |
tempfree(x); |
} |
} |
if (a[1] || a[2]) |
if (a[1] || a[2]) |
while (getrec(record) > 0) { |
while (getrec(&record, &recsize, 1) > 0) { |
x = execute(a[1]); |
x = execute(a[1]); |
if (isexit(x)) |
if (isexit(x)) |
break; |
break; |
|
|
|
|
Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ |
Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ |
{ |
{ |
static Cell newcopycell = { OCELL, CCOPY, 0, (char *) "", 0.0, NUM|STR|DONTFREE }; |
static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE }; |
int i, ncall, ndef; |
int i, ncall, ndef; |
Node *x; |
Node *x; |
Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn; |
Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */ |
|
Cell *y, *z, *fcn; |
char *s; |
char *s; |
|
|
fcn = execute(a[0]); /* the function itself */ |
fcn = execute(a[0]); /* the function itself */ |
s = fcn->nval; |
s = fcn->nval; |
if (!isfunc(fcn)) |
if (!isfcn(fcn)) |
ERROR "calling undefined function %s", s FATAL; |
ERROR "calling undefined function %s", s FATAL; |
if (frame == NULL) { |
if (frame == NULL) { |
fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame)); |
fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame)); |
|
|
for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ |
for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ |
ncall++; |
ncall++; |
ndef = (int) fcn->fval; /* args in defn */ |
ndef = (int) fcn->fval; /* args in defn */ |
dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) ); |
dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) ); |
if (ncall > ndef) |
if (ncall > ndef) |
ERROR "function %s called with %d args, uses only %d", |
ERROR "function %s called with %d args, uses only %d", |
s, ncall, ndef WARNING; |
s, ncall, ndef WARNING; |
if (ncall + ndef > NARGS) |
if (ncall + ndef > NARGS) |
ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL; |
ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL; |
for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */ |
for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */ |
dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) ); |
dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) ); |
y = execute(x); |
y = execute(x); |
oargs[i] = y; |
oargs[i] = y; |
dprintf( ("args[%d]: %s %f <%s>, t=%o\n", |
dprintf( ("args[%d]: %s %f <%s>, t=%o\n", |
i, y->nval, y->fval, isarr(y) ? "(array)" : (char*) y->sval, y->tval) ); |
i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) ); |
if (isfunc(y)) |
if (isfcn(y)) |
ERROR "can't use function %s as argument in %s", y->nval, s FATAL; |
ERROR "can't use function %s as argument in %s", y->nval, s FATAL; |
if (isarr(y)) |
if (isarr(y)) |
args[i] = y; /* arrays by ref */ |
args[i] = y; /* arrays by ref */ |
|
|
fp->nargs = ndef; /* number defined with (excess are locals) */ |
fp->nargs = ndef; /* number defined with (excess are locals) */ |
fp->retval = gettemp(); |
fp->retval = gettemp(); |
|
|
dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) ); |
dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) ); |
y = execute((Node *)(fcn->sval)); /* execute body */ |
y = execute((Node *)(fcn->sval)); /* execute body */ |
dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) ); |
dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) ); |
|
|
for (i = 0; i < ndef; i++) { |
for (i = 0; i < ndef; i++) { |
Cell *t = fp->args[i]; |
Cell *t = fp->args[i]; |
|
|
return y; |
return y; |
tempfree(y); /* this can free twice! */ |
tempfree(y); /* this can free twice! */ |
z = fp->retval; /* return value */ |
z = fp->retval; /* return value */ |
dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) ); |
dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) ); |
fp--; |
fp--; |
return(z); |
return(z); |
} |
} |
|
|
|
|
y = gettemp(); |
y = gettemp(); |
y->csub = CCOPY; /* prevents freeing until call is over */ |
y->csub = CCOPY; /* prevents freeing until call is over */ |
y->nval = x->nval; |
y->nval = x->nval; /* BUG? */ |
y->sval = x->sval ? tostring(x->sval) : NULL; |
y->sval = x->sval ? tostring(x->sval) : NULL; |
y->fval = x->fval; |
y->fval = x->fval; |
y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */ |
y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */ |
|
|
{ |
{ |
|
|
n = (int) a[0]; /* argument number, counting from 0 */ |
n = (int) a[0]; /* argument number, counting from 0 */ |
dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) ); |
dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) ); |
if (n+1 > fp->nargs) |
if (n+1 > fp->nargs) |
ERROR "argument #%d of function %s was not supplied", |
ERROR "argument #%d of function %s was not supplied", |
n+1, fp->fcncell->nval FATAL; |
n+1, fp->fcncell->nval FATAL; |
|
|
Cell *getline(Node **a, int n) /* get next line from specific input */ |
Cell *getline(Node **a, int n) /* get next line from specific input */ |
{ /* a[0] is variable, a[1] is operator, a[2] is filename */ |
{ /* a[0] is variable, a[1] is operator, a[2] is filename */ |
Cell *r, *x; |
Cell *r, *x; |
char buf[RECSIZE]; |
extern Cell **fldtab; |
FILE *fp; |
FILE *fp; |
|
char *buf; |
|
int bufsize = recsize; |
|
|
|
if ((buf = (char *) malloc(bufsize)) == NULL) |
|
ERROR "out of memory in getline" FATAL; |
|
|
fflush(stdout); /* in case someone is waiting for a prompt */ |
fflush(stdout); /* in case someone is waiting for a prompt */ |
r = gettemp(); |
r = gettemp(); |
if (a[1] != NULL) { /* getline < file */ |
if (a[1] != NULL) { /* getline < file */ |
x = execute(a[2]); /* filename */ |
x = execute(a[2]); /* filename */ |
if ((int) a[1] == '|') /* input pipe */ |
if ((int) a[1] == '|') /* input pipe */ |
a[1] = (Node *) LE; /* arbitrary flag */ |
a[1] = (Node *) LE; /* arbitrary flag */ |
fp = openfile((int) a[1], getsval(x)); |
fp = openfile((int) a[1], getsval(x)); |
tempfree(x); |
tempfree(x); |
if (fp == NULL) |
if (fp == NULL) |
n = -1; |
n = -1; |
else |
else |
n = readrec(buf, sizeof(buf), fp); |
n = readrec(&buf, &bufsize, fp); |
if (n <= 0) { |
if (n <= 0) { |
; |
; |
} else if (a[0] != NULL) { /* getline var <file */ |
} else if (a[0] != NULL) { /* getline var <file */ |
setsval(execute(a[0]), buf); |
x = execute(a[0]); |
|
setsval(x, buf); |
|
tempfree(x); |
} else { /* getline <file */ |
} else { /* getline <file */ |
if (!(recloc->tval & DONTFREE)) |
setsval(fldtab[0], buf); |
xfree(recloc->sval); |
if (isnumber(fldtab[0]->sval)) { |
strcpy(record, buf); |
fldtab[0]->fval = atof(fldtab[0]->sval); |
recloc->sval = record; |
fldtab[0]->tval |= NUM; |
recloc->tval = REC | STR | DONTFREE; |
|
if (isnumber(recloc->sval)) { |
|
recloc->fval = atof(recloc->sval); |
|
recloc->tval |= NUM; |
|
} |
} |
donerec = 1; donefld = 0; |
|
} |
} |
} else { /* bare getline; use current input */ |
} else { /* bare getline; use current input */ |
if (a[0] == NULL) /* getline */ |
if (a[0] == NULL) /* getline */ |
n = getrec(record); |
n = getrec(&record, &recsize, 1); |
else { /* getline var */ |
else { /* getline var */ |
n = getrec(buf); |
n = getrec(&buf, &bufsize, 0); |
setsval(execute(a[0]), buf); |
x = execute(a[0]); |
|
setsval(x, buf); |
|
tempfree(x); |
} |
} |
} |
} |
setfval(r, (Awkfloat) n); |
setfval(r, (Awkfloat) n); |
|
free(buf); |
return r; |
return r; |
} |
} |
|
|
|
|
Cell *x, *y, *z; |
Cell *x, *y, *z; |
char *s; |
char *s; |
Node *np; |
Node *np; |
char buf[RECSIZE]; |
char *buf; |
|
int bufsz = recsize; |
|
int nsub = strlen(*SUBSEP); |
|
|
|
if ((buf = malloc(bufsz)) == NULL) |
|
ERROR "out of memory in array" FATAL; |
|
|
x = execute(a[0]); /* Cell* for symbol table */ |
x = execute(a[0]); /* Cell* for symbol table */ |
buf[0] = 0; |
buf[0] = 0; |
for (np = a[1]; np; np = np->nnext) { |
for (np = a[1]; np; np = np->nnext) { |
y = execute(np); /* subscript */ |
y = execute(np); /* subscript */ |
s = getsval(y); |
s = getsval(y); |
strcat(buf, s); /* BUG: unchecked! */ |
if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) |
|
ERROR "out of memory for %s[%s...]", x->nval, buf FATAL; |
|
strcat(buf, s); |
if (np->nnext) |
if (np->nnext) |
strcat(buf, *SUBSEP); |
strcat(buf, *SUBSEP); |
tempfree(y); |
tempfree(y); |
} |
} |
if (!isarr(x)) { |
if (!isarr(x)) { |
dprintf( ("making %s into an array\n", x->nval) ); |
dprintf( ("making %s into an array\n", x->nval) ); |
if (freeable(x)) |
if (freeable(x)) |
xfree(x->sval); |
xfree(x->sval); |
x->tval &= ~(STR|NUM|DONTFREE); |
x->tval &= ~(STR|NUM|DONTFREE); |
|
|
z->ctype = OCELL; |
z->ctype = OCELL; |
z->csub = CVAR; |
z->csub = CVAR; |
tempfree(x); |
tempfree(x); |
|
free(buf); |
return(z); |
return(z); |
} |
} |
|
|
|
|
{ |
{ |
Cell *x, *y; |
Cell *x, *y; |
Node *np; |
Node *np; |
char buf[RECSIZE], *s; |
char *s; |
|
int nsub = strlen(*SUBSEP); |
|
|
x = execute(a[0]); /* Cell* for symbol table */ |
x = execute(a[0]); /* Cell* for symbol table */ |
if (!isarr(x)) |
if (!isarr(x)) |
|
|
x->tval |= ARR; |
x->tval |= ARR; |
x->sval = (char *) makesymtab(NSYMTAB); |
x->sval = (char *) makesymtab(NSYMTAB); |
} else { |
} else { |
|
int bufsz = recsize; |
|
char *buf; |
|
if ((buf = malloc(bufsz)) == NULL) |
|
ERROR "out of memory in adelete" FATAL; |
buf[0] = 0; |
buf[0] = 0; |
for (np = a[1]; np; np = np->nnext) { |
for (np = a[1]; np; np = np->nnext) { |
y = execute(np); /* subscript */ |
y = execute(np); /* subscript */ |
s = getsval(y); |
s = getsval(y); |
strcat(buf, s); |
if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) |
|
ERROR "out of memory deleting %s[%s...]", x->nval, buf FATAL; |
|
strcat(buf, s); |
if (np->nnext) |
if (np->nnext) |
strcat(buf, *SUBSEP); |
strcat(buf, *SUBSEP); |
tempfree(y); |
tempfree(y); |
} |
} |
freeelem(x, buf); |
freeelem(x, buf); |
|
free(buf); |
} |
} |
tempfree(x); |
tempfree(x); |
return true; |
return true; |
|
|
{ |
{ |
Cell *x, *ap, *k; |
Cell *x, *ap, *k; |
Node *p; |
Node *p; |
char buf[RECSIZE]; |
char *buf; |
char *s; |
char *s; |
|
int bufsz = recsize; |
|
int nsub = strlen(*SUBSEP); |
|
|
ap = execute(a[1]); /* array name */ |
ap = execute(a[1]); /* array name */ |
if (!isarr(ap)) { |
if (!isarr(ap)) { |
dprintf( ("making %s into an array\n", ap->nval) ); |
dprintf( ("making %s into an array\n", ap->nval) ); |
if (freeable(ap)) |
if (freeable(ap)) |
xfree(ap->sval); |
xfree(ap->sval); |
ap->tval &= ~(STR|NUM|DONTFREE); |
ap->tval &= ~(STR|NUM|DONTFREE); |
ap->tval |= ARR; |
ap->tval |= ARR; |
ap->sval = (char *) makesymtab(NSYMTAB); |
ap->sval = (char *) makesymtab(NSYMTAB); |
} |
} |
|
if ((buf = malloc(bufsz)) == NULL) { |
|
ERROR "out of memory in intest" FATAL; |
|
} |
buf[0] = 0; |
buf[0] = 0; |
for (p = a[0]; p; p = p->nnext) { |
for (p = a[0]; p; p = p->nnext) { |
x = execute(p); /* expr */ |
x = execute(p); /* expr */ |
s = getsval(x); |
s = getsval(x); |
|
if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) |
|
ERROR "out of memory deleting %s[%s...]", x->nval, buf FATAL; |
strcat(buf, s); |
strcat(buf, s); |
tempfree(x); |
tempfree(x); |
if (p->nnext) |
if (p->nnext) |
|
|
} |
} |
k = lookup(buf, (Array *) ap->sval); |
k = lookup(buf, (Array *) ap->sval); |
tempfree(ap); |
tempfree(ap); |
|
free(buf); |
if (k == NULL) |
if (k == NULL) |
return(false); |
return(false); |
else |
else |
|
|
|
|
void tfree(Cell *a) /* free a tempcell */ |
void tfree(Cell *a) /* free a tempcell */ |
{ |
{ |
if (freeable(a)) |
if (freeable(a)) { |
|
dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) ); |
xfree(a->sval); |
xfree(a->sval); |
|
} |
if (a == tmps) |
if (a == tmps) |
ERROR "tempcell list is curdled" FATAL; |
ERROR "tempcell list is curdled" FATAL; |
a->cnext = tmps; |
a->cnext = tmps; |
|
|
m = getfval(x); |
m = getfval(x); |
if (m == 0 && !isnumber(s = getsval(x))) /* suspicion! */ |
if (m == 0 && !isnumber(s = getsval(x))) /* suspicion! */ |
ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL; |
ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL; |
/* can x->nval ever be null??? */ |
/* BUG: can x->nval ever be null??? */ |
/* ERROR "illegal field $(%s)", s FATAL; */ |
|
tempfree(x); |
tempfree(x); |
x = fieldadr(m); |
x = fieldadr(m); |
x->ctype = OCELL; |
x->ctype = OCELL; /* BUG? why are these needed? */ |
x->csub = CFLD; |
x->csub = CFLD; |
return(x); |
return(x); |
} |
} |
|
|
n = 0; |
n = 0; |
else if (n > k - m) |
else if (n > k - m) |
n = k - m; |
n = k - m; |
dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) ); |
dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) ); |
y = gettemp(); |
y = gettemp(); |
temp = s[n+m-1]; /* with thanks to John Linderman */ |
temp = s[n+m-1]; /* with thanks to John Linderman */ |
s[n+m-1] = '\0'; |
s[n+m-1] = '\0'; |
|
|
return(z); |
return(z); |
} |
} |
|
|
/* |
#define MAXNUMSIZE 50 |
* printf-like conversions |
|
* returns len of buf or -1 on error |
int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversions */ |
*/ |
|
int format(char *buf, int bufsize, char *s, Node *a) |
|
{ |
{ |
char fmt[RECSIZE]; |
char *fmt; |
char *p, *t, *os; |
char *p, *t, *os; |
Cell *x; |
Cell *x; |
int flag = 0, n; |
int flag = 0, n; |
|
int fmtwd; /* format width */ |
|
int fmtsz = recsize; |
|
char *buf = *pbuf; |
|
int bufsize = *pbufsize; |
|
|
os = s; |
os = s; |
p = buf; |
p = buf; |
|
if ((fmt = malloc(fmtsz)) == NULL) |
|
ERROR "out of memory in format()" FATAL; |
while (*s) { |
while (*s) { |
if (p - buf >= bufsize) |
adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format"); |
return -1; |
|
if (*s != '%') { |
if (*s != '%') { |
*p++ = *s++; |
*p++ = *s++; |
continue; |
continue; |
|
|
s += 2; |
s += 2; |
continue; |
continue; |
} |
} |
for (t=fmt; (*t++ = *s) != '\0'; s++) { |
/* have to be real careful in case this is a huge number, eg, %100000d */ |
|
fmtwd = atoi(s+1); |
|
if (fmtwd < 0) |
|
fmtwd = -fmtwd; |
|
adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); |
|
for (t = fmt; (*t++ = *s) != '\0'; s++) { |
|
if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0)) |
|
ERROR "format item %.30s... ran format() out of memory", os FATAL; |
if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L') |
if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L') |
break; /* the ansi panoply */ |
break; /* the ansi panoply */ |
if (*s == '*') { |
if (*s == '*') { |
x = execute(a); |
x = execute(a); |
a = a->nnext; |
a = a->nnext; |
sprintf((char *)t-1, "%d", (int) getfval(x)); |
sprintf(t-1, "%d", fmtwd=(int) getfval(x)); |
|
if (fmtwd < 0) |
|
fmtwd = -fmtwd; |
|
adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); |
t = fmt + strlen(fmt); |
t = fmt + strlen(fmt); |
tempfree(x); |
tempfree(x); |
} |
} |
} |
} |
*t = '\0'; |
*t = '\0'; |
if (t >= fmt + sizeof(fmt)) |
if (fmtwd < 0) |
ERROR "format item %.30s... too long", os FATAL; |
fmtwd = -fmtwd; |
|
adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); |
|
|
switch (*s) { |
switch (*s) { |
case 'f': case 'e': case 'g': case 'E': case 'G': |
case 'f': case 'e': case 'g': case 'E': case 'G': |
flag = 1; |
flag = 1; |
|
|
ERROR "not enough args in printf(%s)", os FATAL; |
ERROR "not enough args in printf(%s)", os FATAL; |
x = execute(a); |
x = execute(a); |
a = a->nnext; |
a = a->nnext; |
|
n = MAXNUMSIZE; |
|
if (fmtwd > n) |
|
n = fmtwd; |
|
adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format"); |
switch (flag) { |
switch (flag) { |
case 0: sprintf((char *)p, "%s", fmt); /* unknown, so dump it too */ |
case 0: sprintf(p, "%s", fmt); /* unknown, so dump it too */ |
|
t = getsval(x); |
|
n = strlen(t); |
|
if (fmtwd > n) |
|
n = fmtwd; |
|
adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format"); |
p += strlen(p); |
p += strlen(p); |
sprintf((char *)p, "%s", getsval(x)); |
sprintf(p, "%s", t); |
break; |
break; |
case 1: sprintf((char *)p, (char *)fmt, getfval(x)); break; |
case 1: sprintf(p, fmt, getfval(x)); break; |
case 2: sprintf((char *)p, (char *)fmt, (long) getfval(x)); break; |
case 2: sprintf(p, fmt, (long) getfval(x)); break; |
case 3: sprintf((char *)p, (char *)fmt, (int) getfval(x)); break; |
case 3: sprintf(p, fmt, (int) getfval(x)); break; |
case 4: |
case 4: |
t = getsval(x); |
t = getsval(x); |
n = strlen(t); |
n = strlen(t); |
if (n >= bufsize) |
if (fmtwd > n) |
ERROR "huge string (%d chars) in printf %.30s...", |
n = fmtwd; |
n, t FATAL; |
if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0)) |
sprintf((char *)p, (char *)fmt, t); |
ERROR "huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t FATAL; |
|
sprintf(p, fmt, t); |
break; |
break; |
case 5: |
case 5: |
isnum(x) ? |
if (isnum(x)) { |
(getfval(x) ? |
if (getfval(x)) |
sprintf((char *)p, (char *)fmt, (int) getfval(x)) |
sprintf(p, fmt, (int) getfval(x)); |
: (*p++ = '\0')) |
else |
: sprintf((char *)p, (char *)fmt, getsval(x)[0]); |
*p++ = '\0'; |
|
} else |
|
sprintf(p, fmt, getsval(x)[0]); |
break; |
break; |
} |
} |
tempfree(x); |
tempfree(x); |
|
|
s++; |
s++; |
} |
} |
*p = '\0'; |
*p = '\0'; |
|
free(fmt); |
for ( ; a; a = a->nnext) /* evaluate any remaining args */ |
for ( ; a; a = a->nnext) /* evaluate any remaining args */ |
execute(a); |
execute(a); |
return ((int)(p - buf)); |
*pbuf = buf; |
|
*pbufsize = bufsize; |
|
return p - buf; |
} |
} |
|
|
Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */ |
Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */ |
{ |
{ |
Cell *x; |
Cell *x; |
Node *y; |
Node *y; |
char buf[3*RECSIZE]; |
char *buf; |
|
int bufsz=3*recsize; |
|
|
|
if ((buf=malloc(bufsz)) == NULL) |
|
ERROR "out of memory in awksprintf" FATAL; |
y = a[0]->nnext; |
y = a[0]->nnext; |
x = execute(a[0]); |
x = execute(a[0]); |
if (format(buf, sizeof buf, getsval(x), y) == -1) |
if (format(&buf, &bufsz, getsval(x), y) == -1) |
ERROR "sprintf string %.30s... too long", buf FATAL; |
ERROR "sprintf string %.30s... too long. can't happen.", buf FATAL; |
tempfree(x); |
tempfree(x); |
x = gettemp(); |
x = gettemp(); |
x->sval = tostring(buf); |
x->sval = buf; |
x->tval = STR; |
x->tval = STR; |
return(x); |
return(x); |
} |
} |
|
|
FILE *fp; |
FILE *fp; |
Cell *x; |
Cell *x; |
Node *y; |
Node *y; |
char buf[3*RECSIZE]; |
char *buf; |
int len; |
int len; |
|
int bufsz=3*recsize; |
|
|
|
if ((buf=malloc(bufsz)) == NULL) |
|
ERROR "out of memory in awkprintf" FATAL; |
y = a[0]->nnext; |
y = a[0]->nnext; |
x = execute(a[0]); |
x = execute(a[0]); |
if ((len = format(buf, sizeof buf, getsval(x), y)) == -1) |
if ((len = format(&buf, &bufsz, getsval(x), y)) == -1) |
ERROR "printf string %.30s... too long", buf FATAL; |
ERROR "printf string %.30s... too long. can't happen.", buf FATAL; |
tempfree(x); |
tempfree(x); |
if (a[1] == NULL) { |
if (a[1] == NULL) { |
|
/* fputs(buf, stdout); */ |
fwrite(buf, len, 1, stdout); |
fwrite(buf, len, 1, stdout); |
if (ferror(stdout)) |
if (ferror(stdout)) |
ERROR "write error on stdout" FATAL; |
ERROR "write error on stdout" FATAL; |
} else { |
} else { |
fp = redirect((int)a[1], a[2]); |
fp = redirect((int)a[1], a[2]); |
|
/* fputs(buf, fp); */ |
fwrite(buf, len, 1, fp); |
fwrite(buf, len, 1, fp); |
fflush(fp); |
fflush(fp); |
if (ferror(fp)) |
if (ferror(fp)) |
ERROR "write error on %s", filename(fp) FATAL; |
ERROR "write error on %s", filename(fp) FATAL; |
} |
} |
|
free(buf); |
return(true); |
return(true); |
} |
} |
|
|
|
|
x->fval = getfval(y); |
x->fval = getfval(y); |
x->tval |= NUM; |
x->tval |= NUM; |
} |
} |
else if (y->tval & STR) |
else if (isstr(y)) |
setsval(x, getsval(y)); |
setsval(x, getsval(y)); |
else if (y->tval & NUM) |
else if (isnum(y)) |
setfval(x, getfval(y)); |
setfval(x, getfval(y)); |
else |
else |
funnyvar(y, "read value of"); |
funnyvar(y, "read value of"); |
|
|
Cell *x = 0, *y, *ap; |
Cell *x = 0, *y, *ap; |
char *s; |
char *s; |
int sep; |
int sep; |
char *t, temp, num[10], *fs = 0; |
char *t, temp, num[50], *fs = 0; |
int n, tempstat; |
int n, tempstat; |
|
|
y = execute(a[0]); /* source string */ |
y = execute(a[0]); /* source string */ |
|
|
x = execute(a[2]); |
x = execute(a[2]); |
fs = getsval(x); |
fs = getsval(x); |
} else if ((int) a[3] == REGEXPR) |
} else if ((int) a[3] == REGEXPR) |
fs = (char*) "(regexpr)"; /* split(str,arr,/regexpr/) */ |
fs = "(regexpr)"; /* split(str,arr,/regexpr/) */ |
else |
else |
ERROR "illegal type of split()" FATAL; |
ERROR "illegal type of split" FATAL; |
sep = *fs; |
sep = *fs; |
ap = execute(a[1]); /* array name */ |
ap = execute(a[1]); /* array name */ |
freesymtab(ap); |
freesymtab(ap); |
dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) ); |
dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) ); |
ap->tval &= ~STR; |
ap->tval &= ~STR; |
ap->tval |= ARR; |
ap->tval |= ARR; |
ap->sval = (char *) makesymtab(NSYMTAB); |
ap->sval = (char *) makesymtab(NSYMTAB); |
|
|
pfa->initstat = 2; |
pfa->initstat = 2; |
do { |
do { |
n++; |
n++; |
sprintf((char *)num, "%d", n); |
sprintf(num, "%d", n); |
temp = *patbeg; |
temp = *patbeg; |
*patbeg = '\0'; |
*patbeg = '\0'; |
if (isnumber(s)) |
if (isnumber(s)) |
setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval); |
setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval); |
else |
else |
setsymtab(num, s, 0.0, STR, (Array *) ap->sval); |
setsymtab(num, s, 0.0, STR, (Array *) ap->sval); |
*patbeg = temp; |
*patbeg = temp; |
s = patbeg + patlen; |
s = patbeg + patlen; |
if (*(patbeg+patlen-1) == 0 || *s == 0) { |
if (*(patbeg+patlen-1) == 0 || *s == 0) { |
n++; |
n++; |
sprintf((char *)num, "%d", n); |
sprintf(num, "%d", n); |
setsymtab(num, "", 0.0, STR, (Array *) ap->sval); |
setsymtab(num, "", 0.0, STR, (Array *) ap->sval); |
pfa->initstat = tempstat; |
pfa->initstat = tempstat; |
goto spdone; |
goto spdone; |
|
|
} while (nematch(pfa,s)); |
} while (nematch(pfa,s)); |
} |
} |
n++; |
n++; |
sprintf((char *)num, "%d", n); |
sprintf(num, "%d", n); |
if (isnumber(s)) |
if (isnumber(s)) |
setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval); |
setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval); |
else |
else |
setsymtab(num, s, 0.0, STR, (Array *) ap->sval); |
setsymtab(num, s, 0.0, STR, (Array *) ap->sval); |
spdone: |
spdone: |
|
|
while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0'); |
while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0'); |
temp = *s; |
temp = *s; |
*s = '\0'; |
*s = '\0'; |
sprintf((char *)num, "%d", n); |
sprintf(num, "%d", n); |
if (isnumber(t)) |
if (isnumber(t)) |
setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval); |
setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); |
else |
else |
setsymtab(num, t, 0.0, STR, (Array *) ap->sval); |
setsymtab(num, t, 0.0, STR, (Array *) ap->sval); |
*s = temp; |
*s = temp; |
|
|
for (n = 0; *s != 0; s++) { |
for (n = 0; *s != 0; s++) { |
char buf[2]; |
char buf[2]; |
n++; |
n++; |
sprintf((char *)num, "%d", n); |
sprintf(num, "%d", n); |
buf[0] = *s; |
buf[0] = *s; |
buf[1] = 0; |
buf[1] = 0; |
if (isdigit(buf[0])) |
if (isdigit(buf[0])) |
|
|
s++; |
s++; |
temp = *s; |
temp = *s; |
*s = '\0'; |
*s = '\0'; |
sprintf((char *)num, "%d", n); |
sprintf(num, "%d", n); |
if (isnumber(t)) |
if (isnumber(t)) |
setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval); |
setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); |
else |
else |
setsymtab(num, t, 0.0, STR, (Array *) ap->sval); |
setsymtab(num, t, 0.0, STR, (Array *) ap->sval); |
*s = temp; |
*s = temp; |
|
|
return true; |
return true; |
} |
} |
|
|
#if 0 |
|
/* if someone ever wants to run over the arrays in sorted order, */ |
|
/* here it is. but it will likely run slower, not faster. */ |
|
|
|
int qstrcmp(p, q) |
|
char **p, **q; |
|
{ |
|
return strcmp(*p, *q); |
|
} |
|
|
|
Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ |
|
{ |
|
Cell *x, *vp, *arrayp, *cp, *ncp, *ret; |
|
Array *tp; |
|
int i, ne; |
|
#define BIGENOUGH 1000 |
|
char *elems[BIGENOUGH], **ep; |
|
|
|
vp = execute(a[0]); |
|
arrayp = execute(a[1]); |
|
if (!isarr(arrayp)) |
|
ERROR "%s is not an array", arrayp->nval FATAL; |
|
tp = (Array *) arrayp->sval; |
|
tempfree(arrayp); |
|
ep = elems; |
|
ret = true; |
|
if (tp->nelem >= BIGENOUGH) |
|
ep = (char **) malloc(tp->nelem * sizeof(char *)); |
|
|
|
for (i = ne = 0; i < tp->size; i++) |
|
for (cp = tp->tab[i]; cp != NULL; cp = cp->cnext) |
|
ep[ne++] = cp->nval; |
|
if (ne != tp->nelem) |
|
ERROR "can't happen: lost elems %d vs. %d", ne, tp->nelem FATAL; |
|
qsort(ep, ne, sizeof(char *), qstrcmp); |
|
for (i = 0; i < ne; i++) { |
|
setsval(vp, ep[i]); |
|
x = execute(a[2]); |
|
if (isbreak(x)) { |
|
tempfree(vp); |
|
break; |
|
} |
|
if (isnext(x) || isnextfile(x) || isexit(x) || isret(x)) { |
|
tempfree(vp); |
|
ret = x; |
|
break; |
|
} |
|
tempfree(x); |
|
} |
|
if (ep != elems) |
|
free(ep); |
|
return ret; |
|
} |
|
#endif |
|
|
|
|
|
Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ |
Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ |
{ |
{ |
Cell *x, *y; |
Cell *x, *y; |
Awkfloat u; |
Awkfloat u; |
int t; |
int t; |
char *p, buf[RECSIZE]; |
char *p, *buf; |
Node *nextarg; |
Node *nextarg; |
FILE *fp; |
FILE *fp; |
|
|
|
|
break; |
break; |
case FSYSTEM: |
case FSYSTEM: |
fflush(stdout); /* in case something is buffered already */ |
fflush(stdout); /* in case something is buffered already */ |
u = (Awkfloat) system((char *)getsval(x)) / 256; /* 256 is unix-dep */ |
u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */ |
break; |
break; |
case FRAND: |
case FRAND: |
/* in principle, rand() returns something in 0..RAND_MAX */ |
/* in principle, rand() returns something in 0..RAND_MAX */ |
u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX; |
u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX; |
break; |
break; |
case FSRAND: |
case FSRAND: |
if (x->tval & REC) /* no argument provided */ |
if (isrec(x)) /* no argument provided */ |
u = time((time_t *)0); |
u = time((time_t *)0); |
else |
else |
u = getfval(x); |
u = getfval(x); |
|
|
break; |
break; |
case FTOUPPER: |
case FTOUPPER: |
case FTOLOWER: |
case FTOLOWER: |
strcpy(buf, getsval(x)); |
buf = tostring(getsval(x)); |
if (t == FTOUPPER) { |
if (t == FTOUPPER) { |
for (p = buf; *p; p++) |
for (p = buf; *p; p++) |
if (islower(*p)) |
if (islower(*p)) |
|
|
tempfree(x); |
tempfree(x); |
x = gettemp(); |
x = gettemp(); |
setsval(x, buf); |
setsval(x, buf); |
|
free(buf); |
return x; |
return x; |
case FFLUSH: |
case FFLUSH: |
if ((fp = openfile(GT, getsval(x))) == NULL) |
if ((fp = openfile(FFLUSH, getsval(x))) == NULL) |
u = EOF; |
u = EOF; |
else |
else |
u = fflush(fp); |
u = fflush(fp); |
|
|
fp = redirect((int)a[1], a[2]); |
fp = redirect((int)a[1], a[2]); |
for (x = a[0]; x != NULL; x = x->nnext) { |
for (x = a[0]; x != NULL; x = x->nnext) { |
y = execute(x); |
y = execute(x); |
fputs((char *)getsval(y), fp); |
fputs(getsval(y), fp); |
tempfree(y); |
tempfree(y); |
if (x->nnext == NULL) |
if (x->nnext == NULL) |
fputs((char *)*ORS, fp); |
fputs(*ORS, fp); |
else |
else |
fputs((char *)*OFS, fp); |
fputs(*OFS, fp); |
} |
} |
if (a[1] != 0) |
if (a[1] != 0) |
fflush(fp); |
fflush(fp); |
|
|
if (*s == '\0') |
if (*s == '\0') |
ERROR "null file name in print or getline" FATAL; |
ERROR "null file name in print or getline" FATAL; |
for (i=0; i < FOPEN_MAX; i++) |
for (i=0; i < FOPEN_MAX; i++) |
if (files[i].fname && strcmp(s, files[i].fname) == 0) |
if (files[i].fname && strcmp(s, files[i].fname) == 0) { |
if (a == files[i].mode || (a==APPEND && files[i].mode==GT)) |
if (a == files[i].mode || (a==APPEND && files[i].mode==GT)) |
return files[i].fp; |
return files[i].fp; |
|
if (a == FFLUSH) |
|
return files[i].fp; |
|
} |
|
if (a == FFLUSH) /* didn't find it, so don't create it! */ |
|
return NULL; |
|
|
for (i=0; i < FOPEN_MAX; i++) |
for (i=0; i < FOPEN_MAX; i++) |
if (files[i].fp == 0) |
if (files[i].fp == 0) |
break; |
break; |
|
|
} |
} |
} |
} |
|
|
#define SUBSIZE (20 * RECSIZE) |
void backsub(char **pb_ptr, char **sptr_ptr); |
|
|
Cell *sub(Node **a, int nnn) /* substitute command */ |
Cell *sub(Node **a, int nnn) /* substitute command */ |
{ |
{ |
char *sptr, *pb, *q; |
char *sptr, *pb, *q; |
Cell *x, *y, *result; |
Cell *x, *y, *result; |
char buf[SUBSIZE], *t; |
char *t, *buf; |
fa *pfa; |
fa *pfa; |
|
int bufsz = recsize; |
|
|
|
if ((buf=malloc(bufsz)) == NULL) |
|
ERROR "out of memory in sub" FATAL; |
x = execute(a[3]); /* target string */ |
x = execute(a[3]); /* target string */ |
t = getsval(x); |
t = getsval(x); |
if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ |
if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ |
|
|
y = execute(a[2]); /* replacement string */ |
y = execute(a[2]); /* replacement string */ |
result = false; |
result = false; |
if (pmatch(pfa, t)) { |
if (pmatch(pfa, t)) { |
pb = buf; |
|
sptr = t; |
sptr = t; |
|
adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub"); |
|
pb = buf; |
while (sptr < patbeg) |
while (sptr < patbeg) |
*pb++ = *sptr++; |
*pb++ = *sptr++; |
sptr = getsval(y); |
sptr = getsval(y); |
while (*sptr != 0 && pb < buf + SUBSIZE - 1) |
while (*sptr != 0) { |
if (*sptr == '\\' && *(sptr+1) == '&') { |
adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub"); |
sptr++; /* skip \, */ |
if (*sptr == '\\') { |
*pb++ = *sptr++; /* add & */ |
backsub(&pb, &sptr); |
} else if (*sptr == '&') { |
} else if (*sptr == '&') { |
sptr++; |
sptr++; |
|
adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub"); |
for (q = patbeg; q < patbeg+patlen; ) |
for (q = patbeg; q < patbeg+patlen; ) |
*pb++ = *q++; |
*pb++ = *q++; |
} else |
} else |
*pb++ = *sptr++; |
*pb++ = *sptr++; |
|
} |
*pb = '\0'; |
*pb = '\0'; |
if (pb >= buf + SUBSIZE) |
if (pb > buf + bufsz) |
ERROR "sub() result %.30s too big", buf FATAL; |
ERROR "sub result1 %.30s too big; can't happen", buf FATAL; |
sptr = patbeg + patlen; |
sptr = patbeg + patlen; |
if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) |
if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) { |
|
adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub"); |
while ((*pb++ = *sptr++) != 0) |
while ((*pb++ = *sptr++) != 0) |
; |
; |
if (pb >= buf + SUBSIZE) |
} |
ERROR "sub() result %.30s too big", buf FATAL; |
if (pb > buf + bufsz) |
setsval(x, buf); |
ERROR "sub result2 %.30s too big; can't happen", buf FATAL; |
|
setsval(x, buf); /* BUG: should be able to avoid copy */ |
result = true;; |
result = true;; |
} |
} |
tempfree(x); |
tempfree(x); |
tempfree(y); |
tempfree(y); |
|
free(buf); |
return result; |
return result; |
} |
} |
|
|
Cell *gsub(Node **a, int nnn) /* global substitute */ |
Cell *gsub(Node **a, int nnn) /* global substitute */ |
{ |
{ |
Cell *x, *y; |
Cell *x, *y; |
char *rptr, *sptr, *t, *pb; |
char *rptr, *sptr, *t, *pb, *q; |
char buf[SUBSIZE]; |
char *buf; |
fa *pfa; |
fa *pfa; |
int mflag, tempstat, num; |
int mflag, tempstat, num; |
|
int bufsz = recsize; |
|
|
|
if ((buf=malloc(bufsz)) == NULL) |
|
ERROR "out of memory in gsub" FATAL; |
mflag = 0; /* if mflag == 0, can replace empty string */ |
mflag = 0; /* if mflag == 0, can replace empty string */ |
num = 0; |
num = 0; |
x = execute(a[3]); /* target string */ |
x = execute(a[3]); /* target string */ |
|
|
pb = buf; |
pb = buf; |
rptr = getsval(y); |
rptr = getsval(y); |
do { |
do { |
/* |
|
char *p; |
|
int i; |
|
printf("target string: %s, *patbeg = %o, patlen = %d\n", |
|
t, *patbeg, patlen); |
|
printf(" match found: "); |
|
p=patbeg; |
|
for (i=0; i<patlen; i++) |
|
printf("%c", *p++); |
|
printf("\n"); |
|
*/ |
|
if (patlen == 0 && *patbeg != 0) { /* matched empty string */ |
if (patlen == 0 && *patbeg != 0) { /* matched empty string */ |
if (mflag == 0) { /* can replace empty */ |
if (mflag == 0) { /* can replace empty */ |
num++; |
num++; |
sptr = rptr; |
sptr = rptr; |
while (*sptr != 0 && pb < buf + SUBSIZE-1) |
while (*sptr != 0) { |
if (*sptr == '\\' && *(sptr+1) == '&') { |
adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); |
sptr++; |
if (*sptr == '\\') { |
*pb++ = *sptr++; |
backsub(&pb, &sptr); |
} else if (*sptr == '&') { |
} else if (*sptr == '&') { |
char *q; |
|
sptr++; |
sptr++; |
|
adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); |
for (q = patbeg; q < patbeg+patlen; ) |
for (q = patbeg; q < patbeg+patlen; ) |
*pb++ = *q++; |
*pb++ = *q++; |
} else |
} else |
*pb++ = *sptr++; |
*pb++ = *sptr++; |
|
} |
} |
} |
if (*t == 0) /* at end */ |
if (*t == 0) /* at end */ |
goto done; |
goto done; |
|
adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub"); |
*pb++ = *t++; |
*pb++ = *t++; |
if (pb >= buf + SUBSIZE-1) |
if (pb > buf + bufsz) /* BUG: not sure of this test */ |
ERROR "gsub() result %.30s too big", buf FATAL; |
ERROR "gsub result0 %.30s too big; can't happen", buf FATAL; |
mflag = 0; |
mflag = 0; |
} |
} |
else { /* matched nonempty string */ |
else { /* matched nonempty string */ |
num++; |
num++; |
/* if (patlen <= 0) |
|
ERROR "4: buf=%s, patlen %d, t=%s, patbeg=%s", buf, patlen, t, patbeg WARNING; */ |
|
sptr = t; |
sptr = t; |
while (sptr < patbeg && pb < buf + SUBSIZE-1) |
adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub"); |
|
while (sptr < patbeg) |
*pb++ = *sptr++; |
*pb++ = *sptr++; |
sptr = rptr; |
sptr = rptr; |
while (*sptr != 0 && pb < buf + SUBSIZE-1) |
while (*sptr != 0) { |
if (*sptr == '\\' && *(sptr+1) == '&') { |
adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); |
sptr++; |
if (*sptr == '\\') { |
*pb++ = *sptr++; |
backsub(&pb, &sptr); |
} else if (*sptr == '&') { |
} else if (*sptr == '&') { |
char *q; |
|
sptr++; |
sptr++; |
|
adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); |
for (q = patbeg; q < patbeg+patlen; ) |
for (q = patbeg; q < patbeg+patlen; ) |
*pb++ = *q++; |
*pb++ = *q++; |
} else |
} else |
*pb++ = *sptr++; |
*pb++ = *sptr++; |
|
} |
t = patbeg + patlen; |
t = patbeg + patlen; |
if (patlen == 0 || *t == 0 || *(t-1) == 0) |
if (patlen == 0 || *t == 0 || *(t-1) == 0) |
goto done; |
goto done; |
if (pb >= buf + SUBSIZE-1) |
if (pb > buf + bufsz) |
ERROR "gsub() result %.30s too big", buf FATAL; |
ERROR "gsub result1 %.30s too big; can't happen", buf FATAL; |
mflag = 1; |
mflag = 1; |
} |
} |
} while (pmatch(pfa,t)); |
} while (pmatch(pfa,t)); |
sptr = t; |
sptr = t; |
|
adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub"); |
while ((*pb++ = *sptr++) != 0) |
while ((*pb++ = *sptr++) != 0) |
; |
; |
done: if (pb >= buf + SUBSIZE-1) |
done: if (pb > buf + bufsz) |
ERROR "gsub() result %.30s too big", buf FATAL; |
ERROR "gsub result2 %.30s too big; can't happen", buf FATAL; |
*pb = '\0'; |
*pb = '\0'; |
setsval(x, buf); |
setsval(x, buf); /* BUG: should be able to avoid copy + free */ |
pfa->initstat = tempstat; |
pfa->initstat = tempstat; |
} |
} |
tempfree(x); |
tempfree(x); |
|
|
x = gettemp(); |
x = gettemp(); |
x->tval = NUM; |
x->tval = NUM; |
x->fval = num; |
x->fval = num; |
|
free(buf); |
return(x); |
return(x); |
|
} |
|
|
|
void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */ |
|
{ /* sptr[0] == '\\' */ |
|
char *pb = *pb_ptr, *sptr = *sptr_ptr; |
|
|
|
if (sptr[1] == '\\') { |
|
if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */ |
|
*pb++ = '\\'; |
|
*pb++ = '&'; |
|
sptr += 4; |
|
} else if (sptr[2] == '&') { /* \\& -> \ + matched */ |
|
*pb++ = '\\'; |
|
sptr += 2; |
|
} else { /* \\x -> \\x */ |
|
*pb++ = *sptr++; |
|
*pb++ = *sptr++; |
|
} |
|
} else if (sptr[1] == '&') { /* literal & */ |
|
sptr++; |
|
*pb++ = *sptr++; |
|
} else /* literal \ */ |
|
*pb++ = *sptr++; |
|
|
|
*pb_ptr = pb; |
|
*sptr_ptr = sptr; |
} |
} |