home *** CD-ROM | disk | FTP | other *** search
- /**
- * $Revision: 1.1 $
- * $Log: C:/AWK/AWK3.C_V $
- *
- * Rev 1.1 09 Sep 1988 18:29:58 vince
- * MC 5.1 version
- *
- * Rev 1.0 09 Sep 1988 18:03:06 vince
- * Original source
- *
- * awk3.c -- Builtin functions and various utility procedures
- *
- *
- * Copyright (C) 1986 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"
-
- 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
- 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);
- */
- 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
- 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
- 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
- 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
- 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);
- }