home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / unix / gawk.sit / source / field.c < prev    next >
Text File  |  1990-07-29  |  11KB  |  425 lines

  1. /*
  2.  * field.c - routines for dealing with fields and record parsing
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. extern void assoc_clear();
  29. extern int a_get_three();
  30. extern int get_rs();
  31.  
  32. static char *get_fs();
  33. static int re_split();
  34. static int parse_fields();
  35. static void set_element();
  36.  
  37. char *line_buf = NULL;    /* holds current input line */
  38.  
  39. static char *parse_extent;    /* marks where to restart parse of record */
  40. static int parse_high_water=0;    /* field number that we have parsed so far */
  41. static char f_empty[] = "";
  42. static char *save_fs = " ";    /* save current value of FS when line is read,
  43.                  * to be used in deferred parsing
  44.                  */
  45.  
  46.  
  47. NODE **fields_arr;        /* array of pointers to the field nodes */
  48. NODE node0;            /* node for $0 which never gets free'd */
  49. int node0_valid = 1;        /* $(>0) has not been changed yet */
  50.  
  51. void
  52. init_fields()
  53. {
  54.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  55.     node0.type = Node_val;
  56.     node0.stref = 0;
  57.     node0.stptr = "";
  58.     node0.flags = (STR|PERM);    /* never free buf */
  59.     fields_arr[0] = &node0;
  60. }
  61.  
  62. /*
  63.  * Danger!  Must only be called for fields we know have just been blanked, or
  64.  * fields we know don't exist yet.  
  65.  */
  66.  
  67. /*ARGSUSED*/
  68. static void
  69. set_field(num, str, len, dummy)
  70. int num;
  71. char *str;
  72. int len;
  73. NODE *dummy;    /* not used -- just to make interface same as set_element */
  74. {
  75.     NODE *n;
  76.     int t;
  77.     static int nf_high_water = 0;
  78.  
  79.     if (num > nf_high_water) {
  80.         erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
  81.         nf_high_water = num;
  82.     }
  83.     /* fill in fields that don't exist */
  84.     for (t = parse_high_water + 1; t < num; t++)
  85.         fields_arr[t] = Nnull_string;
  86.     n = make_string(str, len);
  87.     (void) force_number(n);
  88.     fields_arr[num] = n;
  89.     parse_high_water = num;
  90. }
  91.  
  92. /* Someone assigned a value to $(something).  Fix up $0 to be right */
  93. static void
  94. rebuild_record()
  95. {
  96.     register int tlen;
  97.     register NODE *tmp;
  98.     NODE *ofs;
  99.     char *ops;
  100.     register char *cops;
  101.     register NODE **ptr;
  102.     register int ofslen;
  103.  
  104.     tlen = 0;
  105.     ofs = force_string(OFS_node->var_value);
  106.     ofslen = ofs->stlen;
  107.     ptr = &fields_arr[parse_high_water];
  108.     while (ptr > &fields_arr[0]) {
  109.         tmp = force_string(*ptr);
  110.         tlen += tmp->stlen;
  111.         ptr--;
  112.     }
  113.     tlen += (parse_high_water - 1) * ofslen;
  114.     emalloc(ops, char *, tlen + 1, "fix_fields");
  115.     cops = ops;
  116.     ops[0] = '\0';
  117.     for (ptr = &fields_arr[1]; ptr <= &fields_arr[parse_high_water]; ptr++) {
  118.         tmp = *ptr;
  119.         if (tmp->stlen == 1)
  120.             *cops++ = tmp->stptr[0];
  121.         else if (tmp->stlen != 0) {
  122.             memcpy(cops, tmp->stptr, tmp->stlen);
  123.             cops += tmp->stlen;
  124.         }
  125.         if (ptr != &fields_arr[parse_high_water]) {
  126.             if (ofslen == 1)
  127.                 *cops++ = ofs->stptr[0];
  128.             else if (ofslen != 0) {
  129.                 memcpy(cops, ofs->stptr, ofslen);
  130.                 cops += ofslen;
  131.             }
  132.         }
  133.     }
  134.     tmp = make_string(ops, tlen);
  135.     free(ops);
  136.     deref = fields_arr[0];
  137.     do_deref();
  138.     fields_arr[0] = tmp;
  139. }
  140.  
  141. /*
  142.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  143.  * or to NF.  At that point, parse only as much as necessary.
  144.  */
  145. void
  146. set_record(buf, cnt)
  147. char *buf;
  148. int cnt;
  149. {
  150.     register int i;
  151.  
  152.     assign_number(&NF_node->var_value, (AWKNUM)-1);
  153.     for (i = 1; i <= parse_high_water; i++) {
  154.         deref = fields_arr[i];
  155.         do_deref();
  156.     }
  157.     parse_high_water = 0;
  158.     node0_valid = 1;
  159.     if (buf == line_buf) {
  160.         deref = fields_arr[0];
  161.         do_deref();
  162.         save_fs = get_fs();
  163.         node0.type = Node_val;
  164.         node0.stptr = buf;
  165.         node0.stlen = cnt;
  166.         node0.stref = 1;
  167.         node0.flags = (STR|PERM);    /* never free buf */
  168.         fields_arr[0] = &node0;
  169.     }
  170. }
  171.  
  172. NODE **
  173. get_field(num, assign)
  174. int num;
  175. int assign;    /* this field is on the LHS of an assign */
  176. {
  177.     int n;
  178.  
  179.     /*
  180.      * if requesting whole line but some other field has been altered,
  181.      * then the whole line must be rebuilt
  182.      */
  183.     if (num == 0 && (node0_valid == 0 || assign)) {
  184.         /* first, parse remainder of input record */
  185.         if (NF_node->var_value->numbr == -1) {
  186.             if (parse_high_water == 0)
  187.                 parse_extent = node0.stptr;
  188.             n = parse_fields(HUGE-1, &parse_extent,
  189.                     node0.stlen - (parse_extent - node0.stptr),
  190.                     save_fs, set_field, (NODE *)NULL);
  191.             assign_number(&NF_node->var_value, (AWKNUM)n);
  192.         }
  193.         if (node0_valid == 0)
  194.             rebuild_record();
  195.         return &fields_arr[0];
  196.     }
  197.     if (num > 0 && assign)
  198.         node0_valid = 0;
  199.     if (num <= parse_high_water)    /* we have already parsed this field */
  200.         return &fields_arr[num];
  201.     if (parse_high_water == 0 && num > 0)    /* starting at the beginning */
  202.         parse_extent = fields_arr[0]->stptr;
  203.     /*
  204.      * parse up to num fields, calling set_field() for each, and saving
  205.      * in parse_extent the point where the parse left off
  206.      */
  207.     n = parse_fields(num, &parse_extent,
  208.         fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
  209.         save_fs, set_field, (NODE *)NULL);
  210.     if (num == HUGE-1)
  211.         num = n;
  212.     if (n < num) {    /* requested field number beyond end of record;
  213.              * set_field will just extend the number of fields,
  214.              * with empty fields
  215.              */
  216.         set_field(num, f_empty, 0, (NODE *) NULL);
  217.         /*
  218.          * if this field is onthe LHS of an assignment, then we want to
  219.          * set NF to this value, below
  220.          */
  221.         if (assign)
  222.             n = num;
  223.     }
  224.     /*
  225.      * if we reached the end of the record, set NF to the number of fields
  226.      * so far.  Note that num might actually refer to a field that
  227.      * is beyond the end of the record, but we won't set NF to that value at
  228.      * this point, since this is only a reference to the field and NF
  229.      * only gets set if the field is assigned to -- in this case n has
  230.      * been set to num above
  231.      */
  232.     if (*parse_extent == '\0')
  233.         assign_number(&NF_node->var_value, (AWKNUM)n);
  234.  
  235.     return &fields_arr[num];
  236. }
  237.  
  238. /*
  239.  * this is called both from get_field() and from do_split()
  240.  */
  241. static int
  242. parse_fields(up_to, buf, len, fs, set, n)
  243. int up_to;    /* parse only up to this field number */
  244. char **buf;    /* on input: string to parse; on output: point to start next */
  245. int len;
  246. register char *fs;
  247. void (*set) ();    /* routine to set the value of the parsed field */
  248. NODE *n;
  249. {
  250.     char *s = *buf;
  251.     register char *field;
  252.     register char *scan;
  253.     register char *end = s + len;
  254.     int NF = parse_high_water;
  255.     char rs = get_rs();
  256.  
  257.  
  258.     if (up_to == HUGE)
  259.         NF = 0;
  260.     if (*fs && *(fs + 1) != '\0') {    /* fs is a regexp */
  261.         struct re_registers reregs;
  262.  
  263.         scan = s;
  264.         if (rs == 0 && STREQ(FS_node->var_value->stptr, " ")) {
  265.             while ((*scan == '\n' || *scan == ' ' || *scan == '\t')
  266.                 && scan < end)
  267.                 scan++;
  268.         }
  269.         s = scan;
  270.         while (scan < end
  271.             && re_split(scan, (int)(end - scan), fs, &reregs) != -1
  272.             && NF < up_to) {
  273.             if (reregs.end[0] == 0) {    /* null match */
  274.                 scan++;
  275.                 if (scan == end) {
  276.                     (*set)(++NF, s, scan - s, n);
  277.                     up_to = NF;
  278.                     break;
  279.                 }
  280.                 continue;
  281.             }
  282.             (*set)(++NF, s, scan - s + reregs.start[0], n);
  283.             scan += reregs.end[0];
  284.             s = scan;
  285.         }
  286.         if (NF != up_to && scan <= end) {
  287.             if (!(rs == 0 && scan == end)) {
  288.                 (*set)(++NF, scan, (int)(end - scan), n);
  289.                 scan = end;
  290.             }
  291.         }
  292.         *buf = scan;
  293.         return (NF);
  294.     }
  295.     for (scan = s; scan < end && NF < up_to; scan++) {
  296.         /*
  297.          * special case:  fs is single space, strip leading
  298.          * whitespace 
  299.          */
  300.         if (*fs == ' ') {
  301.             while ((*scan == ' ' || *scan == '\t') && scan < end)
  302.                 scan++;
  303.             if (scan >= end)
  304.                 break;
  305.         }
  306.         field = scan;
  307.         if (*fs == ' ')
  308.             while (*scan != ' ' && *scan != '\t' && scan < end)
  309.                 scan++;
  310.         else {
  311.             while (*scan != *fs && scan < end)
  312.                 scan++;
  313.             if (rs && scan == end-1 && *scan == *fs) {
  314.                 (*set)(++NF, field, (int)(scan - field), n);
  315.                 field = scan;
  316.             }
  317.         }
  318.         (*set)(++NF, field, (int)(scan - field), n);
  319.         if (scan == end)
  320.             break;
  321.     }
  322.     *buf = scan;
  323.     return NF;
  324. }
  325.  
  326. static int
  327. re_split(buf, len, fs, reregsp)
  328. char *buf, *fs;
  329. int len;
  330. struct re_registers *reregsp;
  331. {
  332.     typedef struct re_pattern_buffer RPAT;
  333.     static RPAT *rp;
  334.     static char *last_fs = NULL;
  335.  
  336.     if ((last_fs != NULL && !STREQ(fs, last_fs))
  337.         || (rp && ! strict && ((IGNORECASE_node->var_value->numbr != 0)
  338.              ^ (rp->translate != NULL))))
  339.     {
  340.         /* fs has changed or IGNORECASE has changed */
  341.         free(rp->buffer);
  342.         free(rp->fastmap);
  343.         free((char *) rp);
  344.         free(last_fs);
  345.         last_fs = NULL;
  346.     }
  347.     if (last_fs == NULL) {    /* first time */
  348.         emalloc(rp, RPAT *, sizeof(RPAT), "re_split");
  349.         memset((char *) rp, 0, sizeof(RPAT));
  350.         emalloc(rp->buffer, char *, 8, "re_split");
  351.         rp->allocated = 8;
  352.         emalloc(rp->fastmap, char *, 256, "re_split");
  353.         emalloc(last_fs, char *, strlen(fs) + 1, "re_split");
  354.         (void) strcpy(last_fs, fs);
  355.         if (! strict && IGNORECASE_node->var_value->numbr != 0.0)
  356.             rp->translate = casetable;
  357.         else
  358.             rp->translate = NULL;
  359.         if (re_compile_pattern(fs, strlen(fs), rp) != NULL)
  360.             fatal("illegal regular expression for FS: `%s'", fs);
  361.     }
  362.     return re_search(rp, buf, len, 0, len, reregsp);
  363. }
  364.  
  365. NODE *
  366. do_split(tree)
  367. NODE *tree;
  368. {
  369.     NODE *t1, *t2, *t3;
  370.     register char *splitc;
  371.     char *s;
  372.     NODE *n;
  373.  
  374.     if (a_get_three(tree, &t1, &t2, &t3) < 3)
  375.         splitc = get_fs();
  376.     else
  377.         splitc = force_string(t3)->stptr;
  378.  
  379.     n = t2;
  380.     if (t2->type == Node_param_list)
  381.         n = stack_ptr[t2->param_cnt];
  382.     if (n->type != Node_var && n->type != Node_var_array)
  383.         fatal("second argument of split is not a variable");
  384.     assoc_clear(n);
  385.  
  386.     tree = force_string(t1);
  387.  
  388.     s = tree->stptr;
  389.     return tmp_number((AWKNUM)
  390.         parse_fields(HUGE, &s, tree->stlen, splitc, set_element, n));
  391. }
  392.  
  393. static char *
  394. get_fs()
  395. {
  396.     register NODE *tmp;
  397.     static char buf[10];
  398.  
  399.     tmp = force_string(FS_node->var_value);
  400.     if (get_rs() == 0) {
  401.         if (tmp->stlen == 1) {
  402.             if (tmp->stptr[0] == ' ')
  403.                 (void) strcpy(buf, "[     \n]+");
  404.             else
  405.                 sprintf(buf, "[%c\n]", tmp->stptr[0]);
  406.         } else if (tmp->stlen == 0) {
  407.             buf[0] = '\n';
  408.             buf[1] = '\0';
  409.         } else
  410.             return tmp->stptr;
  411.         return buf;
  412.     }
  413.     return tmp->stptr;
  414. }
  415.  
  416. static void
  417. set_element(num, s, len, n)
  418. int num;
  419. char *s;
  420. int len;
  421. NODE *n;
  422. {
  423.     *assoc_lookup(n, tmp_number((AWKNUM) (num))) = make_string(s, len);
  424. }
  425.