home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 419b.lha / GNU_Awk_v2.10_Beta / awk4.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  11KB  |  405 lines

  1. /*
  2.  * awk4 -- Code for features in new AWK, System V compatibility.
  3.  *
  4.  * $Log:    awk4.c,v $
  5.  * Revision 1.38  89/03/31  13:26:09  david
  6.  * GNU license
  7.  * 
  8.  * Revision 1.37  89/03/29  14:19:07  david
  9.  * delinting and code movement
  10.  * 
  11.  * Revision 1.36  89/03/22  22:10:23  david
  12.  * a cleaner way to handle assignment to $n where n > 0
  13.  * 
  14.  * Revision 1.35  89/03/22  21:05:24  david
  15.  * delete some obsolete code
  16.  * 
  17.  * Revision 1.34  89/03/22  21:00:34  david
  18.  * replace some free()'s with freenode()
  19.  * 
  20.  * Revision 1.33  89/03/21  19:26:01  david
  21.  * minor cleanup
  22.  * 
  23.  * Revision 1.32  89/03/21  18:22:54  david
  24.  * some function tracing debugging code
  25.  * 
  26.  * Revision 1.31  89/03/21  10:53:21  david
  27.  * cleanup
  28.  * 
  29.  * Revision 1.30  89/03/15  22:22:03  david
  30.  * fix from hack: check for null function before using it in diagnostic
  31.  * 
  32.  * Revision 1.29  89/03/15  22:02:24  david
  33.  * new case stuff added
  34.  * 
  35.  * Revision 1.28  89/03/15  21:34:37  david
  36.  * free more memory and purge obstack stuff
  37.  * 
  38.  * Revision 1.27  88/12/14  10:53:49  david
  39.  * malloc structures in func_call and free them on return
  40.  * 
  41.  * Revision 1.26  88/12/13  22:29:15  david
  42.  * minor change
  43.  * 
  44.  * Revision 1.25  88/12/08  10:52:01  david
  45.  * small correction to #ifdef'ing
  46.  * 
  47.  * Revision 1.24  88/11/30  15:18:21  david
  48.  * fooling around with memory allocation in func_call() but this new code remains
  49.  * #ifdef'd out
  50.  * correction to creasting private copy of string in do_sub()
  51.  * 
  52.  * Revision 1.23  88/11/29  09:55:48  david
  53.  * corrections to code that tracks value of NF -- this needs cleanup
  54.  * 
  55.  * Revision 1.22  88/11/28  20:30:10  david
  56.  * bug fix for do_sub when third arg. not specified
  57.  * 
  58.  * Revision 1.21  88/11/22  13:51:10  david
  59.  * Arnold: delinting
  60.  * 
  61.  * Revision 1.20  88/11/15  10:25:14  david
  62.  * Arnold: minor cleanup
  63.  * 
  64.  * Revision 1.19  88/11/14  22:00:09  david
  65.  * Arnold: error message on bad regexp; correction to handling of RSTART in
  66.  * match() on failure; return arg handling to previous behaviour: var=val
  67.  * arg is processed whne it is encountered.
  68.  * 
  69.  * Revision 1.18  88/11/14  21:28:09  david
  70.  * moved concat_exp(); update NF on assign to field > NF; temporarily aborted
  71.  * mods. in func_call(); flag misnamed as TMP becomes PERM (don't free)
  72.  * 
  73.  * Revision 1.17  88/11/01  12:19:37  david
  74.  * cleanup and substantial changes to do_sub()
  75.  * 
  76.  * Revision 1.16  88/10/19  21:59:20  david
  77.  * replace malloc and realloc with error checking versions
  78.  * 
  79.  * Revision 1.15  88/10/17  20:54:54  david
  80.  * SYSV --> USG
  81.  * 
  82.  * Revision 1.14  88/10/13  22:00:44  david
  83.  * purge FAST and cleanup error messages
  84.  * 
  85.  * Revision 1.13  88/10/11  09:29:12  david
  86.  * retrieve parameters from the stack in func_call
  87.  * 
  88.  * Revision 1.12  88/10/06  21:53:15  david
  89.  * added FSF copyleft; Arnold's changes to command line processing
  90.  * 
  91.  *
  92.  */
  93.  
  94. /* 
  95.  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
  96.  * 
  97.  * This file is part of GAWK, the GNU implementation of the
  98.  * AWK Progamming Language.
  99.  * 
  100.  * GAWK is free software; you can redistribute it and/or modify
  101.  * it under the terms of the GNU General Public License as published by
  102.  * the Free Software Foundation; either version 1, or (at your option)
  103.  * any later version.
  104.  * 
  105.  * GAWK is distributed in the hope that it will be useful,
  106.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  107.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  108.  * GNU General Public License for more details.
  109.  * 
  110.  * You should have received a copy of the GNU General Public License
  111.  * along with GAWK; see the file COPYING.  If not, write to
  112.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  113.  */
  114.  
  115. #include "awk.h"
  116.  
  117. extern NODE **fields_arr;
  118.  
  119. jmp_buf func_tag;
  120. NODE **stack_ptr;
  121.  
  122. NODE *
  123. func_call(name, arg_list)
  124. NODE *name;        /* name is a Node_val giving function name */
  125. NODE *arg_list;        /* Node_expression_list of calling args. */
  126. {
  127.     register NODE *arg, *argp, *r;
  128.     NODE *n, *f;
  129.     jmp_buf func_tag_stack;
  130.     NODE *ret_node_stack;
  131.     NODE **local_stack;
  132.     NODE **sp;
  133.     static int func_tag_valid = 0;
  134.     int count;
  135.     extern NODE *ret_node;
  136.  
  137.     /*
  138.      * retrieve function definition node
  139.      */
  140.     f = lookup(variables, name->stptr);
  141.     if (!f || f->type != Node_func)
  142.         fatal("function `%s' not defined", name->stptr);
  143. #ifdef FUNC_TRACE
  144.     fprintf(stderr, "function %s called\n", name->stptr);
  145. #endif
  146.     /*
  147.      * mark stack for variables allocated during life of function
  148.      */
  149.     count = f->lnode->param_cnt;
  150.     emalloc(local_stack, NODE **, count * sizeof(NODE *), "func_call");
  151.     sp = local_stack;
  152.  
  153.     /*
  154.      * for each calling arg. add NODE * on stack
  155.      */
  156.     for (argp = arg_list; count && argp != NULL; argp = argp->rnode) {
  157.         arg = argp->lnode;
  158.         r = newnode(Node_var);
  159.         /*
  160.          * call by reference for arrays; see below also
  161.          */
  162.         if (arg->type == Node_param_list)
  163.             arg = stack_ptr[arg->param_cnt];
  164.         if (arg->type == Node_var_array)
  165.             *r = *arg;
  166.         else {
  167.             n = dupnode(tree_eval(arg));
  168.             r->lnode = n;
  169.             r->rnode = (NODE *) NULL;
  170.           }
  171.         *sp++ = r;
  172.         count--;
  173.     }
  174.     if (argp != NULL)    /* left over calling args. */
  175.         warning(
  176.             "function `%s' called with more arguments than declared",
  177.             name->stptr);
  178.     /*
  179.      * add remaining params. on stack with null value
  180.      */
  181.     while (count-- > 0) {
  182.         r = newnode(Node_var);
  183.         r->lnode = Nnull_string;
  184.         r->rnode = (NODE *) NULL;
  185.         *sp++ = r;
  186.     }
  187.  
  188.     /*
  189.      * execute function body, saving context, as a return statement
  190.      * will longjmp back here
  191.      */
  192.     sp = local_stack;
  193.     local_stack = stack_ptr;
  194.     stack_ptr = sp;
  195.     PUSH_BINDING(func_tag_stack, func_tag, func_tag_valid);
  196.     ret_node_stack = ret_node;
  197.     if (_setjmp(func_tag) == 0)
  198.         (void) interpret(f->rnode);
  199.     r = ret_node;
  200.     ret_node = ret_node_stack;
  201.     RESTORE_BINDING(func_tag_stack, func_tag, func_tag_valid);
  202.     sp = stack_ptr;
  203.     stack_ptr = local_stack;
  204.     local_stack = sp;
  205.  
  206.     /*
  207.      * here, we pop each parameter and check whether
  208.      * it was an array.  If so, and if the arg. passed in was
  209.      * a simple variable, then the value should be copied back.
  210.      * This achieves "call-by-reference" for arrays.
  211.      */
  212.     count = f->lnode->param_cnt;
  213.     for (argp = arg_list; count-- > 0 && argp != NULL; argp = argp->rnode) {
  214.         arg = argp->lnode;
  215.         n = *sp++;
  216.         if (arg->type == Node_var && n->type == Node_var_array) {
  217.             arg->var_array = n->var_array;
  218.             arg->type = Node_var_array;
  219.         }
  220.         deref = n->lnode;
  221.         do_deref();
  222.         freenode(n);
  223.     }
  224.     while (count-- > 0) {
  225.         n = *sp++;
  226.         deref = n->lnode;
  227.         do_deref();
  228.         freenode(n);
  229.     }
  230.     free((char *) local_stack);
  231.     return r;
  232. }
  233.  
  234. NODE *
  235. do_match(tree)
  236. NODE *tree;
  237. {
  238.     NODE *t1;
  239.     int rstart;
  240.     struct re_registers reregs;
  241.     struct re_pattern_buffer *rp;
  242.  
  243.     t1 = force_string(tree_eval(tree->lnode));
  244.     if (tree->rnode->type == Node_regex) {
  245.         rp = tree->rnode->rereg;
  246.         if (!strict && ((IGNORECASE_node->var_value->numbr != 0)
  247.             ^ (tree->rnode->re_case != 0))) {
  248.             /* recompile since case sensitivity differs */
  249.             rp = tree->rnode->rereg =
  250.                 mk_re_parse(tree->rnode->re_text,
  251.                 (IGNORECASE_node->var_value->numbr != 0));
  252.             tree->rnode->re_case = (IGNORECASE_node->var_value->numbr != 0);
  253.         }
  254.     } else {
  255.         rp = make_regexp(force_string(tree_eval(tree->rnode)),
  256.                 (IGNORECASE_node->var_value->numbr != 0));
  257.         if (rp == NULL)
  258.             cant_happen();
  259.     }
  260.     rstart = re_search(rp, t1->stptr, t1->stlen, 0, t1->stlen, &reregs);
  261.     free_temp(t1);
  262.     if (rstart >= 0) {
  263.         rstart++;    /* 1-based indexing */
  264.         /* RSTART set to rstart below */
  265.         RLENGTH_node->var_value->numbr =
  266.             (AWKNUM) (reregs.end[0] - reregs.start[0]);
  267.     } else {
  268.         /*
  269.          * Match failed. Set RSTART to 0, RLENGTH to -1.
  270.          * Return the value of RSTART.
  271.          */
  272.         rstart = 0;    /* used as return value */
  273.         RLENGTH_node->var_value->numbr = -1.0;
  274.     }
  275.     RSTART_node->var_value->numbr = (AWKNUM) rstart;
  276.     return tmp_number((AWKNUM) rstart);
  277. }
  278.  
  279. NODE *
  280. do_sub(tree)
  281. NODE *tree;
  282. {
  283.     register int len;
  284.     register char *scan;
  285.     register char *bp, *cp;
  286.     int search_start = 0;
  287.     int match_length;
  288.     int matches = 0;
  289.     char *buf;
  290.     int global;
  291.     struct re_pattern_buffer *rp;
  292.     NODE *s;        /* subst. pattern */
  293.     NODE *t;        /* string to make sub. in; $0 if none given */
  294.     struct re_registers reregs;
  295.     unsigned int saveflags;
  296.     NODE *tmp;
  297.     NODE **lhs;
  298.     char *lastbuf;
  299.  
  300.     global = (tree->type == Node_gsub);
  301.  
  302.     if (tree->rnode->type == Node_regex) {
  303.         rp = tree->rnode->rereg;
  304.         if (! strict && ((IGNORECASE_node->var_value->numbr != 0)
  305.             ^ (tree->rnode->re_case != 0))) {
  306.             /* recompile since case sensitivity differs */
  307.             rp = tree->rnode->rereg =
  308.                 mk_re_parse(tree->rnode->re_text,
  309.                 (IGNORECASE_node->var_value->numbr != 0));
  310.             tree->rnode->re_case = (IGNORECASE_node->var_value->numbr != 0);
  311.         }
  312.     } else {
  313.         rp = make_regexp(force_string(tree_eval(tree->rnode)),
  314.                 (IGNORECASE_node->var_value->numbr != 0));
  315.         if (rp == NULL)
  316.             cant_happen();
  317.     }
  318.     tree = tree->lnode;
  319.     s = force_string(tree_eval(tree->lnode));
  320.     tree = tree->rnode;
  321.     deref = 0;
  322.     field_num = -1;
  323.     if (tree == NULL) {
  324.         t = node0_valid ? fields_arr[0] : *get_field(0, 0);
  325.         lhs = &fields_arr[0];
  326.         field_num = 0;
  327.         deref = t;
  328.     } else {
  329.         t = tree->lnode;
  330.         lhs = get_lhs(t, 1);
  331.         t = force_string(tree_eval(t));
  332.     }
  333.     /*
  334.      * create a private copy of the string
  335.      */
  336.     if (t->stref > 1 || (t->flags & PERM)) {
  337.         saveflags = t->flags;
  338.         t->flags &= ~MALLOC;
  339.         tmp = dupnode(t);
  340.         t->flags = saveflags;
  341.         do_deref();
  342.         t = tmp;
  343.         if (lhs)
  344.             *lhs = tmp;
  345.     }
  346.     lastbuf = t->stptr;
  347.     do {
  348.         if (re_search(rp, t->stptr, t->stlen, search_start,
  349.             t->stlen-search_start, &reregs) == -1
  350.             || reregs.start[0] == reregs.end[0])
  351.             break;
  352.         matches++;
  353.  
  354.         /*
  355.          * first, make a pass through the sub. pattern, to calculate
  356.          * the length of the string after substitution 
  357.          */
  358.         match_length = reregs.end[0] - reregs.start[0];
  359.         len = t->stlen - match_length;
  360.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  361.             if (*scan == '&')
  362.                 len += match_length;
  363.             else if (*scan == '\\' && *(scan+1) == '&') {
  364.                 scan++;
  365.                 len++;
  366.             } else
  367.                 len++;
  368.         emalloc(buf, char *, len + 1, "do_sub");
  369.         bp = buf;
  370.  
  371.         /*
  372.          * now, create the result, copying in parts of the original
  373.          * string 
  374.          */
  375.         for (scan = t->stptr; scan < t->stptr + reregs.start[0]; scan++)
  376.             *bp++ = *scan;
  377.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  378.             if (*scan == '&')
  379.                 for (cp = t->stptr + reregs.start[0]; cp < t->stptr + reregs.end[0]; cp++)
  380.                     *bp++ = *cp;
  381.             else if (*scan == '\\' && *(scan+1) == '&') {
  382.                 scan++;
  383.                 *bp++ = *scan;
  384.             } else
  385.                 *bp++ = *scan;
  386.         search_start = bp - buf;
  387.         for (scan = t->stptr + reregs.end[0]; scan < t->stptr + t->stlen; scan++)
  388.             *bp++ = *scan;
  389.         *bp = '\0';
  390.         free(lastbuf);
  391.         t->stptr = buf;
  392.         lastbuf = buf;
  393.         t->stlen = len;
  394.     } while (global && search_start < t->stlen);
  395.  
  396.     free_temp(s);
  397.     if (matches > 0) {
  398.         if (field_num == 0)
  399.             set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
  400.         t->flags &= ~NUM;
  401.     }
  402.     field_num = -1;
  403.     return tmp_number((AWKNUM) matches);
  404. }
  405.