home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 11 Util
/
11-Util.zip
/
NGAWK1.ZIP
/
AWK3.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-07-17
|
33KB
|
1,573 lines
/* awk3.c -- Builtin functions and various utility procedures
* Copyright (C) 1986,1987 Free Software Foundation
* Written by Jay Fenlason, December 1986
*
* Modifications by Andrew D. Estes, July 1988
*/
/*
GAWK is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY. No author or distributor accepts responsibility to anyone
for the consequences of using it or for whether it serves any
particular purpose or works at all, unless he says so in writing.
Refer to the GAWK General Public License for full details.
Everyone is granted permission to copy, modify and redistribute GAWK,
but only under the conditions described in the GAWK General Public
License. A copy of this license is supposed to have been given to you
along with GAWK so you can know your rights and responsibilities. It
should be in a file named COPYING. Among other things, the copyright
notice and this notice must be preserved on all copies.
In other words, go ahead and share GAWK, but don't try to stop
anyone else from sharing it farther. Help stamp out software hoarding!
*/
#include <stdio.h>
#include "obstack.h"
#include "awk.h"
#include "regex.h" /* ADE */
struct re_registers reregs; /* ADE */
extern struct obstack temp_strings;
/* This node is the cannonical null string, used everywhere */
extern NODE *Nnull_string;
/* These nodes store all the special variables gAWK uses */
NODE *FS_node, *NF_node, *FNR_node, *RS_node, *NR_node;
NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node;
NODE *ARGC_node, *ARGV_node, *RSTART_node, *RLENGTH_node;
/* This dumb kludge is used by force_string to turn a floating point
number into a string */
NODE dumb[2];
NODE **get_lhs();
FILE *deal_redirect();
struct redirect {
int flag; /* JF was NODETYPE */
NODE *value;
FILE *fp;
};
struct redirect reds[20]; /* An arbitrary limit, surely, but there's an
arbitrary limit on open files, too. So it
doesn't make much difference, does it? */
static char *inrecbuf; /* input buffer for inrec & getline -ade- */
long NR;
int NF;
int FNR; /* new variables -ade- */
int ARGV_index;
int ARGC;
/* The next #define tells how you find $0. Its a hack */
extern NODE **fields_arr;
#define WHOLELINE fields_arr[0]
/* Set all the special variables to their initial values. Also sets up
the dumb[] array for force_string */
init_vars()
{
NODE *spc_var();
NODE *do_sprintf();
FS_node=spc_var("FS",make_string(" ",1));
NF_node=spc_var("NF",make_number(0.0));
RS_node=spc_var("RS",make_string("\n",1));
NR_node=spc_var("NR",make_number(0.0));
FNR_node=spc_var("FNR",make_number(0.0)); /* File Number Records -ade- */
FILENAME_node=spc_var("FILENAME",Nnull_string);
OFS_node=spc_var("OFS",make_string(" ",1));
ORS_node=spc_var("ORS",make_string("\n",1));
OFMT_node=spc_var("OFMT",make_string("%.6g",4));
RSTART_node=spc_var("RSTART",make_number(0.0)); /* for Match -ade- */
RLENGTH_node=spc_var("RLENGTH",make_number(0.0)); /* for Match -ade- */
/* This ugly hack is used by force_string
to fake a call to sprintf */
dumb[0].type=Node_expression_list;
dumb[0].lnode=OFMT_node;
dumb[0].rnode= &dumb[1];
dumb[1].type=Node_expression_list;
dumb[1].lnode=(NODE *)0; /* fill in the var here */
dumb[1].rnode=(NODE *)0;
reds[0].flag=0; /* Don't depend on uninit data being zero, although it should be */
}
/* ADE */
init_args(argstart, argend, argv)
int argstart;
int argend;
char **argv;
{
NODE *tmp, *spc_var(), **assoc_lookup();
register int count;
ARGC_node = spc_var("ARGC", make_number((float)(argend-argstart+1)));
ARGC = argend - argstart;
ARGV_index = 1;
tmp = variable("ARGV");
assoc_clear(tmp);
*assoc_lookup(tmp, make_number((AWKNUM)(0))) =
make_string("awk",3);
for (count = argstart; count < argend; count++)
{
*assoc_lookup(tmp, make_number((AWKNUM)(count-argstart+1))) =
make_string(argv[count], strlen(argv[count]));
}
}
/* argc and argv functions added so that gawk will be in sync with
** ARGC and ARGV[] internal variables -ADE-
*/
int
get_argc()
{
return (ARGC);
}
set_argc(val)
int val;
{
ARGC = val;
}
int
get_argc_dec()
{
return (ARGC--);
}
char *
get_argv()
{
register NODE *tmp, *tmp1;
tmp = variable("ARGV");
tmp1 = *assoc_lookup(tmp, make_number((AWKNUM)ARGV_index));
if (tmp1->stlen==0) return 0;
return (tmp1->stptr);
}
inc_argv()
{
ARGV_index++;
}
set_argv(str)
char *str;
{
NODE *tmp, *spc_var(), **assoc_lookup();
tmp = variable("ARGV");
*assoc_lookup(tmp, make_number((AWKNUM)ARGV_index)) =
make_string(str, strlen(str));
}
/* OFMT is special because we don't dare use force_string on it for fear of
infinite loops. Thus, if it isn't a string, we return the default "%.6g"
This may or may not be the right thing to do, but its the easiest */
/* This routine isn't used! It should be. */
char *get_ofmt()
{
register NODE *tmp;
tmp= *get_lhs(OFMT_node);
if(tmp->type!=Node_string || tmp->stlen==0)
return "%.6g";
return tmp->stptr;
}
/* this was int. changed to allow regular expressions
** as field seperators -ade- */
char *
get_fs()
{
register NODE *tmp;
tmp=force_string(FS_node->var_value);
if(tmp->stlen==0) return NULL; /* ade */
return (tmp->stptr); /* ade */
}
set_fs(str)
char *str;
{
register NODE **tmp;
tmp= get_lhs(FS_node);
do_deref();
/* stupid special case so -F\t works as documented in awk */
/* even though the shell hands us -Ft. Bleah! (jfw) */
if (*str == 't') *str == '\t';
*tmp=make_string(str,1);
}
set_rs(str)
char *str;
{
register NODE **tmp;
tmp= get_lhs(RS_node);
do_deref();
/* stupid special case to be consistent with -F (jfw) */
if (*str == 't') *str == '\t';
*tmp=make_string(str,1);
}
int
get_rs()
{
register NODE *tmp;
tmp=force_string(RS_node->var_value);
if(tmp->stlen==0) return 0;
return *(tmp->stptr);
}
/* ADE */
set_fnr(fnr)
int fnr;
{
FNR = fnr;
assign_number(&(FNR_node->var_value),(AWKNUM)fnr);
}
/* Builtin functions */
/* ADE - added do_atan2, do_close, do_cos, do_gsub, do_match, do_sub
** do_srand, do_rand, do_sin and do_system
*/
NODE *
do_atan2(tree)
NODE *tree;
{
NODE *tmp1, *tmp2;
double atan2();
get_two(tree, &tmp1, &tmp2);
return tmp_number((AWKNUM)atan2((double)force_number(tmp1),
(double)force_number(tmp2)));
}
NODE *
do_close(tree)
NODE *tree;
{
register NODE *tmp;
register struct redirect *rp;
register char *str;
register FILE *fp;
#ifdef UNIX
/* %%% VANDYS: I guess you could run a prog to a file... */
FILE *popen();
#endif /* UNIX */
int tflag;
tmp=tree_eval(tree->subnode);
for(rp=reds;rp->flag!=0 && rp<&reds[20];rp++) { /* That limit again */
if(cmp_nodes(rp->value,tmp)==0)
break;
}
if(rp==&reds[20])
return tmp_number(1.1); /* ERROR not a redirect -ADE- */
if(rp->flag==0)
return tmp_number(1.1);
rp->flag=0;
fclose(rp->fp);
return tmp_number(0.0);
}
NODE *
do_cos(tree)
NODE *tree;
{
NODE *tmp;
double cos();
get_one(tree, &tmp);
return tmp_number((AWKNUM)cos((double)force_number(tmp)));
}
NODE *
do_exp(tree)
NODE *tree;
{
NODE *tmp;
double exp();
get_one(tree,&tmp);
return tmp_number((AWKNUM)exp((double)force_number(tmp)));
}
/* JF: I don't know what this should return. */
/* jfw: 1 if successful or by land, 0 if end of file or by sea */
/* do_getline has been beefed up to allow assignment to variables
** and reading from a redirection. -ade-
*/
/* ADE: 1 if record present, 0 if end of file, -1 error */
NODE *
do_getline(tree)
NODE *tree;
{
NODE **tmp, *t1, *t2;
FILE *infp, *deal_redirect_in();
extern FILE *input_file;
int retval, parse_type;
parse_type = 0;
t1 = tree->rnode;
tree = tree->lnode;
infp = deal_redirect_in(t1);
if (infp != input_file)
{
parse_type += 2;
FNR = 0;
}
if (tree == NULL)
retval = inrec(parse_type, infp);
else if (tree->type != Node_var)
retval = inrec(parse_type, infp);
else
{
parse_type++;
t1 = tree;
retval = inrec(parse_type, infp);
tmp = get_lhs(t1);
do_deref();
*tmp = make_string(inrecbuf, strlen(inrecbuf));
}
if(retval == 1)
return tmp_number(0.0);
else
return tmp_number(1.0);
}
/* globally substitute function -ade- */
NODE *
do_gsub(tree)
NODE *tree;
{
NODE **tmp, *t1, *t2, *t3, *t4;
char *temp, *temp1, *regsub();
int new_len, redofields;
switch (b_get_three(tree, &t1, &t2, &t3))
{
case 1:
printf("Error: gsub needs 2 or 3 parameters\n");
abort();
break;
case 2:
t3 = WHOLELINE;
redofields++;
break;
default:
redofields = 0;
break;
}
if (t3->type == Node_field_spec)
++redofields;
t4 = tree_eval(t3);
if (re_search(t1->rereg, t4->stptr, t4->stlen,
0, t4->stlen, &reregs) != -1)
{
if ((temp = malloc(64)) == NULL)
panic("Memory exhausted");
new_len = 64;
temp = regsub(t4->stptr, temp, t2->stptr, &new_len);
while (re_search(t1->rereg, temp, new_len,
0, new_len, &reregs) != -1)
{
if ((temp1 = malloc(64)) == NULL)
panic("Memory exhausted");
new_len = 64;
temp1 = regsub(temp, temp1, t2->stptr, &new_len);
free(temp);
temp = temp1;
}
if ((t3->lnode->type == Node_field_spec) || redofields)
{
--FNR;
--NR;
parse_fields(temp, temp+strlen(temp), 0);
free(temp);
return (tmp_number(1.0));
}
tmp = get_lhs(t3);
do_deref();
*tmp = make_string(temp, strlen(temp));
free(temp);
free(temp1);
return (tmp_number(1.0));
}
return (tmp_number(0.0));
}
NODE *
do_index(tree)
NODE *tree;
{
NODE *s1,*s2;
register char *p1,*p2;
register int l1,l2;
get_two(tree,&s1,&s2);
p1=s1->stptr;
p2=s2->stptr;
l1=s1->stlen;
l2=s2->stlen;
while(l1) {
if(!strncmp(p1,p2,l2))
return tmp_number((AWKNUM)(1+s1->stlen-l1));
l1--;
p1++;
}
return tmp_number(0.0);
}
NODE *
do_int(tree)
NODE *tree;
{
NODE *tmp;
double floor();
get_one(tree,&tmp);
return tmp_number((AWKNUM)floor((double)force_number(tmp)));
}
NODE *
do_length(tree)
NODE *tree;
{
NODE *tmp;
get_one(tree,&tmp);
return tmp_number((AWKNUM)(force_string(tmp)->stlen));
}
NODE *
do_log(tree)
NODE *tree;
{
NODE *tmp;
double log();
get_one(tree,&tmp);
return tmp_number(log(force_number(tmp)));
}
NODE *
do_match(tree)
NODE *tree;
{
NODE **tmp, *tmp1, *tmp2;
int retval;
get_two(tree, &tmp1, &tmp2);
retval = re_search(tmp2->rereg, tmp1->stptr,tmp1->stlen,
0, tmp1->stlen, &reregs);
retval++;
tmp= get_lhs(RSTART_node);
do_deref();
*tmp=make_number((AWKNUM)retval);
tmp= get_lhs(RLENGTH_node);
do_deref();
*tmp=make_number((AWKNUM)(reregs.end[0] - reregs.start[0]));
return (tmp_number((AWKNUM) retval));
}
NODE *
do_printf(tree)
NODE *tree;
{
register FILE *fp;
NODE *do_sprintf();
fp=deal_redirect(tree->rnode);
print_simple(do_sprintf(tree->lnode),fp);
return Nnull_string;
}
NODE *
do_sin(tree)
NODE *tree;
{
NODE *tmp;
double sin();
get_one(tree, &tmp);
return(tmp_number((AWKNUM)sin((double)force_number(tmp))));
}
NODE *
do_split(tree)
NODE *tree;
{
NODE *t1,*t2,*t3;
register char *splitc;
register int num,snum,olds;
register char *ptr,*oldp;
NODE **assoc_lookup();
if(a_get_three(tree,&t1,&t2,&t3)<3)
splitc= get_fs();
else
splitc= (force_string(t3)->stptr);
num=0;
tree=force_string(t1);
olds=snum=tree->stlen;
oldp=ptr=tree->stptr;
assoc_clear(t2);
while(snum--) {
if(*ptr++==*splitc) {
*assoc_lookup(t2,make_number((AWKNUM)(++num)))=make_string(oldp,(olds-snum)-1);
oldp=ptr;
olds=snum;
}
}
*assoc_lookup(t2,make_number((AWKNUM)(++num)))=make_string(oldp,(olds-snum)-1);
return tmp_number((AWKNUM)num);
}
/* Note that the output buffer cannot be static because sprintf may get called
recursively by force_string. Hence the wasteful alloca calls */
/* %e and %f formats are not properly implemented. Someone should fix them */
/* %f format seems to be working now -ADE- */
NODE *
do_sprintf(tree)
NODE *tree;
{
#define bchunk(s,l) if(l) {\
if((l)>ofre) {\
char *tmp;\
tmp=(char *)alloca(osiz*2);\
bcopy(obuf,tmp,olen);\
obuf=tmp;\
ofre+=osiz;\
osiz*=2;\
}\
bcopy(s,obuf+olen,(l));\
olen+=(l);\
ofre-=(l);\
}
/* Is there space for something L big in the buffer? */
#define chksize(l) if((l)>ofre) {\
char *tmp;\
tmp=(char *)alloca(osiz*2);\
bcopy(obuf,tmp,olen);\
obuf=tmp;\
ofre+=osiz;\
osiz*=2;\
}
/* Get the next arg to be formatted. If we've run out of args, return
"" (Null string) */
#define parse_next_arg() {\
if(!carg) arg= Nnull_string;\
else {\
get_one(carg,&arg);\
carg=carg->rnode;\
}\
}
char *obuf;
int osiz,ofre,olen, dec;
static char chbuf[] = "0123456789abcdef";
static char sp[] =" ";
char *s0,*s1;
int n0;
NODE *sfmt,*arg;
register NODE *carg;
long fw,prec,lj,alt,big;
long *cur;
long val;
unsigned long uval;
int sgn;
int base;
char cpbuf[30]; /* if we have numbers bigger than 30 */
char *cend= &cpbuf[30]; /* chars, we lose, but seems unlikely */
char *cp;
char *fill;
double tmpval;
char *pr_str;
obuf=(char *)alloca(120);
osiz=120;
ofre=osiz;
olen=0;
get_one(tree,&sfmt);
sfmt=force_string(sfmt);
carg=tree->rnode;
for(s0=s1=sfmt->stptr,n0=sfmt->stlen;n0-->0;) {
if(*s1!='%') {
s1++;
continue;
}
bchunk(s0,s1-s0);
s0=s1;
cur= &fw;
fw=0;
prec=0;
lj=alt=big=0;
fill= sp;
cp=cend;
s1++;
retry:
--n0;
switch(*s1++) {
case '%':
bchunk("%",1);
s0=s1;
break;
case '0':
if(fill!=sp || lj) goto lose;
fill="0"; /* FALL through */
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if(cur==0)
goto lose;
*cur= s1[-1]-'0';
while(n0>0 && *s1>='0' && *s1<='9') {
--n0;
*cur= *cur * 10 + *s1++ - '0';
}
goto retry;
case '-':
if(lj || fill!=sp) goto lose;
lj++;
goto retry;
case '.':
if(cur!=&fw) goto lose;
cur= ≺
goto retry;
case '#':
if(alt) goto lose;
alt++;
goto retry;
case 'l':
if(big) goto lose;
big++;
goto retry;
case '*':
if(cur==0) goto lose;
parse_next_arg();
*cur=(int)arg;
goto retry;
case 'c':
parse_next_arg();
if(arg->type==Node_number) {
uval=(unsigned long)arg->numbr;
cpbuf[0]=uval;
prec=1;
pr_str=cpbuf;
goto dopr_string;
}
if(!prec || prec>arg->stlen)
prec=arg->stlen;
pr_str=cpbuf;
goto dopr_string;
case 's':
parse_next_arg();
arg=force_string(arg);
if(!prec || prec>arg->stlen)
prec=arg->stlen;
pr_str=arg->stptr;
dopr_string:
if(fw>prec && !lj) {
while(fw>prec) {
bchunk(sp,1);
fw--;
}
}
bchunk(pr_str,(int)prec);
if(fw>prec) {
while(fw>prec) {
bchunk(sp,1);
fw--;
}
}
s0=s1;
break;
case 'd':
parse_next_arg();
val=(long)force_number(arg);
if(val<0) {
sgn=1;
val= -val;
} else sgn=0;
do {
*--cp='0'+val%10;
val/=10;
} while (val);
if(sgn) *--cp='-';
prec=cend-cp;
if(fw>prec && !lj) {
if(fill!=sp && *cp=='-') {
bchunk(cp,1);
cp++;
prec--;
fw--;
}
while(fw>prec) {
bchunk(fill,1);
fw--;
}
}
bchunk(cp,(int)prec);
if(fw>prec) {
while(fw>prec) {
bchunk(fill,1);
fw--;
}
}
s0=s1;
break;
case 'u':
base=10;
goto pr_unsigned;
case 'o':
base=8;
goto pr_unsigned;
case 'x':
base=16;
goto pr_unsigned;
pr_unsigned:
parse_next_arg();
uval=(unsigned long)force_number(arg);
do {
*--cp=chbuf[uval%base];
uval/=base;
} while(uval);
prec=cend-cp;
if(fw>prec && !lj) {
while(fw>prec) {
bchunk(fill,1);
fw--;
}
}
bchunk(cp,(int)prec);
if(fw>prec) {
while(fw>prec) {
bchunk(fill,1);
fw--;
}
}
s0=s1;
break;
case 'g':
parse_next_arg();
tmpval=force_number(arg);
if(prec==0) prec=13;
gcvt(tmpval,prec,cpbuf);
prec=strlen(cpbuf);
cp=cpbuf;
if (cpbuf[prec-1] == '.') /* if last char is a '.' */
cpbuf[--prec] = '\0'; /* drop it -ADE- */
if(fw>prec && !lj) {
if(fill!=sp && *cp=='-') {
bchunk(cp,1);
cp++;
prec--;
} /* Deal with .5 as 0.5 */
if(fill==sp && *cp=='.') {
--fw;
while(--fw>=prec) {
bchunk(fill,1);
}
bchunk("0",1);
} else
while(fw-->prec) bchunk(fill,1);
} else { /* Turn .5 into 0.5 */
/* FOO */
if(*cp=='.' && fill==sp) {
bchunk("0",1);
--fw;
}
}
bchunk(cp,(int)prec);
if(fw>prec) while(fw-->prec) bchunk(fill,1);
s0=s1;
break;
/* JF how to handle these!? */
case 'f':
parse_next_arg();
tmpval=force_number(arg);
if (prec == 0) prec=6;
cp=fcvt(tmpval,prec,&dec,&sgn);
prec=strlen(cp);
if(fw>prec && !lj) {
if(fill!=sp && *cp=='-') {
bchunk(cp,1);
cp++;
prec--;
} /* Deal with .5 as 0.5 */
if(fill==sp && *cp=='.') {
--fw;
while(--fw>=prec) {
bchunk(fill,1);
}
bchunk("0",1);
} else
while(fw-->prec) bchunk(fill,1);
} else { /* Turn .5 into 0.5 */
/* FOO */
if(*cp=='.' && fill==sp) {
bchunk("0",1);
--fw;
}
}
if (sgn)
bchunk("-",1);
if (dec > 0)
{
bchunk(cp, dec);
bchunk(".", 1);
cp += dec;
bchunk(cp, (int)prec - dec);
}
else if (dec)
{
prec += dec;
bchunk("0", 1);
bchunk(".", 1);
while (dec++) bchunk("0", 1);
bchunk(cp, (int)prec);
}
else
{
bchunk("0", 1);
bchunk(".", 1);
bchunk(cp, (int)prec);
}
if (fw>prec) while (fw-- > prec) bchunk(fill,1);
/* chksize(fw+prec+5);
** *cp++='%';
** if(lj) *cp++='-';
** if(fill!=sp) *cp++='0';
** if(prec!=0) {
** strcpy(cp,"*.*f");
** sprintf(obuf+olen,cpbuf,fw,prec,(double)tmpval);
** } else {
** strcpy(cp,"*f");
** sprintf(obuf+olen,cpbuf,fw,(double)tmpval);
** }
** cp=obuf+olen;
** ofre-=strlen(obuf+olen);
** olen+=strlen(obuf+olen);
*/ /* There may be nulls */
s0=s1;
break;
case 'e':
parse_next_arg();
tmpval=force_number(arg);
if (prec == 0) prec=13;
cp=ecvt(tmpval,prec,&dec,&sgn);
prec=strlen(cp);
if (sgn)
bchunk("-",1);
if (dec > 0)
{
bchunk(cp, dec);
bchunk(".", 1);
cp += dec;
bchunk(cp, (int)prec - dec);
}
else if (dec)
{
bchunk("0", abs(dec));
bchunk(".", 1);
bchunk(cp, (int)prec + dec);
}
else
{
bchunk("0", 1);
bchunk(".", 1);
bchunk(cp, (int)prec);
}
if (fw>prec) while (fw-- > prec) bchunk(fill,1);
/* chksize(fw+prec+5);
** cp=cpbuf;
** *cp++='%';
** if(lj) *cp++='-';
** if(fill!=sp) *cp++='0';
** if(prec!=0) {
** strcpy(cp,"*.*e");
** sprintf(obuf+olen,cpbuf,fw,prec,(double)tmpval);
** } else {
** strcpy(cp,"*e");
** sprintf(obuf+olen,cpbuf,fw,(double)tmpval);
** }
** cp=obuf+olen;
** ofre-=strlen(obuf+olen);
** olen+=strlen(obuf+olen);
**/
s0=s1;
break;
/* case 'g':
parse_next_arg();
tmpval=force_number(arg);
if(prec!=0) sprintf(obuf+osiz-ofre,"%*.*g",fw,prec,(double)tmpval);
else sprintf(obuf+osiz-ofre,"%*g",fw,(double)tmpval);
ofre-=strlen(obuf+osiz-ofre);
s0=s1;
break; */
default:
lose:
break;
}
}
bchunk(s0,s1-s0);
return tmp_string(obuf,olen);
}
NODE *
do_sqrt(tree)
NODE *tree;
{
NODE *tmp;
double sqrt();
get_one(tree,&tmp);
return tmp_number((AWKNUM)sqrt((double)force_number(tmp)));
}
/* set a seed for rand(). if no parameter, use time. -ade- */
NODE *
do_srand(tree)
NODE *tree;
{
NODE *tmp;
long ltime, *time();
if (tree == NULL)
srand((unsigned)time(<ime));
else
{
get_one(tree, &tmp);
srand((unsigned)force_number(tmp));
}
return tmp_number(1.0);
}
NODE *
do_sub(tree)
NODE *tree;
{
NODE **tmp, *t1, *t2, *t3, *t4;
char *temp;
int redofields, new_len;
char *regsub();
switch (b_get_three(tree, &t1, &t2, &t3))
{
case 1:
printf("Error: sub needs 2 or 3 parameters\n");
abort();
break;
case 2:
t3 = WHOLELINE;
redofields = 1;
break;
default:
redofields = 0;
break;
}
t4 = tree_eval(t3);
if (re_search(t1->rereg, t4->stptr, t4->stlen,
0, t4->stlen, &reregs) != -1)
{
if ((temp = malloc(64)) == NULL)
panic("Memory exhausted");
new_len = 64;
temp = regsub(t4->stptr, temp, t2->stptr, &new_len);
if ((t3->lnode->type == Node_field_spec) || redofields)
{
--FNR;
--NR;
parse_fields(temp, temp+strlen(temp), 0);
free(temp);
return (tmp_number(1.0));
}
tmp = get_lhs(t3);
do_deref();
*tmp = make_string(temp, strlen(temp));
free(temp);
return (tmp_number(1.0));
}
return (tmp_number(0.0));
}
NODE *
do_substr(tree)
NODE *tree;
{
NODE *t1,*t2,*t3;
register int n1,n2;
if(get_three(tree,&t1,&t2,&t3)<3)
n2=32000;
else
n2=(int)force_number(t3);
n1=(int)force_number(t2)-1;
tree=force_string(t1);
if(n1<0 || n1>=tree->stlen || n2<=0)
return Nnull_string;
if(n1+n2>tree->stlen)
n2=tree->stlen-n1;
return tmp_string(tree->stptr+n1,n2);
}
NODE *
do_system(tree)
NODE *tree;
{
NODE *tmp;
int system();
get_one(tree, &tmp);
tmp = force_string(tmp);
return(tmp_number(system(tmp->stptr)));
}
NODE *
do_rand(tree)
NODE *tree;
{
return (tmp_number((float)(rand() / 32767.0)));
}
/* The print command. Its name is historical */
hack_print_node(tree)
NODE *tree;
{
register FILE *fp;
#ifndef FAST
if(!tree || tree->type != Node_K_print)
abort();
#endif
fp=deal_redirect(tree->rnode);
tree=tree->lnode;
if(!tree) tree=WHOLELINE;
if(tree->type!=Node_expression_list) {
print_simple(tree,fp);
} else {
while(tree) {
print_simple(tree_eval(tree->lnode),fp);
tree=tree->rnode;
if(tree) print_simple(OFS_node->var_value,fp);
}
}
print_simple(ORS_node->var_value,fp);
}
/* Get the arguments to functions. No function cares if you give it
too many args (they're ignored). Only a few fuctions complain
about being given too few args. The rest have defaults */
get_one(tree,res)
NODE *tree,**res;
{
if(!tree) {
*res= WHOLELINE;
return;
}
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res=tree_eval(tree->lnode);
}
get_two(tree,res1,res2)
NODE *tree,**res1,**res2;
{
if(!tree) {
*res1= WHOLELINE;
return;
}
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res1=tree_eval(tree->lnode);
if(!tree->rnode)
return;
tree=tree->rnode;
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res2=tree_eval(tree->lnode);
}
get_three(tree,res1,res2,res3)
NODE *tree,**res1,**res2,**res3;
{
if(!tree) {
*res1= WHOLELINE;
return 0;
}
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res1=tree_eval(tree->lnode);
if(!tree->rnode)
return 1;
tree=tree->rnode;
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res2=tree_eval(tree->lnode);
if(!tree->rnode)
return 2;
tree=tree->rnode;
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res3=tree_eval(tree->lnode);
return 3;
}
a_get_three(tree,res1,res2,res3)
NODE *tree,**res1,**res2,**res3;
{
if(!tree) {
*res1= WHOLELINE;
return 0;
}
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res1=tree_eval(tree->lnode);
if(!tree->rnode)
return 1;
tree=tree->rnode;
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res2=tree->lnode;
if(!tree->rnode)
return 2;
tree=tree->rnode;
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res3=tree_eval(tree->lnode);
return 3;
}
/* special get_three for do_sub and do_gsub. -ade- */
b_get_three(tree,res1,res2,res3)
NODE *tree,**res1,**res2,**res3;
{
if(!tree) {
*res1= WHOLELINE;
return 0;
}
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res1=tree_eval(tree->lnode);
if(!tree->rnode)
return 1;
tree=tree->rnode;
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res2=tree_eval(tree->lnode);
if(!tree->rnode)
return 2;
tree=tree->rnode;
#ifndef FAST
if(tree->type!=Node_expression_list)
abort();
#endif
*res3=tree->lnode;
return 3;
}
/* FOO this should re-allocate the buffer if it isn't big enough.
Also, it should do RMS style only-parse-enough stuff. */
/* This reads in a line from the input file */
/* This used to do field parsing, that was broken off into its own
** function for do_getline. Note that inrec also takes two parameters
** now. One is passed to parse_fields (type) and one specifies the
** file to read from. -ADE-
*/
inrec(type, in_file)
int type;
FILE *in_file;
{
static char *buf,*buf_end;
static bsz;
register char *cur;
register char *tmp;
register char *ttmp;
int cnt;
int tcnt;
register int c;
int rs;
int fs;
NODE **get_lhs();
rs = get_rs();
if(!inrecbuf) {
inrecbuf=malloc(128);
bsz=128;
buf_end=buf+bsz;
}
buf = inrecbuf;
cur=buf;
cnt=0;
while ((c=getc(in_file))!=EOF) {
if((!rs && c=='\n' && cur[-1]=='\n' && cur!=buf) || (c == rs))
break;
*cur++=c;
cnt++;
if(cur==buf_end) {
buf=realloc(buf,bsz*2);
cur=buf+bsz;
bsz*=2;
buf_end=buf+bsz;
}
}
*cur='\0';
parse_fields(buf, cur, type);
if(c==EOF && cnt==0)
return 1;
return 0;
}
/* parse_fields does the field parsing. parse_type specifies the extent
** of parsing and internal variable setting. -ADE-
*/
parse_fields(start, end, parse_type)
char *start, *end;
int parse_type;
{
static char *buf,*buf_end;
static bsz;
register char *cur;
register char *tmp;
register char *ttmp;
int cnt;
int tcnt, ttmplen, re_val;
register int c;
int rs;
struct re_pattern_buffer *re_fs, *make_regexp();
char *fs;
NODE **get_lhs();
buf = start;
cur = end;
fs = get_fs();
if (parse_type == 0 || parse_type == 2)
blank_fields();
if (strlen(fs) > 1)
re_fs = make_regexp(fs);
if (parse_type == 0 || parse_type == 2)
NF=0;
cnt = cur - buf;
if (parse_type == 0 || parse_type == 2)
{
set_field(0,buf,cnt);
assign_number(&(NF_node->var_value),0.0);
}
if (parse_type < 2)
{
NR++;
assign_number(&(NR_node->var_value),
1.0+force_number(NR_node->var_value));
FNR++;
assign_number(&(FNR_node->var_value),
1.0+force_number(FNR_node->var_value));
}
if (parse_type == 1 || parse_type == 3)
return;
for(tmp=buf;tmp<cur;tmp++) {
if (strlen(fs) > 1) /* if fs is a string, make into a reg exp -ADE- */
{
tcnt = 0;
ttmp = tmp;
ttmplen = strlen(ttmp);
re_val = re_search(re_fs, ttmp, ttmplen, 0, ttmplen, &reregs);
if (re_val == -1)
{
tcnt == ttmplen;
break;
}
if (re_val == 0)
{
tmp += reregs.end[0];
continue;
}
tmp += reregs.end[0];
tcnt = reregs.start[0];
} else {
if(*fs==' ') {
while((*tmp==' ' || *tmp=='\t') && tmp<cur)
tmp++;
if(tmp>=cur)
break;
}
if(*fs==' ') {
tcnt = 0;
ttmp = tmp;
while(*tmp!=' ' && *tmp!='\t' && tmp<cur) {
tmp++;
tcnt++;
}
} else {
tcnt = 0;
ttmp = tmp;
while(*tmp!=*fs && tmp<cur) {
tmp++;
tcnt++;
}
}
}
set_field(++NF,ttmp,tcnt);
}
assign_number(&(NF_node->var_value),(AWKNUM)NF);
}
/* Redirection for printf and print commands */
FILE *
deal_redirect(tree)
NODE *tree;
{
register NODE *tmp;
register struct redirect *rp;
register char *str;
register FILE *fp;
#ifdef UNIX
/* %%% VANDYS: I guess you could run a prog to a file... */
FILE *popen();
#endif /* UNIX */
int tflag;
if(!tree) return stdout;
tflag= (tree->type==Node_redirect_pipe) ? 1 : 2;
tmp=tree_eval(tree->subnode);
for(rp=reds;rp->flag!=0 && rp<&reds[20];rp++) { /* That limit again */
if(rp->flag==tflag && cmp_nodes(rp->value,tmp)==0)
break;
}
if(rp==&reds[20]) {
panic("too many redirections",0);
return 0;
}
if(rp->flag!=0)
return rp->fp;
rp->flag=tflag;
rp->value=dupnode(tmp);
str=force_string(tmp)->stptr;
switch(tree->type) {
case Node_redirect_output:
fp=rp->fp=fopen(str,"w");
break;
case Node_redirect_append:
fp=rp->fp=fopen(str,"a");
break;
case Node_redirect_pipe:
#ifdef UNIX
fp=rp->fp=popen(str,"w");
#else
fp = 0;
#endif /* UNIX */
break;
}
if(fp==0) panic("can't redirect to '%s'\n",str);
rp++;
rp->flag=0;
return fp;
}
/* Redirection for getline command -ADE- */
FILE *
deal_redirect_in(tree)
NODE *tree;
{
register NODE *tmp;
register struct redirect *rp;
register char *str;
extern FILE *input_file;
register FILE *fp;
#ifdef UNIX
/* %%% VANDYS: I guess you could run a prog to a file... */
FILE *popen();
#endif /* UNIX */
int tflag;
if(!tree) return input_file;
tflag= (tree->type==Node_redirect_pipe) ? 1 : 2;
tmp=tree_eval(tree->subnode);
for(rp=reds;rp->flag!=0 && rp<&reds[20];rp++) { /* That limit again */
if(rp->flag==tflag && cmp_nodes(rp->value,tmp)==0)
break;
}
if(rp==&reds[20]) {
panic("too many redirections",0);
return 0;
}
if(rp->flag!=0)
return rp->fp;
rp->flag=tflag;
rp->value=dupnode(tmp);
str=force_string(tmp)->stptr;
switch(tree->type) {
case Node_redirect_input:
fp=rp->fp=fopen(str,"r");
break;
case Node_redirect_pipe:
#ifdef UNIX
fp=rp->fp=popen(str,"r");
#else
fp = 0;
#endif /* UNIX */
break;
}
if(fp==0) panic("can't redirect from '%s'\n",str);
rp++;
rp->flag=0;
return fp;
}
print_simple(tree,fp)
NODE *tree;
FILE *fp;
{
#ifndef FAST
/* Deal with some obscure bugs */
if(tree==(NODE *)0x55000000) {
fprintf(fp,"***HUH***");
return;
}
if((int)tree&01) {
fprintf(fp,"$that's odd$");
return;
}
#endif
tree=force_string(tree);
fwrite(tree->stptr,sizeof(char),tree->stlen,fp);
}
#define EXPAND_DEST \
{\
if ((dst=realloc(dst,dlen*2))==NULL) panic("Memory exhausted");\
dlen *= 2;\
}
/* substitute for a regular expression. This should allow tagged regular
** expressions, but I haven't tested it yet. -ADE-
*/
char *
regsub(source, dest, pattern, dlength)
char *source;
char *dest;
char *pattern;
int *dlength;
{
register char *src;
register char *dst;
char c;
char *substart, *subend;
char *pat;
int no, len, dnext, dlen;
extern char *strncpy();
src = source;
dst = dest;
pat = pattern;
substart = src + reregs.start[0];
subend = src + reregs.end[0];
dnext = 0;
dlen = *dlength;
while ((c = *src) != '\0')
{
if (src++ == substart)
{
while ((c = *pat++) != '\0')
{
if (c == '&')
no = 0;
else if (c == '\\' && '0' <= *pat && *pat <= '9')
no = *src++ - '0';
else
no = -1;
if (no < 0)
{
if (dlen <= dnext)
EXPAND_DEST;
dst[dnext++] = c;
}
else if (reregs.start[no] != -1 && reregs.end[no] != -1)
{
len = reregs.end[no] - reregs.start[no];
if (dlen <= (dnext + len))
EXPAND_DEST;
(void) strncpy(dst, source + reregs.start[no], len);
dst += len;
dnext += len;
}
}
src = subend;
}
else
{
if (dlen <= dnext)
EXPAND_DEST;
dst[dnext++] = c;
}
}
if (dlen <= dnext)
EXPAND_DEST;
dst[dnext] = '\0';
*dlength = dnext;
return (dst);
}