home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / MPW / gawk 2.11.1r3 / Sources / field.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-01  |  10.4 KB  |  431 lines  |  [TEXT/MPS ]

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