diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-15 23:12:49 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-15 23:12:49 +0300 |
commit | 3697ec5ca140f686643d204a54181a5ddbf9a799 (patch) | |
tree | 592873e8614475012ddd5f4e6d0482acadbfc9e2 /builtin.c | |
parent | f3d9dd233ac07f764a554528c85be3768a1d1ddb (diff) | |
download | egawk-3697ec5ca140f686643d204a54181a5ddbf9a799.tar.gz egawk-3697ec5ca140f686643d204a54181a5ddbf9a799.tar.bz2 egawk-3697ec5ca140f686643d204a54181a5ddbf9a799.zip |
Moved to gawk 2.11.
Diffstat (limited to 'builtin.c')
-rw-r--r-- | builtin.c | 1057 |
1 files changed, 1057 insertions, 0 deletions
diff --git a/builtin.c b/builtin.c new file mode 100644 index 00000000..b949a33b --- /dev/null +++ b/builtin.c @@ -0,0 +1,1057 @@ +/* + * builtin.c - Builtin functions and various utility procedures + */ + +/* + * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "awk.h" + +extern void srandom(); +extern char *initstate(); +extern char *setstate(); +extern long random(); + +extern NODE **fields_arr; + +static void get_one(); +static void get_two(); +static int get_three(); + +/* Builtin functions */ +NODE * +do_exp(tree) +NODE *tree; +{ + NODE *tmp; + double d, res; + double exp(); + + get_one(tree, &tmp); + d = force_number(tmp); + free_temp(tmp); + errno = 0; + res = exp(d); + if (errno == ERANGE) + warning("exp argument %g is out of range", d); + return tmp_number((AWKNUM) res); +} + +NODE * +do_index(tree) +NODE *tree; +{ + NODE *s1, *s2; + register char *p1, *p2; + register int l1, l2; + long ret; + + + get_two(tree, &s1, &s2); + force_string(s1); + force_string(s2); + p1 = s1->stptr; + p2 = s2->stptr; + l1 = s1->stlen; + l2 = s2->stlen; + ret = 0; + if (! strict && IGNORECASE_node->var_value->numbr != 0.0) { + while (l1) { + if (casetable[*p1] == casetable[*p2] + && strncasecmp(p1, p2, l2) == 0) { + ret = 1 + s1->stlen - l1; + break; + } + l1--; + p1++; + } + } else { + while (l1) { + if (STREQN(p1, p2, l2)) { + ret = 1 + s1->stlen - l1; + break; + } + l1--; + p1++; + } + } + free_temp(s1); + free_temp(s2); + return tmp_number((AWKNUM) ret); +} + +NODE * +do_int(tree) +NODE *tree; +{ + NODE *tmp; + double floor(); + double d; + + get_one(tree, &tmp); + d = floor((double)force_number(tmp)); + free_temp(tmp); + return tmp_number((AWKNUM) d); +} + +NODE * +do_length(tree) +NODE *tree; +{ + NODE *tmp; + int len; + + get_one(tree, &tmp); + len = force_string(tmp)->stlen; + free_temp(tmp); + return tmp_number((AWKNUM) len); +} + +NODE * +do_log(tree) +NODE *tree; +{ + NODE *tmp; + double log(); + double d, arg; + + get_one(tree, &tmp); + arg = (double) force_number(tmp); + if (arg < 0.0) + warning("log called with negative argument %g", arg); + d = log(arg); + free_temp(tmp); + return tmp_number((AWKNUM) d); +} + +/* + * 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 * +do_sprintf(tree) +NODE *tree; +{ +#define bchunk(s,l) if(l) {\ + while((l)>ofre) {\ + char *tmp;\ + tmp=(char *)alloca(osiz*2);\ + memcpy(tmp,obuf,olen);\ + obuf=tmp;\ + ofre+=osiz;\ + osiz*=2;\ + }\ + memcpy(obuf+olen,s,(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);\ + memcpy(tmp,obuf,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; + 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; +#ifdef sun386 /* Can't cast unsigned (int/long) from ptr->value */ + long tmp_uval; /* on 386i 4.0.1 C compiler -- it just hangs */ +#endif + 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; + int ucasehex = 0; + 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; + s1++; + +retry: + --n0; + switch (*s1++) { + case '%': + bchunk("%", 1); + s0 = s1; + break; + + case '0': + if (fill != sp || lj) + goto lose; + if (cur == &fw) + 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; +#ifdef not_yet + case ' ': /* print ' ' or '-' */ + case '+': /* print '+' or '-' */ +#endif + 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 'c': + parse_next_arg(); + if (arg->flags & NUMERIC) { +#ifdef sun386 + tmp_uval = arg->numbr; + uval= (unsigned long) tmp_uval; +#else + uval = (unsigned long) arg->numbr; +#endif + cpbuf[0] = uval; + prec = 1; + pr_str = cpbuf; + goto dopr_string; + } + if (! prec) + prec = 1; + else if (prec > arg->stlen) + prec = arg->stlen; + pr_str = arg->stptr; + 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; + free_temp(arg); + break; + case 'd': + case 'i': + parse_next_arg(); + val = (long) force_number(arg); + free_temp(arg); + if (val < 0) { + sgn = 1; + val = -val; + } else + sgn = 0; + do { + *--cp = '0' + val % 10; + val /= 10; + } while (val); + if (sgn) + *--cp = '-'; + if (prec > fw) + fw = prec; + 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': + ucasehex = 1; + case 'x': + base = 16; + goto pr_unsigned; + pr_unsigned: + parse_next_arg(); + uval = (unsigned long) force_number(arg); + free_temp(arg); + do { + *--cp = chbuf[uval % base]; + if (ucasehex && isalpha(*cp)) + *cp = toupper(*cp); + uval /= base; + } while (uval); + if (alt && (base == 8 || base == 16)) { + if (base == 16) { + if (ucasehex) + *--cp = 'X'; + else + *--cp = 'x'; + } + *--cp = '0'; + } + 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); + free_temp(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 == '.') { + --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; + case 'f': + parse_next_arg(); + tmpval = force_number(arg); + free_temp(arg); + chksize(fw + prec + 5); /* 5==slop */ + + cp = cpbuf; + *cp++ = '%'; + if (lj) + *cp++ = '-'; + if (fill != sp) + *cp++ = '0'; + if (cur != &fw) { + (void) strcpy(cp, "*.*f"); + (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval); + } else { + (void) strcpy(cp, "*f"); + (void) sprintf(obuf + olen, cpbuf, (int) 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); + free_temp(arg); + chksize(fw + prec + 5); /* 5==slop */ + cp = cpbuf; + *cp++ = '%'; + if (lj) + *cp++ = '-'; + if (fill != sp) + *cp++ = '0'; + if (cur != &fw) { + (void) strcpy(cp, "*.*e"); + (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval); + } else { + (void) strcpy(cp, "*e"); + (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval); + } + cp = obuf + olen; + ofre -= strlen(obuf + olen); + olen += strlen(obuf + olen); /* There may be nulls */ + s0 = s1; + break; + + default: + lose: + break; + } + } + bchunk(s0, s1 - s0); + free_temp(sfmt); + return tmp_string(obuf, olen); +} + +void +do_printf(tree) +NODE *tree; +{ + struct redirect *rp = NULL; + register FILE *fp = stdout; + int errflg = 0; /* not used, sigh */ + + if (tree->rnode) { + rp = redirect(tree->rnode, &errflg); + if (rp) + fp = rp->fp; + } + if (fp) + print_simple(do_sprintf(tree->lnode), fp); + if (rp && (rp->flag & RED_NOBUF)) + fflush(fp); +} + +NODE * +do_sqrt(tree) +NODE *tree; +{ + NODE *tmp; + double sqrt(); + double d, arg; + + get_one(tree, &tmp); + arg = (double) force_number(tmp); + if (arg < 0.0) + warning("sqrt called with negative argument %g", arg); + d = sqrt(arg); + free_temp(tmp); + return tmp_number((AWKNUM) d); +} + +NODE * +do_substr(tree) +NODE *tree; +{ + NODE *t1, *t2, *t3; + NODE *r; + register int indx, length; + + t1 = t2 = t3 = NULL; + length = -1; + if (get_three(tree, &t1, &t2, &t3) == 3) + length = (int) force_number(t3); + indx = (int) force_number(t2) - 1; + t1 = force_string(t1); + if (length == -1) + length = t1->stlen; + if (indx < 0) + indx = 0; + if (indx >= t1->stlen || length <= 0) { + if (t3) + free_temp(t3); + free_temp(t2); + free_temp(t1); + return Nnull_string; + } + if (indx + length > t1->stlen) + length = t1->stlen - indx; + if (t3) + free_temp(t3); + free_temp(t2); + r = tmp_string(t1->stptr + indx, length); + free_temp(t1); + return r; +} + +NODE * +do_system(tree) +NODE *tree; +{ +#if defined(unix) || defined(MSDOS) /* || defined(gnu) */ + NODE *tmp; + int ret; + + (void) flush_io (); /* so output is synchronous with gawk's */ + get_one(tree, &tmp); + ret = system(force_string(tmp)->stptr); + ret = (ret >> 8) & 0xff; + free_temp(tmp); + return tmp_number((AWKNUM) ret); +#else + fatal("the \"system\" function is not supported."); + /* NOTREACHED */ +#endif +} + +void +do_print(tree) +register NODE *tree; +{ + struct redirect *rp = NULL; + register FILE *fp = stdout; + int errflg = 0; /* not used, sigh */ + + if (tree->rnode) { + rp = redirect(tree->rnode, &errflg); + if (rp) + fp = rp->fp; + } + if (!fp) + return; + 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(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); + if (rp && (rp->flag & RED_NOBUF)) + fflush(fp); +} + +NODE * +do_tolower(tree) +NODE *tree; +{ + NODE *t1, *t2; + register char *cp, *cp2; + + get_one(tree, &t1); + t1 = force_string(t1); + t2 = tmp_string(t1->stptr, t1->stlen); + for (cp = t2->stptr, cp2 = t2->stptr + t2->stlen; cp < cp2; cp++) + if (isupper(*cp)) + *cp = tolower(*cp); + free_temp(t1); + return t2; +} + +NODE * +do_toupper(tree) +NODE *tree; +{ + NODE *t1, *t2; + register char *cp; + + get_one(tree, &t1); + t1 = force_string(t1); + t2 = tmp_string(t1->stptr, t1->stlen); + for (cp = t2->stptr; cp < t2->stptr + t2->stlen; cp++) + if (islower(*cp)) + *cp = toupper(*cp); + free_temp(t1); + return t2; +} + +/* + * 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. + */ + +static void +get_one(tree, res) +NODE *tree, **res; +{ + if (!tree) { + *res = WHOLELINE; + return; + } + *res = tree_eval(tree->lnode); +} + +static void +get_two(tree, res1, res2) +NODE *tree, **res1, **res2; +{ + if (!tree) { + *res1 = WHOLELINE; + return; + } + *res1 = tree_eval(tree->lnode); + if (!tree->rnode) + return; + tree = tree->rnode; + *res2 = tree_eval(tree->lnode); +} + +static int +get_three(tree, res1, res2, res3) +NODE *tree, **res1, **res2, **res3; +{ + if (!tree) { + *res1 = WHOLELINE; + return 0; + } + *res1 = tree_eval(tree->lnode); + if (!tree->rnode) + return 1; + tree = tree->rnode; + *res2 = tree_eval(tree->lnode); + if (!tree->rnode) + return 2; + tree = tree->rnode; + *res3 = tree_eval(tree->lnode); + return 3; +} + +int +a_get_three(tree, res1, res2, res3) +NODE *tree, **res1, **res2, **res3; +{ + if (!tree) { + *res1 = WHOLELINE; + return 0; + } + *res1 = tree_eval(tree->lnode); + if (!tree->rnode) + return 1; + tree = tree->rnode; + *res2 = tree->lnode; + if (!tree->rnode) + return 2; + tree = tree->rnode; + *res3 = tree_eval(tree->lnode); + return 3; +} + +void +print_simple(tree, fp) +NODE *tree; +FILE *fp; +{ + if (fwrite(tree->stptr, sizeof(char), tree->stlen, fp) != tree->stlen) + warning("fwrite: %s", strerror(errno)); + free_temp(tree); +} + +NODE * +do_atan2(tree) +NODE *tree; +{ + NODE *t1, *t2; + extern double atan2(); + double d1, d2; + + get_two(tree, &t1, &t2); + d1 = force_number(t1); + d2 = force_number(t2); + free_temp(t1); + free_temp(t2); + return tmp_number((AWKNUM) atan2(d1, d2)); +} + +NODE * +do_sin(tree) +NODE *tree; +{ + NODE *tmp; + extern double sin(); + double d; + + get_one(tree, &tmp); + d = sin((double)force_number(tmp)); + free_temp(tmp); + return tmp_number((AWKNUM) d); +} + +NODE * +do_cos(tree) +NODE *tree; +{ + NODE *tmp; + extern double cos(); + double d; + + get_one(tree, &tmp); + d = cos((double)force_number(tmp)); + free_temp(tmp); + return tmp_number((AWKNUM) d); +} + +static int firstrand = 1; +static char state[256]; + +#define MAXLONG 2147483647 /* maximum value for long int */ + +/* ARGSUSED */ +NODE * +do_rand(tree) +NODE *tree; +{ + if (firstrand) { + (void) initstate((unsigned) 1, state, sizeof state); + srandom(1); + firstrand = 0; + } + return tmp_number((AWKNUM) random() / MAXLONG); +} + +NODE * +do_srand(tree) +NODE *tree; +{ + NODE *tmp; + static long save_seed = 1; + long ret = save_seed; /* SVR4 awk srand returns previous seed */ + extern long time(); + + 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))); + free_temp(tmp); + } + firstrand = 0; + return tmp_number((AWKNUM) ret); +} + +NODE * +do_match(tree) +NODE *tree; +{ + NODE *t1; + int rstart; + struct re_registers reregs; + struct re_pattern_buffer *rp; + int need_to_free = 0; + + t1 = force_string(tree_eval(tree->lnode)); + tree = tree->rnode; + if (tree == NULL || tree->lnode == NULL) + fatal("match called with only one argument"); + tree = tree->lnode; + if (tree->type == Node_regex) { + rp = tree->rereg; + if (!strict && ((IGNORECASE_node->var_value->numbr != 0) + ^ (tree->re_case != 0))) { + /* recompile since case sensitivity differs */ + rp = tree->rereg = + mk_re_parse(tree->re_text, + (IGNORECASE_node->var_value->numbr != 0)); + tree->re_case = + (IGNORECASE_node->var_value->numbr != 0); + } + } else { + need_to_free = 1; + rp = make_regexp(force_string(tree_eval(tree)), + (IGNORECASE_node->var_value->numbr != 0)); + if (rp == NULL) + cant_happen(); + } + rstart = re_search(rp, t1->stptr, t1->stlen, 0, t1->stlen, &reregs); + free_temp(t1); + if (rstart >= 0) { + rstart++; /* 1-based indexing */ + /* RSTART set to rstart below */ + RLENGTH_node->var_value->numbr = + (AWKNUM) (reregs.end[0] - reregs.start[0]); + } else { + /* + * Match failed. Set RSTART to 0, RLENGTH to -1. + * Return the value of RSTART. + */ + rstart = 0; /* used as return value */ + RLENGTH_node->var_value->numbr = -1.0; + } + RSTART_node->var_value->numbr = (AWKNUM) rstart; + if (need_to_free) { + free(rp->buffer); + free(rp->fastmap); + free((char *) rp); + } + return tmp_number((AWKNUM) rstart); +} + +static NODE * +sub_common(tree, global) +NODE *tree; +int global; +{ + register int len; + register char *scan; + register char *bp, *cp; + int search_start = 0; + int match_length; + int matches = 0; + char *buf; + struct re_pattern_buffer *rp; + NODE *s; /* subst. pattern */ + NODE *t; /* string to make sub. in; $0 if none given */ + struct re_registers reregs; + unsigned int saveflags; + NODE *tmp; + NODE **lhs; + char *lastbuf; + int need_to_free = 0; + + if (tree == NULL) + fatal("sub or gsub called with 0 arguments"); + tmp = tree->lnode; + if (tmp->type == Node_regex) { + rp = tmp->rereg; + if (! strict && ((IGNORECASE_node->var_value->numbr != 0) + ^ (tmp->re_case != 0))) { + /* recompile since case sensitivity differs */ + rp = tmp->rereg = + mk_re_parse(tmp->re_text, + (IGNORECASE_node->var_value->numbr != 0)); + tmp->re_case = (IGNORECASE_node->var_value->numbr != 0); + } + } else { + need_to_free = 1; + rp = make_regexp(force_string(tree_eval(tmp)), + (IGNORECASE_node->var_value->numbr != 0)); + if (rp == NULL) + cant_happen(); + } + tree = tree->rnode; + if (tree == NULL) + fatal("sub or gsub called with only 1 argument"); + s = force_string(tree_eval(tree->lnode)); + tree = tree->rnode; + deref = 0; + field_num = -1; + if (tree == NULL) { + t = node0_valid ? fields_arr[0] : *get_field(0, 0); + lhs = &fields_arr[0]; + field_num = 0; + deref = t; + } else { + t = tree->lnode; + lhs = get_lhs(t, 1); + t = force_string(tree_eval(t)); + } + /* + * create a private copy of the string + */ + if (t->stref > 1 || (t->flags & PERM)) { + saveflags = t->flags; + t->flags &= ~MALLOC; + tmp = dupnode(t); + t->flags = saveflags; + do_deref(); + t = tmp; + if (lhs) + *lhs = tmp; + } + lastbuf = t->stptr; + do { + if (re_search(rp, t->stptr, t->stlen, search_start, + t->stlen-search_start, &reregs) == -1 + || reregs.start[0] == reregs.end[0]) + break; + matches++; + + /* + * first, make a pass through the sub. pattern, to calculate + * the length of the string after substitution + */ + match_length = reregs.end[0] - reregs.start[0]; + len = t->stlen - match_length; + for (scan = s->stptr; scan < s->stptr + s->stlen; scan++) + if (*scan == '&') + len += match_length; + else if (*scan == '\\' && *(scan+1) == '&') { + scan++; + len++; + } else + len++; + emalloc(buf, char *, len + 1, "do_sub"); + bp = buf; + + /* + * now, create the result, copying in parts of the original + * string + */ + for (scan = t->stptr; scan < t->stptr + reregs.start[0]; scan++) + *bp++ = *scan; + for (scan = s->stptr; scan < s->stptr + s->stlen; scan++) + if (*scan == '&') + for (cp = t->stptr + reregs.start[0]; + cp < t->stptr + reregs.end[0]; cp++) + *bp++ = *cp; + else if (*scan == '\\' && *(scan+1) == '&') { + scan++; + *bp++ = *scan; + } else + *bp++ = *scan; + search_start = bp - buf; + for (scan = t->stptr + reregs.end[0]; + scan < t->stptr + t->stlen; scan++) + *bp++ = *scan; + *bp = '\0'; + free(lastbuf); + t->stptr = buf; + lastbuf = buf; + t->stlen = len; + } while (global && search_start < t->stlen); + + free_temp(s); + if (need_to_free) { + free(rp->buffer); + free(rp->fastmap); + free((char *) rp); + } + if (matches > 0) { + if (field_num == 0) + set_record(fields_arr[0]->stptr, fields_arr[0]->stlen); + t->flags &= ~(NUM|NUMERIC); + } + field_num = -1; + return tmp_number((AWKNUM) matches); +} + +NODE * +do_gsub(tree) +NODE *tree; +{ + return sub_common(tree, 1); +} + +NODE * +do_sub(tree) +NODE *tree; +{ + return sub_common(tree, 0); +} + |