home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / TOP / USR / SRC / gawk2.0.t.Z / gawk2.0.t / awk4.c < prev    next >
Text File  |  1988-12-31  |  11KB  |  428 lines

  1. /*
  2.  * awk4 -- Code for features in new AWK, System V compatibility.
  3.  *
  4.  * Copyright (C) 1988 Free Software Foundation
  5.  * Written by David Trueman, 1988
  6.  *
  7.  * $Log:    awk4.c,v $
  8.  * Revision 1.25  88/12/08  10:52:01  david
  9.  * small correction to #ifdef'ing
  10.  * 
  11.  * Revision 1.24  88/11/30  15:18:21  david
  12.  * fooling around with memory allocation in func_call() but this new code remains
  13.  * #ifdef'd out
  14.  * correction to creasting private copy of string in do_sub()
  15.  * 
  16.  * Revision 1.23  88/11/29  09:55:48  david
  17.  * corrections to code that tracks value of NF -- this needs cleanup
  18.  * 
  19.  * Revision 1.22  88/11/28  20:30:10  david
  20.  * bug fix for do_sub when third arg. not specified
  21.  * 
  22.  * Revision 1.21  88/11/22  13:51:10  david
  23.  * Arnold: delinting
  24.  * 
  25.  * Revision 1.20  88/11/15  10:25:14  david
  26.  * Arnold: minor cleanup
  27.  * 
  28.  * Revision 1.19  88/11/14  22:00:09  david
  29.  * Arnold: error message on bad regexp; correction to handling of RSTART in
  30.  * match() on failure; return arg handling to previous behaviour: var=val
  31.  * arg is processed whne it is encountered.
  32.  * 
  33.  * Revision 1.18  88/11/14  21:28:09  david
  34.  * moved concat_exp(); update NF on assign to field > NF; temporarily aborted
  35.  * mods. in func_call(); flag misnamed as TMP becomes PERM (don't free)
  36.  * 
  37.  * Revision 1.17  88/11/01  12:19:37  david
  38.  * cleanup and substantial changes to do_sub()
  39.  * 
  40.  * Revision 1.16  88/10/19  21:59:20  david
  41.  * replace malloc and realloc with error checking versions
  42.  * 
  43.  * Revision 1.15  88/10/17  20:54:54  david
  44.  * SYSV --> USG
  45.  * 
  46.  * Revision 1.14  88/10/13  22:00:44  david
  47.  * purge FAST and cleanup error messages
  48.  * 
  49.  * Revision 1.13  88/10/11  09:29:12  david
  50.  * retrieve parameters from the stack in func_call
  51.  * 
  52.  * Revision 1.12  88/10/06  21:53:15  david
  53.  * added FSF copyleft; Arnold's changes to command line processing
  54.  * 
  55.  *
  56.  */
  57.  
  58. /*
  59.  * GAWK is distributed in the hope that it will be useful, but WITHOUT ANY
  60.  * WARRANTY.  No author or distributor accepts responsibility to anyone for
  61.  * the consequences of using it or for whether it serves any particular
  62.  * purpose or works at all, unless he says so in writing. Refer to the GAWK
  63.  * General Public License for full details. 
  64.  *
  65.  * Everyone is granted permission to copy, modify and redistribute GAWK, but
  66.  * only under the conditions described in the GAWK General Public License.  A
  67.  * copy of this license is supposed to have been given to you along with GAWK
  68.  * so you can know your rights and responsibilities.  It should be in a file
  69.  * named COPYING.  Among other things, the copyright notice and this notice
  70.  * must be preserved on all copies. 
  71.  *
  72.  * In other words, go ahead and share GAWK, but don't try to stop anyone else
  73.  * from sharing it farther.  Help stamp out software hoarding! 
  74.  */
  75.  
  76. #include "awk.h"
  77.  
  78. NODE *ARGC_node, *ARGV_node;
  79. extern NODE **fields_arr;
  80.  
  81. extern NODE *tree_eval();
  82.  
  83. jmp_buf func_tag;
  84. NODE **stack_ptr;
  85.  
  86. NODE *
  87. func_call(name, arg_list)
  88. NODE *name;        /* name is a Node_val giving function name */
  89. NODE *arg_list;        /* Node_expression_list of calling args. */
  90. {
  91.     register NODE *arg, *argp, *r;
  92.     NODE *n, *f, *p;
  93.     char *func_begin;
  94.     auto jmp_buf func_tag_stack;
  95.     auto NODE *ret_node_stack;
  96.     auto NODE **local_stack;
  97.     auto NODE **sp;
  98.     static int func_tag_valid = 0;
  99.     int count;
  100.     extern NODE *lookup(), *install(), *tree_eval();
  101.     extern NODE *pop_var();
  102.     extern NODE *ret_node;
  103.     extern struct obstack var_stack;
  104.  
  105.     /*
  106.      * retrieve function definition node
  107.      */
  108.     f = lookup(variables, name->stptr);
  109.     if (f->type != Node_func)
  110.         fatal("function `%s' not defined", name->stptr);
  111.     /*
  112.      * mark stack for variables allocated during life of function
  113.      */
  114.     count = f->lnode->param_cnt;
  115. #ifndef notdef
  116.     func_begin = obstack_alloc(&var_stack, 0);
  117.     local_stack = (NODE **) obstack_alloc(&var_stack,
  118.         count * sizeof(NODE *));
  119. #else
  120.     emalloc(local_stack, NODE **, count * sizeof(NODE *), "func_call");
  121. #endif
  122.     sp = local_stack;
  123.  
  124.     /*
  125.      * for each calling arg. add NODE * on stack
  126.      */
  127.     for (argp = arg_list; count && argp != NULL; argp = argp->rnode) {
  128.         arg = argp->lnode;
  129. #ifndef notdef
  130.         r = (NODE *) obstack_alloc(&var_stack, sizeof(NODE));
  131. #else
  132.         r = newnode(Node_var);
  133. #endif
  134.         /*
  135.          * call by reference for arrays; see below also
  136.          */
  137.         if (arg->type == Node_param_list)
  138.             arg = stack_ptr[arg->param_cnt];
  139.         if (arg->type == Node_var_array)
  140.             *r = *arg;
  141.         else {
  142. #ifdef notdef
  143.             n = tree_eval(arg);
  144.             p = (NODE *) obstack_alloc(&var_stack, sizeof(NODE));
  145.             *p = *n;
  146.             if (p->flags & STR) {
  147.                 p->stptr = (char *) obstack_alloc(&var_stack,
  148.                     p->stlen+1);
  149.                 p->stref = 1;
  150.                 bcopy(n->stptr, p->stptr, p->stlen+1);
  151.             }
  152.             p->flags &= ~(MALLOC|TEMP);
  153.             p->flags |= PERM;
  154.             FREE_TEMP(n);
  155.             r->lnode = p;
  156. #else
  157.             n = dupnode(tree_eval(arg));
  158.             r->lnode = n;
  159. #endif
  160.             r->type = Node_var;
  161.             r->rnode = (NODE *) NULL;
  162.           }
  163.         r->flags = PERM;    /* mustn't be free'd */
  164.         *sp++ = r;
  165.         count--;
  166.     }
  167.     if (argp != NULL)    /* left over calling args. */
  168.         warning(
  169.             "function `%s' called with more arguments than declared",
  170.             name->stptr);
  171.     /*
  172.      * add remaining params. on stack with null value
  173.      */
  174.     while (count-- > 0) {
  175. #ifndef notdef
  176.         r = (NODE *) obstack_alloc(&var_stack, sizeof(NODE));
  177.         r->type = Node_var;
  178. #else
  179.         r = newnode(Node_var);
  180. #endif
  181.         r->lnode = Nnull_string;
  182.         r->rnode = (NODE *) NULL;
  183.         r->flags = PERM;
  184.         *sp++ = r;
  185.     }
  186.  
  187.     /*
  188.      * execute function body, saving context, as a return statement
  189.      * will longjmp back here
  190.      */
  191.     sp = local_stack;
  192.     local_stack = stack_ptr;
  193.     stack_ptr = sp;
  194.     PUSH_BINDING(func_tag_stack, func_tag, func_tag_valid);
  195.     ret_node_stack = ret_node;
  196.     if (_setjmp(func_tag) == 0)
  197.         (void) interpret(f->rnode);
  198.     r = ret_node;
  199.     ret_node = ret_node_stack;
  200.     RESTORE_BINDING(func_tag_stack, func_tag, func_tag_valid);
  201.     sp = stack_ptr;
  202.     stack_ptr = local_stack;
  203.     local_stack = sp;
  204.  
  205.     /*
  206.      * here, we pop each parameter and check whether
  207.      * it was an array.  If so, and if the arg. passed in was
  208.      * a simple variable, then the value should be copied back.
  209.      * This achieves "call-by-reference" for arrays.
  210.      */
  211.     count = f->lnode->param_cnt;
  212.     for (argp = arg_list; count-- && argp != NULL; argp = argp->rnode) {
  213.         arg = argp->lnode;
  214.         n = *sp++;
  215.         if (arg->type == Node_var && n->type == Node_var_array) {
  216.             arg->var_array = n->var_array;
  217.             arg->type = Node_var_array;
  218.         }
  219.     }
  220. #ifndef notdef
  221.     obstack_free(&var_stack, func_begin);
  222. #else
  223.     free((char *) local_stack);
  224. #endif
  225.     return r;
  226. }
  227.  
  228. NODE *
  229. do_match(tree)
  230. NODE *tree;
  231. {
  232.     NODE *t1;
  233.     int rstart;
  234.     struct re_registers reregs;
  235.     struct re_pattern_buffer *rp;
  236.     extern NODE *RSTART_node, *RLENGTH_node;
  237.  
  238.     t1 = force_string(tree_eval(tree->lnode));
  239.     if (tree->rnode->type == Node_regex)
  240.         rp = tree->rnode->rereg;
  241.     else {
  242.         rp = make_regexp(force_string(tree_eval(tree->rnode)));
  243.         if (rp == NULL)
  244.             cant_happen();
  245.     }
  246.     rstart = re_search(rp, t1->stptr, t1->stlen, 0, t1->stlen, &reregs);
  247.     if (rstart >= 0) {
  248.         rstart++;    /* 1-based indexing */
  249.         /* RSTART set to rstart below */
  250.         RLENGTH_node->var_value->numbr =
  251.             (AWKNUM) (reregs.end[0] - reregs.start[0]);
  252.     } else {
  253.         /*
  254.          * Match failed. Set RSTART to 0, RLENGTH to -1.
  255.          * Return the value of RSTART.
  256.          */
  257.         rstart = 0;    /* used as return value */
  258.         RLENGTH_node->var_value->numbr = -1.0;
  259.     }
  260.     RSTART_node->var_value->numbr = (AWKNUM) rstart;
  261.     return tmp_number((AWKNUM) rstart);
  262. }
  263.  
  264. NODE *
  265. do_sub(tree)
  266. NODE *tree;
  267. {
  268.     register int len;
  269.     register char *scan;
  270.     register char *bp, *cp;
  271.     int search_start = 0;
  272.     int match_length;
  273.     int matches = 0;
  274.     char *buf;
  275.     int global;
  276.     struct re_pattern_buffer *rp;
  277.     NODE *s;        /* subst. pattern */
  278.     NODE *t;        /* string to make sub. in; $0 if none given */
  279.     struct re_registers reregs;
  280.     unsigned int saveflags;
  281.     NODE *tmp;
  282.     NODE **lhs;
  283.     char *lastbuf;
  284.  
  285.     global = (tree->type == Node_gsub);
  286.  
  287.     if (tree->rnode->type == Node_regex)
  288.         rp = tree->rnode->rereg;
  289.     else {
  290.         rp = make_regexp(force_string(tree_eval(tree->rnode)));
  291.         if (rp == NULL)
  292.             cant_happen();
  293.     }
  294.     tree = tree->lnode;
  295.     s = force_string(tree_eval(tree->lnode));
  296.     tree = tree->rnode;
  297.     deref = 0;
  298.     if (tree == NULL) {
  299.         t = WHOLELINE;
  300.         lhs = &fields_arr[0];
  301.         field_num = 0;
  302.         deref = t;
  303.     } else {
  304.         t = tree->lnode;
  305.         lhs = get_lhs(t);
  306.         t = force_string(tree_eval(t));
  307.     }
  308.     /*
  309.      * create a private copy of the string
  310.      */
  311.     if (t->stref > 1 || (t->flags & PERM)) {
  312.         saveflags = t->flags;
  313.         t->flags &= ~MALLOC;
  314.         tmp = dupnode(t);
  315.         t->flags = saveflags;
  316.         do_deref();
  317.         t = tmp;
  318.         if (lhs)
  319.             *lhs = tmp;
  320.     }
  321.     lastbuf = t->stptr;
  322.     do {
  323.         if (re_search(rp, t->stptr, t->stlen, search_start,
  324.             t->stlen-search_start, &reregs) == -1
  325.             || reregs.start[0] == reregs.end[0])
  326.             break;
  327.         matches++;
  328.  
  329.         /*
  330.          * first, make a pass through the sub. pattern, to calculate
  331.          * the length of the string after substitution 
  332.          */
  333.         match_length = reregs.end[0] - reregs.start[0];
  334.         len = t->stlen - match_length;
  335.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  336.             if (*scan == '&')
  337.                 len += match_length;
  338.             else if (*scan == '\\' && *(scan+1) == '&') {
  339.                 scan++;
  340.                 len++;
  341.             } else
  342.                 len++;
  343.         emalloc(buf, char *, len + 1, "do_sub");
  344.         bp = buf;
  345.  
  346.         /*
  347.          * now, create the result, copying in parts of the original
  348.          * string 
  349.          */
  350.         for (scan = t->stptr; scan < t->stptr + reregs.start[0]; scan++)
  351.             *bp++ = *scan;
  352.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  353.             if (*scan == '&')
  354.                 for (cp = t->stptr + reregs.start[0]; cp < t->stptr + reregs.end[0]; cp++)
  355.                     *bp++ = *cp;
  356.             else if (*scan == '\\' && *(scan+1) == '&') {
  357.                 scan++;
  358.                 *bp++ = *scan;
  359.             } else
  360.                 *bp++ = *scan;
  361.         search_start = bp - buf;
  362.         for (scan = t->stptr + reregs.end[0]; scan < t->stptr + t->stlen; scan++)
  363.             *bp++ = *scan;
  364.         *bp = '\0';
  365.         free(lastbuf);
  366.         t->stptr = buf;
  367.         lastbuf = buf;
  368.         t->stlen = len;
  369.     } while (global && search_start < t->stlen);
  370.  
  371.     if (matches > 0) {
  372.         if (field_num == 0)
  373.             set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
  374.         else if (field_num > 0) {
  375.             node0_valid = 0;
  376.             if (NF_node->var_value->numbr == -1 &&
  377.                 field_num > NF_node->var_value->numbr)
  378.                 assign_number(&(NF_node->var_value),
  379.                     (AWKNUM) field_num);
  380.         }
  381.         t->flags &= ~NUM;
  382.     }
  383.     field_num = -1;
  384.     return tmp_number((AWKNUM) matches);
  385. }
  386.  
  387. init_args(argc0, argc, argv0, argv)
  388. int argc0, argc;
  389. char *argv0;
  390. char **argv;
  391. {
  392.     int i, j;
  393.     NODE **aptr;
  394.     extern NODE **assoc_lookup();
  395.     extern NODE *spc_var();
  396.     extern NODE *make_string();
  397.     extern NODE *make_number();
  398.     extern NODE *tmp_number();
  399.  
  400.     ARGV_node = spc_var("ARGV", Nnull_string);
  401.     aptr = assoc_lookup(ARGV_node, tmp_number(0.0));
  402.     *aptr = make_string(argv0, strlen(argv0));
  403.     for (i = argc0, j = 1; i < argc; i++) {
  404.         aptr = assoc_lookup(ARGV_node, tmp_number((AWKNUM) j));
  405.         *aptr = make_string(argv[i], strlen(argv[i]));
  406.         j++;
  407.     }
  408.     ARGC_node = spc_var("ARGC", make_number((AWKNUM) j));
  409. }
  410.  
  411. #ifdef USG
  412. int 
  413. bcopy (src, dst, length)
  414. register char *src, *dst;
  415. register int length;
  416. {
  417.     (void) memcpy (dst, src, length);
  418. }
  419.  
  420. int 
  421. bzero (b, length)
  422. register char *b;
  423. register int length;
  424. {
  425.     (void) memset (b, '\0', length);
  426. }
  427. #endif
  428.