home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
dirs
/
gnuawk_406.lzh
/
GnuAwk
/
src.lzh
/
src
/
awk4.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-04-13
|
11KB
|
405 lines
/*
* 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);
}