diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-02 15:46:31 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-02 15:46:31 +0300 |
commit | 3711eedc1b995eb1926c9ffb902d5d796cacf8d0 (patch) | |
tree | 5642fdee11499774e0b7401f195931cd3a143d18 /awk3.c | |
parent | ec6415f1ba061b2fb78808b7dba3246745a15398 (diff) | |
download | egawk-3711eedc1b995eb1926c9ffb902d5d796cacf8d0.tar.gz egawk-3711eedc1b995eb1926c9ffb902d5d796cacf8d0.tar.bz2 egawk-3711eedc1b995eb1926c9ffb902d5d796cacf8d0.zip |
Now at 2.02.
Diffstat (limited to 'awk3.c')
-rw-r--r-- | awk3.c | 1446 |
1 files changed, 867 insertions, 579 deletions
@@ -1,113 +1,255 @@ -/* awk3.c -- Builtin functions and various utility procedures - Copyright (C) 1986,1987 Free Software Foundation - Written by Jay Fenlason, December 1986 - +/* + * awk3 -- Builtin functions and various utility procedures + * + * Copyright (C) 1986,1987 Free Software Foundation Written by Jay Fenlason, + * December 1986 + * + * $Log: awk3.c,v $ + * Revision 1.34 88/12/13 22:28:10 david + * temporarily #ifdef out flush_io in redirect(); adjust atan2() for + * force_number as a macro + * + * Revision 1.32 88/12/01 15:03:21 david + * renamed hack_print_node to do_print (at last!) + * moved force_string() up out of print_simple for simplicity + * + * Revision 1.31 88/11/30 15:17:27 david + * free previous value in set_fs + * + * Revision 1.30 88/11/29 16:24:47 david + * fix bug in previous change + * + * Revision 1.29 88/11/29 15:14:52 david + * dynamically manage open files/pipes to allow an arbitrary number of open files + * (i.e. when out of file descriptors, close the least recently used file, + * saving the current offset; if it is reused, reopen and seek to saved offset) + * + * Revision 1.28 88/11/28 20:12:53 david + * correct previous error in cleanup of do_substr + * + * Revision 1.27 88/11/23 21:42:13 david + * Arnold: change ENV to ENVIRON nad a further bug fix for -Ft + * .. + * + * Revision 1.26 88/11/22 13:50:33 david + * Arnold: added ENV array and bug fix to -Ft + * + * Revision 1.25 88/11/15 10:24:08 david + * Arnold: cleanup of comments, #include's and obsolete code + * + * Revision 1.24 88/11/14 21:57:03 david + * Arnold: init. FILENAME to "-" and cleanup in do_substr() + * + * Revision 1.23 88/11/01 12:17:45 david + * cleanu and code movement; changes to reflect change to parse_fields() + * + * Revision 1.22 88/10/19 21:58:43 david + * replace malloc and realloc with error checking versions + * + * Revision 1.21 88/10/17 20:55:31 david + * SYSV --> USG + * + * Revision 1.20 88/10/13 21:59:55 david + * purge FAST and cleanup error messages + * + * Revision 1.19 88/10/06 21:54:28 david + * cleaned up I/O handling + * + * Revision 1.18 88/10/06 15:49:01 david + * changes from Arnold: be careful about flushing I/O; warn about error on close; + * return seed from srand + * + * Revision 1.17 88/09/19 20:39:11 david + * minor cleanup + * + * Revision 1.16 88/08/09 14:55:16 david + * getline now gets next file properly + * stupid bug in do_split() fixed + * substr() now works if second arg. is negative (truncated to 0) + * + * Revision 1.15 88/06/13 18:07:12 david + * delete -R option + * cleanup of redirection code [from Arnold] + * + * Revision 1.14 88/06/07 23:41:00 david + * some paranoid typecasting plus one bug fix: + * in do_getline(), use stdin if input_file is NULL and ther is no redirection + * + * Revision 1.13 88/06/06 21:40:49 david + * oops! got a little overenthusiastic on that last merge + * + * Revision 1.12 88/06/06 11:27:57 david + * get rid of some obsolete code + * merge parsing of fields for record input and split() + * + * Revision 1.11 88/06/05 21:00:35 david + * flush I/O buffers before calling system (fix from Arnold) + * + * Revision 1.10 88/06/05 20:59:26 david + * local vars. now come off a stack + * + * Revision 1.9 88/06/01 22:08:24 david + * in split(), ensure that if second arg. is a local var. that the value is + * looked up + * + * Revision 1.8 88/05/31 09:30:16 david + * Arnold's portability fixes to last change in random() stuff + * + * Revision 1.7 88/05/30 09:53:49 david + * clean up some fatal() calls + * de-lint the random number code + * + * Revision 1.6 88/05/27 11:06:21 david + * input_file wasn't getting properly reset after getline + * + * Revision 1.5 88/05/26 22:49:55 david + * fixed error message for redirection + * + * Revision 1.4 88/05/18 18:20:02 david + * fixed case where RS==""; record was including a trailing newline + * + * Revision 1.3 88/04/13 17:39:26 david + * fixed bug in handling of NR and FNR + * + * Revision 1.2 88/04/12 16:04:02 david + * fixed bug: NF at end of record generated one less field than it should have + * + * Revision 1.1 88/04/08 15:15:07 david + * Initial revision + * Revision 1.7 88/04/08 15:08:48 david bug fix for file + * descriptor handlin + * + * Revision 1.6 88/04/08 14:48:36 david changes from Arnold Robbins + * + * Revision 1.5 88/03/28 14:13:54 david *** empty log message *** + * + * Revision 1.4 88/03/23 22:17:41 david mostly delinting -- a couple of bug + * fixes + * + * Revision 1.3 88/03/18 21:00:13 david Baseline -- hoefully all the + * functionality of the new awk added. Just debugging and tuning to do. + * + * Revision 1.2 87/11/19 14:42:31 david expanded functionality for getline + * broke out get_a_record() from inrec() so that the former can be used from + * do_getline add system() builtin and skeletons for many other new builtins + * + * Revision 1.1 87/10/27 15:23:33 david Initial revision + * */ /* -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> + * 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 "awk.h" -#include <obstack.h> - -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, *RS_node, *NR_node; -NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node; - -/* This dumb kludge is used by force_string to turn a floating point - number into a string */ -NODE dumb[2]; +/* These nodes store all the special variables AWK uses */ +NODE *FS_node, *NF_node, *RS_node, *NR_node; +NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node; +NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node; +NODE *ENVIRON_node; -NODE **get_lhs(); -FILE *deal_redirect(); +FILE *redirect(); +/* + * structure used to dynamically maintain a linked-list of open files/pipes + */ struct redirect { - int flag; /* JF was NODETYPE */ - NODE *value; - FILE *fp; + int flag; +# define RED_FILE 1 +# define RED_PIPE 2 +# define RED_READ 4 +# define RED_WRITE 8 +# define RED_APPEND 16 + char *value; + FILE *fp; + long offset; /* used for dynamic management of open files */ + struct redirect *prev; + struct redirect *next; }; -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? */ - +struct redirect *red_head = NULL; -long NR; -int NF; - -/* 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 */ +/* + * Set all the special variables to their initial values. + */ 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)); - 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)); - - /* 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 */ -} - -/* 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 */ + NODE *spc_var(); + NODE *do_sprintf(); + extern char **environ; + char *var, *val; + NODE **aptr; + int i; + extern NODE **assoc_lookup(); + extern NODE *tmp_string(); + + FS_node = spc_var("FS", make_string(" ", 1)); + NF_node = spc_var("NF", make_number(-1.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)); + FILENAME_node = spc_var("FILENAME", make_string("-", 1)); + 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)); + RLENGTH_node = spc_var("RLENGTH", make_number(0.0)); + RSTART_node = spc_var("RSTART", make_number(0.0)); + SUBSEP_node = spc_var("SUBSEP", make_string("\034", 1)); + + ENVIRON_node = spc_var("ENVIRON", Nnull_string); + for (i = 0; environ[i]; i++) { + var = environ[i]; + val = index(var, '='); + if (val) + *val++ = '\0'; + else + val = ""; + aptr = assoc_lookup(ENVIRON_node, tmp_string(var, strlen (var))); + *aptr = make_string(val, strlen (val)); + } +} + +/* + * 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() +#ifdef notdef +char * +get_ofmt() { register NODE *tmp; - tmp= *get_lhs(OFMT_node); - if(tmp->type!=Node_string || tmp->stlen==0) + tmp = *get_lhs(OFMT_node); + if ((tmp->type != Node_string && tmp->type != Node_str_num) || tmp->stlen == 0) return "%.6g"; return tmp->stptr; } +#endif -int +char * get_fs() { register NODE *tmp; - tmp=force_string(FS_node->var_value); - if(tmp->stlen==0) return 0; - return *(tmp->stptr); + tmp = force_string(FS_node->var_value); + if (tmp->stlen == 0) + return 0; + return tmp->stptr; } set_fs(str) @@ -115,38 +257,27 @@ char *str; { register NODE **tmp; - tmp= get_lhs(FS_node); + 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); + /* stupid special case so -F\t works as documented in awk */ + /* even though the shell hands us -Ft. Bleah! */ + if (str[0] == 't' && str[1] == '\0') + str[0] = '\t'; + *tmp = make_string(str, 1); 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; + tmp = force_string(RS_node->var_value); + if (tmp->stlen == 0) + return 0; return *(tmp->stptr); } - /* Builtin functions */ NODE * do_exp(tree) @@ -155,53 +286,41 @@ NODE *tree; NODE *tmp; double exp(); - get_one(tree,&tmp); - return tmp_number(exp(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 */ -NODE * -do_getline(tree) -NODE *tree; -{ - if(inrec() == 0) - return tmp_number(1.0); - else - return tmp_number(0.0); + get_one(tree, &tmp); + return tmp_number((AWKNUM)exp((double)force_number(tmp))); } 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)); + 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); + return tmp_number((AWKNUM) 0.0); } NODE * do_int(tree) NODE *tree; { - NODE *tmp; - double floor(); + NODE *tmp; + double floor(); - get_one(tree,&tmp); - return tmp_number(floor(force_number(tmp))); + get_one(tree, &tmp); + return tmp_number((AWKNUM)floor((double)force_number(tmp))); } NODE * @@ -210,67 +329,77 @@ NODE *tree; { NODE *tmp; - get_one(tree,&tmp); - return tmp_number((AWKNUM)(force_string(tmp)->stlen)); + get_one(tree, &tmp); + return tmp_number((AWKNUM) (force_string(tmp)->stlen)); } NODE * do_log(tree) NODE *tree; { - NODE *tmp; + NODE *tmp; double log(); - get_one(tree,&tmp); - return tmp_number(log(force_number(tmp))); + get_one(tree, &tmp); + return tmp_number((AWKNUM)log((double)force_number(tmp))); } -NODE * +NODE * do_printf(tree) NODE *tree; { - register FILE *fp; - NODE *do_sprintf(); + register FILE *fp; + NODE *do_sprintf(); - fp=deal_redirect(tree->rnode); - print_simple(do_sprintf(tree->lnode),fp); + fp = redirect(tree->rnode); + print_simple(do_sprintf(tree->lnode), fp); return Nnull_string; } +set_element(num, s, len, n) +int num; +char *s; +int len; +NODE *n; +{ + extern NODE **assoc_lookup(); + + *assoc_lookup(n, tmp_number((AWKNUM) (num))) = make_string(s, len); +} NODE * do_split(tree) NODE *tree; { - NODE *t1,*t2,*t3; - register int splitc; - register int num,snum,olds; - register char *ptr,*oldp; - NODE **assoc_lookup(); + NODE *t1, *t2, *t3; + register char *splitc; + char *s; + NODE *n; - if(a_get_three(tree,&t1,&t2,&t3)<3) - splitc= get_fs(); + 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); + splitc = force_string(t3)->stptr; + + n = t2; + if (t2->type == Node_param_list) + n = stack_ptr[t2->param_cnt]; + if (n->type != Node_var && n->type != Node_var_array) + fatal("second argument of split is not a variable"); + assoc_clear(n); + + tree = force_string(t1); + + s = tree->stptr; + return tmp_number((AWKNUM) + parse_fields(HUGE, &s, tree->stlen, splitc, set_element, n)); } -/* Note that the output buffer cannot be static because sprintf may get called - recursively by force_string. Hence the wasteful alloca calls */ +/* + * 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 */ NODE * @@ -291,7 +420,7 @@ NODE *tree; ofre-=(l);\ } -/* Is there space for something L big in the buffer? */ + /* Is there space for something L big in the buffer? */ #define chksize(l) if((l)>ofre) {\ char *tmp;\ tmp=(char *)alloca(osiz*2);\ @@ -300,8 +429,11 @@ NODE *tree; ofre+=osiz;\ osiz*=2;\ } -/* Get the next arg to be formatted. If we've run out of args, return - "" (Null string) */ + + /* + * 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 {\ @@ -311,61 +443,62 @@ NODE *tree; } char *obuf; - int osiz,ofre,olen; + int osiz, ofre, olen; static char chbuf[] = "0123456789abcdef"; - static char sp[] =" "; - char *s0,*s1; - int n0; - NODE *sfmt,*arg; + static char sp[] = " "; + char *s0, *s1; + int n0; + NODE *sfmt, *arg; register NODE *carg; - long fw,prec,lj,alt,big; - long *cur; - long val; + 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!='%') { + 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; + extern char *gcvt(); + + + 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; + bchunk(s0, s1 - s0); + s0 = s1; + cur = &fw; + fw = 0; + prec = 0; + lj = alt = big = 0; + fill = sp; + cp = cend; s1++; - retry: +retry: --n0; - switch(*s1++) { + switch (*s1++) { case '%': - bchunk("%",1); - s0=s1; + bchunk("%", 1); + s0 = s1; break; case '0': - if(fill!=sp || lj) goto lose; - fill="0"; /* FALL through */ + if (fill != sp || lj) + goto lose; + fill = "0"; /* FALL through */ case '1': case '2': case '3': @@ -375,526 +508,681 @@ NODE *tree; case '7': case '8': case '9': - if(cur==0) + if (cur == 0) goto lose; - *cur= s1[-1]-'0'; - while(n0>0 && *s1>='0' && *s1<='9') { + *cur = s1[-1] - '0'; + while (n0 > 0 && *s1 >= '0' && *s1 <= '9') { --n0; - *cur= *cur * 10 + *s1++ - '0'; + *cur = *cur * 10 + *s1++ - '0'; } goto retry; case '-': - if(lj || fill!=sp) goto lose; + if (lj || fill != sp) + goto lose; lj++; goto retry; case '.': - if(cur!=&fw) goto lose; - cur= ≺ + if (cur != &fw) + goto lose; + cur = ≺ goto retry; case '#': - if(alt) goto lose; + if (alt) + goto lose; alt++; goto retry; case 'l': - if(big) goto lose; + 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; + if (arg->flags & NUM) { + 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; + 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); + 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); + bchunk(pr_str, (int) prec); + if (fw > prec) { + while (fw > prec) { + bchunk(sp, 1); fw--; } } - s0=s1; + s0 = s1; break; case 'd': parse_next_arg(); - val=(long)force_number(arg); - if(val<0) { - sgn=1; - val= -val; - } else sgn=0; + val = (long) force_number(arg); + if (val < 0) { + sgn = 1; + val = -val; + } else + sgn = 0; do { - *--cp='0'+val%10; - val/=10; + *--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); + 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); + while (fw > prec) { + bchunk(fill, 1); fw--; } } - bchunk(cp,(int)prec); - if(fw>prec) { - while(fw>prec) { - bchunk(fill,1); + bchunk(cp, (int) prec); + if (fw > prec) { + while (fw > prec) { + bchunk(fill, 1); fw--; } } - s0=s1; + s0 = s1; break; case 'u': - base=10; + base = 10; goto pr_unsigned; case 'o': - base=8; + base = 8; goto pr_unsigned; case 'x': - base=16; + base = 16; goto pr_unsigned; - pr_unsigned: + pr_unsigned: parse_next_arg(); - uval=(unsigned long)force_number(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); + *--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); + bchunk(cp, (int) prec); + if (fw > prec) { + while (fw > prec) { + bchunk(fill, 1); fw--; } } - s0=s1; + 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(fw>prec && !lj) { - if(fill!=sp && *cp=='-') { - bchunk(cp,1); + tmpval = force_number(arg); + if (prec == 0) + prec = 13; + (void) gcvt(tmpval, (int) prec, cpbuf); + prec = strlen(cpbuf); + cp = cpbuf; + if (fw > prec && !lj) { + if (fill != sp && *cp == '-') { + bchunk(cp, 1); cp++; prec--; } /* Deal with .5 as 0.5 */ - if(fill==sp && *cp=='.') { + if (fill == sp && *cp == '.') { --fw; - while(--fw>=prec) { - bchunk(fill,1); + 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); + 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; + 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); - chksize(fw+prec+5); /* 5==slop */ -/* cp=fcvt(tmpval,prec,&dec,&sgn); - prec=strlen(cp); - if(sgn) prec++; */ - cp=cpbuf; - *cp++='%'; - if(lj) *cp++='-'; - if(fill!=sp) *cp++='0'; - if(prec!=0) { - strcpy(cp,"*.*f"); - sprintf(obuf+olen,cpbuf,fw,prec,(double)tmpval); + tmpval = force_number(arg); + chksize(fw + prec + 5); /* 5==slop */ + + cp = cpbuf; + *cp++ = '%'; + if (lj) + *cp++ = '-'; + if (fill != sp) + *cp++ = '0'; + if (prec != 0) { + (void) strcpy(cp, "*.*f"); + (void) sprintf(obuf + olen, cpbuf, fw, prec, (double) tmpval); } else { - strcpy(cp,"*f"); - sprintf(obuf+olen,cpbuf,fw,(double)tmpval); + (void) strcpy(cp, "*f"); + (void) sprintf(obuf + olen, cpbuf, fw, (double) tmpval); } - cp=obuf+olen; - ofre-=strlen(obuf+olen); - olen+=strlen(obuf+olen);/* There may be nulls */ - s0=s1; + 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); - chksize(fw+prec+5); /* 5==slop */ - 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); + tmpval = force_number(arg); + chksize(fw + prec + 5); /* 5==slop */ + cp = cpbuf; + *cp++ = '%'; + if (lj) + *cp++ = '-'; + if (fill != sp) + *cp++ = '0'; + if (prec != 0) { + (void) strcpy(cp, "*.*e"); + (void) sprintf(obuf + olen, cpbuf, fw, prec, (double) tmpval); } else { - strcpy(cp,"*e"); - sprintf(obuf+olen,cpbuf,fw,(double)tmpval); + (void) strcpy(cp, "*e"); + (void) 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; + cp = obuf + olen; + ofre -= strlen(obuf + olen); + olen += strlen(obuf + olen); /* There may be nulls */ + 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: + lose: break; } } - bchunk(s0,s1-s0); - return tmp_string(obuf,olen); + bchunk(s0, s1 - s0); + return tmp_string(obuf, olen); } NODE * do_sqrt(tree) NODE *tree; { - NODE *tmp; - double sqrt(); + NODE *tmp; + double sqrt(); - get_one(tree,&tmp); - return tmp_number(sqrt(force_number(tmp))); + get_one(tree, &tmp); + return tmp_number((AWKNUM)sqrt((double)force_number(tmp))); } 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) + NODE *t1, *t2, *t3; + register int index, length; + + length = -1; + if (get_three(tree, &t1, &t2, &t3) == 3) + length = (int) force_number(t3); + index = (int) force_number(t2) - 1; + tree = force_string(t1); + if (length == -1) + length = tree->stlen; + if (index < 0) + index = 0; + if (index >= tree->stlen || length <= 0) return Nnull_string; - if(n1+n2>tree->stlen) - n2=tree->stlen-n1; - return tmp_string(tree->stptr+n1,n2); + if (index + length > tree->stlen) + length = tree->stlen - index; + return tmp_string(tree->stptr + index, length); } -/* The print command. Its name is historical */ -hack_print_node(tree) -NODE *tree; +NODE * +do_system(tree) +NODE *tree; { - register FILE *fp; + NODE *tmp; + int ret; + extern int flush_io (); + + (void) flush_io (); /* so output is syncrhonous with gawk's */ + get_one(tree, &tmp); + ret = system(force_string(tmp)->stptr); + ret = (ret >> 8) & 0xff; + return tmp_number((AWKNUM) ret); +} -#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); +/* The print command. Its name is historical */ +do_print(tree) +NODE *tree; +{ + register FILE *fp; + + fp = redirect(tree->rnode); + tree = tree->lnode; + if (!tree) + tree = WHOLELINE; + if (tree->type != Node_expression_list) { + if (!(tree->flags & STR)) + cant_happen(); + 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); + while (tree) { + print_simple(force_string(tree_eval(tree->lnode)), fp); + tree = tree->rnode; + if (tree) + print_simple(OFS_node->var_value, fp); } } - print_simple(ORS_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 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; +get_one(tree, res) +NODE *tree, **res; { - if(!tree) { - *res= WHOLELINE; + if (!tree) { + *res = WHOLELINE; return; } -#ifndef FAST - if(tree->type!=Node_expression_list) - abort(); -#endif - *res=tree_eval(tree->lnode); + *res = tree_eval(tree->lnode); } -get_two(tree,res1,res2) -NODE *tree,**res1,**res2; +get_two(tree, res1, res2) +NODE *tree, **res1, **res2; { - if(!tree) { - *res1= WHOLELINE; + if (!tree) { + *res1 = WHOLELINE; return; } -#ifndef FAST - if(tree->type!=Node_expression_list) - abort(); -#endif - *res1=tree_eval(tree->lnode); - if(!tree->rnode) + *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); + tree = tree->rnode; + *res2 = tree_eval(tree->lnode); } -get_three(tree,res1,res2,res3) -NODE *tree,**res1,**res2,**res3; +get_three(tree, res1, res2, res3) +NODE *tree, **res1, **res2, **res3; { - if(!tree) { - *res1= WHOLELINE; + if (!tree) { + *res1 = WHOLELINE; return 0; } -#ifndef FAST - if(tree->type!=Node_expression_list) - abort(); -#endif - *res1=tree_eval(tree->lnode); - if(!tree->rnode) + *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) + tree = tree->rnode; + *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); + tree = tree->rnode; + *res3 = tree_eval(tree->lnode); return 3; } -a_get_three(tree,res1,res2,res3) -NODE *tree,**res1,**res2,**res3; +a_get_three(tree, res1, res2, res3) +NODE *tree, **res1, **res2, **res3; { - if(!tree) { - *res1= WHOLELINE; + if (!tree) { + *res1 = WHOLELINE; return 0; } -#ifndef FAST - if(tree->type!=Node_expression_list) - abort(); -#endif - *res1=tree_eval(tree->lnode); - if(!tree->rnode) + *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) + tree = tree->rnode; + *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); + tree = tree->rnode; + *res3 = tree_eval(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 */ -inrec() -{ - 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; - extern FILE *input_file; - NODE **get_lhs(); - - rs = get_rs(); - fs = get_fs(); - blank_fields(); - NR++; - NF=0; - if(!buf) { - buf=malloc(128); - bsz=128; - buf_end=buf+bsz; +/* Redirection for printf and print commands */ +FILE * +redirect(tree) +NODE *tree; +{ + register NODE *tmp; + register struct redirect *rp; + register char *str; + register FILE *fp; + FILE *popen(); + FILE *fopen(); + int tflag; + char *direction = "to"; + + if (!tree) + return stdout; + tflag = 0; + switch (tree->type) { + case Node_redirect_append: + tflag = RED_APPEND; + case Node_redirect_output: + tflag |= (RED_FILE|RED_WRITE); + break; + case Node_redirect_pipe: + tflag = (RED_PIPE|RED_WRITE); + break; + case Node_redirect_pipein: + tflag = (RED_PIPE|RED_READ); + break; + case Node_redirect_input: + tflag = (RED_FILE|RED_READ); + break; + default: + fatal ("invalid tree type %d in redirect()\n", tree->type); + break; } - cur=buf; - cnt=0; - while ((c=getc(input_file))!=EOF) { - if((!rs && c=='\n' && cur[-1]=='\n' && cur!=buf) || (c == rs)) + tmp = force_string(tree_eval(tree->subnode)); + str = tmp->stptr; + for (rp = red_head; rp != NULL; rp = rp->next) + if (rp->flag == tflag && strcmp(rp->value, str) == 0) break; - *cur++=c; - cnt++; - if(cur==buf_end) { - buf=realloc(buf,bsz*2); - cur=buf+bsz; - bsz*=2; - buf_end=buf+bsz; - } + if (rp == NULL) { + emalloc(rp, struct redirect *, sizeof(struct redirect), + "redirect"); + emalloc(str, char *, strlen(tmp->stptr)+1, "redirect"); + (void) strcpy(str, tmp->stptr); + rp->value = str; + rp->flag = tflag; + rp->offset = 0; + rp->fp = NULL; + /* maintain list in most-recently-used first order */ + if (red_head) + red_head->prev = rp; + rp->prev = NULL; + rp->next = red_head; + red_head = rp; } - *cur='\0'; - set_field(0,buf,cnt); - assign_number(&(NF_node->var_value),0.0); - if(c==EOF && cnt==0) - return 1; - assign_number(&(NR_node->var_value),1.0+force_number(NR_node->var_value)); - for(tmp=buf;tmp<cur;tmp++) { - if(fs==' ') { - while((*tmp==' ' || *tmp=='\t') && tmp<cur) - tmp++; - if(tmp>=cur) - break; + while (rp->fp == NULL) { + errno = 0; + 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: + fp = rp->fp = popen(str, "w"); + break; + case Node_redirect_pipein: + direction = "from"; + fp = rp->fp = popen(str, "r"); + break; + case Node_redirect_input: + direction = "from"; + fp = rp->fp = fopen(str, "r"); + break; } - tcnt=0; - ttmp=tmp; - if(fs==' ') { - while(*tmp!=' ' && *tmp!='\t' && tmp<cur) { - tmp++; - tcnt++; - } - } else { - while(*tmp!=fs && tmp<cur) { - tmp++; - tcnt++; - } + if (fp == NULL) { + /* too many files open -- close one and try again */ + if (errno == ENFILE || errno == EMFILE) + close_one(); + else /* some other reason for failure */ + fatal("can't redirect %s `%s'\n", direction, + str); } - set_field(++NF,ttmp,tcnt); } - assign_number(&(NF_node->var_value),(AWKNUM)NF); - return 0; + if (rp->offset != 0) { /* this file was previously open */ + if (fseek(fp, rp->offset, 0) == -1) + fatal("can't seek to %ld on `%s'\n", rp->offset, str); + } +#ifdef notdef + (void) flush_io(); /* a la SVR4 awk */ +#endif + free_temp(tmp); + return rp->fp; } -/* Redirection for printf and print commands */ -FILE * -deal_redirect(tree) -NODE *tree; +close_one() { - register NODE *tmp; register struct redirect *rp; - register char *str; - register FILE *fp; - FILE *popen(); - int tflag; + register struct redirect *rplast; + + /* go to end of list first, to pick up least recently used entry */ + for (rp = red_head; rp != NULL; rp = rp->next) + rplast = rp; + /* now work back up through the list */ + for (rp = rplast; rp != NULL; rp = rp->prev) + if (rp->fp && (rp->flag & RED_FILE)) { + rp->offset = ftell(rp->fp); + if (fclose(rp->fp)) + warning("close of \"%s\" failed.", + rp->value); + rp->fp = NULL; + break; + } + if (rp == NULL) + /* surely this is the only reason ??? */ + fatal("too many pipes open"); +} +NODE * +do_close(tree) +NODE *tree; +{ + NODE *tmp; + register struct redirect *rp; - 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) + tmp = force_string(tree_eval(tree->subnode)); + for (rp = red_head; rp != NULL; rp = rp->next) { + if (strcmp(rp->value, tmp->stptr) == 0) break; } - if(rp==&reds[20]) { - panic("too many redirections",0); - return 0; + free_temp(tmp); + if (rp == NULL) /* no match */ + return tmp_number((AWKNUM) 0.0); + return tmp_number((AWKNUM)close_fp(rp)); +} + +int +close_fp(rp) +register struct redirect *rp; +{ + int status; + + if (rp->flag & RED_PIPE) + status = pclose(rp->fp); + else + status = fclose(rp->fp); + + /* SVR4 awk checks and warns about status of close */ + if (status) + warning("%s close of \"%s\" failed.", + (rp->flag & RED_PIPE) ? "pipe" : "file", rp->value); + if (rp->prev) + rp->prev->next = rp->next; + else + red_head = rp->next; + free(rp->value); + free(rp); + return status; +} + +int +flush_io () +{ + register struct redirect *rp; + int status = 0; + + if (fflush(stdout)) { + warning("error writing standard output."); + status++; } - 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: - fp=rp->fp=popen(str,"w"); - break; + if (fflush(stderr)) { + warning("error writing standard error."); + status++; } - if(fp==0) panic("can't redirect to '%s'\n",str); - rp++; - rp->flag=0; - return fp; + for (rp = red_head; rp != NULL; rp = rp->next) + /* flush both files and pipes, what the heck */ + if ((rp->flag & RED_WRITE) && rp->fp != NULL) + if (fflush(rp->fp)) { + warning( "%s flush of \"%s\" failed.", + (rp->flag & RED_PIPE) ? "pipe" : "file", + rp->value); + status++; + } + return status; } -print_simple(tree,fp) +int +close_io () +{ + register struct redirect *rp; + int status = 0; + + for (rp = red_head; rp != NULL; rp = rp->next) + if (rp->fp && close_fp(rp)) + status++; + return status; +} + +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; + if (fwrite(tree->stptr, sizeof(char), tree->stlen, fp) != tree->stlen) + warning("fwrite: %s", sys_errlist[errno]); + free_temp(tree); +} + +NODE * +do_atan2(tree) +NODE *tree; +{ + NODE *t1, *t2; + extern double atan2(); + + get_two(tree, &t1, &t2); + (void) force_number(t1); + return tmp_number((AWKNUM) atan2((double) t1->numbr, + (double) force_number(t2))); +} + +NODE * +do_sin(tree) +NODE *tree; +{ + NODE *tmp; + extern double sin(); + + get_one(tree, &tmp); + return tmp_number((AWKNUM) sin((double)force_number(tmp))); +} + +NODE * +do_cos(tree) +NODE *tree; +{ + NODE *tmp; + extern double cos(); + + get_one(tree, &tmp); + return tmp_number((AWKNUM) cos((double)force_number(tmp))); +} + +static int firstrand = 1; + +#ifndef USG +static char state[256]; +extern char *initstate(); + +#endif + +#define MAXLONG 2147483647 /* maximum value for long int */ + +/* ARGSUSED */ +NODE * +do_rand(tree) +NODE *tree; +{ +#ifdef USG + extern long lrand48(); + + return tmp_number((AWKNUM) lrand48() / MAXLONG); +#else + extern long random(); + + if (firstrand) { + (void) initstate((unsigned) 1, state, sizeof state); + srandom(1); + firstrand = 0; } + return tmp_number((AWKNUM) random() / MAXLONG); #endif - tree=force_string(tree); - fwrite(tree->stptr,sizeof(char),tree->stlen,fp); } +NODE * +do_srand(tree) +NODE *tree; +{ + NODE *tmp; + extern long time(); + static long save_seed = 1; + long ret = save_seed; /* SVR4 awk srand returns previous seed */ + +#ifdef USG + extern void srand48(); + + if (tree == NULL) + srand48(save_seed = time((long *) 0)); + else { + get_one(tree, &tmp); + srand48(save_seed = (long) force_number(tmp)); + } +#else + extern srandom(); + extern char *setstate(); + + if (firstrand) + (void) initstate((unsigned) 1, state, sizeof state); + else + (void) setstate(state); + + if (!tree) + srandom((int) (save_seed = time((long *) 0))); + else { + get_one(tree, &tmp); + srandom((int) (save_seed = (long) force_number(tmp))); + } +#endif + firstrand = 0; + return tmp_number((AWKNUM) ret); +} |