home *** CD-ROM | disk | FTP | other *** search
- /*
- * awk4 -- Code for features in new AWK, System V compatibility.
- *
- * $Log: awk4.c,v $
- * Revision 1.38 89/03/31 13:26:09 david
- * GNU license
- *
- * Revision 1.37 89/03/29 14:19:07 david
- * delinting and code movement
- *
- * Revision 1.36 89/03/22 22:10:23 david
- * a cleaner way to handle assignment to $n where n > 0
- *
- * Revision 1.35 89/03/22 21:05:24 david
- * delete some obsolete code
- *
- * Revision 1.34 89/03/22 21:00:34 david
- * replace some free()'s with freenode()
- *
- * Revision 1.33 89/03/21 19:26:01 david
- * minor cleanup
- *
- * Revision 1.32 89/03/21 18:22:54 david
- * some function tracing debugging code
- *
- * Revision 1.31 89/03/21 10:53:21 david
- * cleanup
- *
- * Revision 1.30 89/03/15 22:22:03 david
- * fix from hack: check for null function before using it in diagnostic
- *
- * Revision 1.29 89/03/15 22:02:24 david
- * new case stuff added
- *
- * Revision 1.28 89/03/15 21:34:37 david
- * free more memory and purge obstack stuff
- *
- * Revision 1.27 88/12/14 10:53:49 david
- * malloc structures in func_call and free them on return
- *
- * Revision 1.26 88/12/13 22:29:15 david
- * minor change
- *
- * Revision 1.25 88/12/08 10:52:01 david
- * small correction to #ifdef'ing
- *
- * Revision 1.24 88/11/30 15:18:21 david
- * fooling around with memory allocation in func_call() but this new code remains
- * #ifdef'd out
- * correction to creasting private copy of string in do_sub()
- *
- * Revision 1.23 88/11/29 09:55:48 david
- * corrections to code that tracks value of NF -- this needs cleanup
- *
- * Revision 1.22 88/11/28 20:30:10 david
- * bug fix for do_sub when third arg. not specified
- *
- * Revision 1.21 88/11/22 13:51:10 david
- * Arnold: delinting
- *
- * Revision 1.20 88/11/15 10:25:14 david
- * Arnold: minor cleanup
- *
- * Revision 1.19 88/11/14 22:00:09 david
- * Arnold: error message on bad regexp; correction to handling of RSTART in
- * match() on failure; return arg handling to previous behaviour: var=val
- * arg is processed whne it is encountered.
- *
- * Revision 1.18 88/11/14 21:28:09 david
- * moved concat_exp(); update NF on assign to field > NF; temporarily aborted
- * mods. in func_call(); flag misnamed as TMP becomes PERM (don't free)
- *
- * Revision 1.17 88/11/01 12:19:37 david
- * cleanup and substantial changes to do_sub()
- *
- * Revision 1.16 88/10/19 21:59:20 david
- * replace malloc and realloc with error checking versions
- *
- * Revision 1.15 88/10/17 20:54:54 david
- * SYSV --> USG
- *
- * Revision 1.14 88/10/13 22:00:44 david
- * purge FAST and cleanup error messages
- *
- * Revision 1.13 88/10/11 09:29:12 david
- * retrieve parameters from the stack in func_call
- *
- * Revision 1.12 88/10/06 21:53:15 david
- * added FSF copyleft; Arnold's changes to command line processing
- *
- *
- */
-
- /*
- * 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 NODE **fields_arr;
-
- jmp_buf func_tag;
- NODE **stack_ptr;
-
- NODE *
- func_call(name, arg_list)
- NODE *name; /* name is a Node_val giving function name */
- NODE *arg_list; /* Node_expression_list of calling args. */
- {
- register NODE *arg, *argp, *r;
- NODE *n, *f;
- jmp_buf func_tag_stack;
- NODE *ret_node_stack;
- NODE **local_stack;
- NODE **sp;
- static int func_tag_valid = 0;
- int count;
- extern NODE *ret_node;
-
- /*
- * retrieve function definition node
- */
- f = lookup(variables, name->stptr);
- if (!f || f->type != Node_func)
- fatal("function `%s' not defined", name->stptr);
- #ifdef FUNC_TRACE
- fprintf(stderr, "function %s called\n", name->stptr);
- #endif
- /*
- * mark stack for variables allocated during life of function
- */
- count = f->lnode->param_cnt;
- emalloc(local_stack, NODE **, count * sizeof(NODE *), "func_call");
- sp = local_stack;
-
- /*
- * for each calling arg. add NODE * on stack
- */
- for (argp = arg_list; count && argp != NULL; argp = argp->rnode) {
- arg = argp->lnode;
- r = newnode(Node_var);
- /*
- * call by reference for arrays; see below also
- */
- if (arg->type == Node_param_list)
- arg = stack_ptr[arg->param_cnt];
- if (arg->type == Node_var_array)
- *r = *arg;
- else {
- n = dupnode(tree_eval(arg));
- r->lnode = n;
- r->rnode = (NODE *) NULL;
- }
- *sp++ = r;
- count--;
- }
- if (argp != NULL) /* left over calling args. */
- warning(
- "function `%s' called with more arguments than declared",
- name->stptr);
- /*
- * add remaining params. on stack with null value
- */
- while (count-- > 0) {
- r = newnode(Node_var);
- r->lnode = Nnull_string;
- r->rnode = (NODE *) NULL;
- *sp++ = r;
- }
-
- /*
- * execute function body, saving context, as a return statement
- * will longjmp back here
- */
- sp = local_stack;
- local_stack = stack_ptr;
- stack_ptr = sp;
- PUSH_BINDING(func_tag_stack, func_tag, func_tag_valid);
- ret_node_stack = ret_node;
- if (_setjmp(func_tag) == 0)
- (void) interpret(f->rnode);
- r = ret_node;
- ret_node = ret_node_stack;
- RESTORE_BINDING(func_tag_stack, func_tag, func_tag_valid);
- sp = stack_ptr;
- stack_ptr = local_stack;
- local_stack = sp;
-
- /*
- * here, we pop each parameter and check whether
- * it was an array. If so, and if the arg. passed in was
- * a simple variable, then the value should be copied back.
- * This achieves "call-by-reference" for arrays.
- */
- count = f->lnode->param_cnt;
- for (argp = arg_list; count-- > 0 && argp != NULL; argp = argp->rnode) {
- arg = argp->lnode;
- n = *sp++;
- if (arg->type == Node_var && n->type == Node_var_array) {
- arg->var_array = n->var_array;
- arg->type = Node_var_array;
- }
- deref = n->lnode;
- do_deref();
- freenode(n);
- }
- while (count-- > 0) {
- n = *sp++;
- deref = n->lnode;
- do_deref();
- freenode(n);
- }
- free((char *) local_stack);
- return r;
- }
-
- NODE *
- do_match(tree)
- NODE *tree;
- {
- NODE *t1;
- int rstart;
- struct re_registers reregs;
- struct re_pattern_buffer *rp;
-
- t1 = force_string(tree_eval(tree->lnode));
- if (tree->rnode->type == Node_regex) {
- rp = tree->rnode->rereg;
- if (!strict && ((IGNORECASE_node->var_value->numbr != 0)
- ^ (tree->rnode->re_case != 0))) {
- /* recompile since case sensitivity differs */
- rp = tree->rnode->rereg =
- mk_re_parse(tree->rnode->re_text,
- (IGNORECASE_node->var_value->numbr != 0));
- tree->rnode->re_case = (IGNORECASE_node->var_value->numbr != 0);
- }
- } else {
- rp = make_regexp(force_string(tree_eval(tree->rnode)),
- (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;
- return tmp_number((AWKNUM) rstart);
- }
-
- NODE *
- do_sub(tree)
- NODE *tree;
- {
- register int len;
- register char *scan;
- register char *bp, *cp;
- int search_start = 0;
- int match_length;
- int matches = 0;
- char *buf;
- int global;
- 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;
-
- global = (tree->type == Node_gsub);
-
- if (tree->rnode->type == Node_regex) {
- rp = tree->rnode->rereg;
- if (! strict && ((IGNORECASE_node->var_value->numbr != 0)
- ^ (tree->rnode->re_case != 0))) {
- /* recompile since case sensitivity differs */
- rp = tree->rnode->rereg =
- mk_re_parse(tree->rnode->re_text,
- (IGNORECASE_node->var_value->numbr != 0));
- tree->rnode->re_case = (IGNORECASE_node->var_value->numbr != 0);
- }
- } else {
- rp = make_regexp(force_string(tree_eval(tree->rnode)),
- (IGNORECASE_node->var_value->numbr != 0));
- if (rp == NULL)
- cant_happen();
- }
- tree = tree->lnode;
- 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 (matches > 0) {
- if (field_num == 0)
- set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
- t->flags &= ~NUM;
- }
- field_num = -1;
- return tmp_number((AWKNUM) matches);
- }
-