home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD2.bin / bbs / gnu / gawk-2.15.5-src.lha / gawk-2.15.5 / field.c < prev    next >
C/C++ Source or Header  |  1994-05-18  |  16KB  |  679 lines

  1. /*
  2.  * field.c - routines for dealing with fields and record parsing
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 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 2 of the License, or
  14.  * (at your option) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. typedef void (* Setfunc) P((int, char*, int, NODE *));
  29.  
  30. static long (*parse_field) P((int, char **, int, NODE *,
  31.                  Regexp *, Setfunc, NODE *));
  32. static void rebuild_record P((void));
  33. static long re_parse_field P((int, char **, int, NODE *,
  34.                  Regexp *, Setfunc, NODE *));
  35. static long def_parse_field P((int, char **, int, NODE *,
  36.                   Regexp *, Setfunc, NODE *));
  37. static long sc_parse_field P((int, char **, int, NODE *,
  38.                  Regexp *, Setfunc, NODE *));
  39. static long fw_parse_field P((int, char **, int, NODE *,
  40.                  Regexp *, Setfunc, NODE *));
  41. static void set_element P((int, char *, int, NODE *));
  42. static void grow_fields_arr P((long num));
  43. static void set_field P((int num, char *str, int len, NODE *dummy));
  44.  
  45.  
  46. static Regexp *FS_regexp = NULL;
  47. static char *parse_extent;    /* marks where to restart parse of record */
  48. static long parse_high_water=0;    /* field number that we have parsed so far */
  49. static long nf_high_water = 0;    /* size of fields_arr */
  50. static int resave_fs;
  51. static NODE *save_FS;        /* save current value of FS when line is read,
  52.                  * to be used in deferred parsing
  53.                  */
  54.  
  55. NODE **fields_arr;        /* array of pointers to the field nodes */
  56. int field0_valid;        /* $(>0) has not been changed yet */
  57. int default_FS;
  58. static NODE **nodes;        /* permanent repository of field nodes */
  59. static int *FIELDWIDTHS = NULL;
  60.  
  61. void
  62. init_fields()
  63. {
  64.     NODE *n;
  65.  
  66.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  67.     emalloc(nodes, NODE **, sizeof(NODE *), "init_fields");
  68.     getnode(n);
  69.     *n = *Nnull_string;
  70.     fields_arr[0] = nodes[0] = n;
  71.     parse_extent = fields_arr[0]->stptr;
  72.     save_FS = dupnode(FS_node->var_value);
  73.     field0_valid = 1;
  74. }
  75.  
  76.  
  77. static void
  78. grow_fields_arr(num)
  79. long num;
  80. {
  81.     register int t;
  82.     register NODE *n;
  83.  
  84.     erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
  85.     erealloc(nodes, NODE **, (num+1) * sizeof(NODE *), "set_field");
  86.     for (t = nf_high_water+1; t <= num; t++) {
  87.         getnode(n);
  88.         *n = *Nnull_string;
  89.         fields_arr[t] = nodes[t] = n;
  90.     }
  91.     nf_high_water = num;
  92. }
  93.  
  94. /*ARGSUSED*/
  95. static void
  96. set_field(num, str, len, dummy)
  97. int num;
  98. char *str;
  99. int len;
  100. NODE *dummy;    /* not used -- just to make interface same as set_element */
  101. {
  102.     register NODE *n;
  103.  
  104.     if (num > nf_high_water)
  105.         grow_fields_arr(num);
  106.     n = nodes[num];
  107.     n->stptr = str;
  108.     n->stlen = len;
  109.     n->flags = (PERM|STR|STRING|MAYBE_NUM);
  110.     fields_arr[num] = n;
  111. }
  112.  
  113. /* Someone assigned a value to $(something).  Fix up $0 to be right */
  114. static void
  115. rebuild_record()
  116. {
  117.     register size_t tlen;
  118.     register NODE *tmp;
  119.     NODE *ofs;
  120.     char *ops;
  121.     register char *cops;
  122.     register NODE **ptr;
  123.     register size_t ofslen;
  124.  
  125.     tlen = 0;
  126.     ofs = force_string(OFS_node->var_value);
  127.     ofslen = ofs->stlen;
  128.     ptr = &fields_arr[NF];
  129.     while (ptr > &fields_arr[0]) {
  130.         tmp = force_string(*ptr);
  131.         tlen += tmp->stlen;
  132.         ptr--;
  133.     }
  134.     tlen += (NF - 1) * ofslen;
  135.     if ((long)tlen < 0)
  136.         tlen = 0;
  137.     emalloc(ops, char *, tlen + 2, "rebuild_record");
  138.     cops = ops;
  139.     ops[0] = '\0';
  140.     for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) {
  141.         tmp = *ptr;
  142.         if (tmp->stlen == 1)
  143.             *cops++ = tmp->stptr[0];
  144.         else if (tmp->stlen != 0) {
  145.             memcpy(cops, tmp->stptr, tmp->stlen);
  146.             cops += tmp->stlen;
  147.         }
  148.         if (ptr != &fields_arr[NF]) {
  149.             if (ofslen == 1)
  150.                 *cops++ = ofs->stptr[0];
  151.             else if (ofslen != 0) {
  152.                 memcpy(cops, ofs->stptr, ofslen);
  153.                 cops += ofslen;
  154.             }
  155.         }
  156.     }
  157.     tmp = make_str_node(ops, tlen, ALREADY_MALLOCED);
  158.     unref(fields_arr[0]);
  159.     fields_arr[0] = tmp;
  160.     field0_valid = 1;
  161. }
  162.  
  163. /*
  164.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  165.  * or to NF.  At that point, parse only as much as necessary.
  166.  */
  167. void
  168. set_record(buf, cnt, freeold)
  169. char *buf;
  170. int cnt;
  171. int freeold;
  172. {
  173.     register int i;
  174.  
  175.     NF = -1;
  176.     for (i = 1; i <= parse_high_water; i++) {
  177.         unref(fields_arr[i]);
  178.     }
  179.     parse_high_water = 0;
  180.     if (freeold) {
  181.         unref(fields_arr[0]);
  182.         if (resave_fs) {
  183.             resave_fs = 0;
  184.             unref(save_FS);
  185.             save_FS = dupnode(FS_node->var_value);
  186.         }
  187.         nodes[0]->stptr = buf;
  188.         nodes[0]->stlen = cnt;
  189.         nodes[0]->stref = 1;
  190.         nodes[0]->flags = (STRING|STR|PERM|MAYBE_NUM);
  191.         fields_arr[0] = nodes[0];
  192.     }
  193.     fields_arr[0]->flags |= MAYBE_NUM;
  194.     field0_valid = 1;
  195. }
  196.  
  197. void
  198. reset_record()
  199. {
  200.     (void) force_string(fields_arr[0]);
  201.     set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, 0);
  202. }
  203.  
  204. void
  205. set_NF()
  206. {
  207.     register int i;
  208.  
  209.     NF = (long) force_number(NF_node->var_value);
  210.     if (NF > nf_high_water)
  211.         grow_fields_arr(NF);
  212.     for (i = parse_high_water + 1; i <= NF; i++) {
  213.         unref(fields_arr[i]);
  214.         fields_arr[i] = Nnull_string;
  215.     }
  216.     field0_valid = 0;
  217. }
  218.  
  219. /*
  220.  * this is called both from get_field() and from do_split()
  221.  * via (*parse_field)().  This variation is for when FS is a regular
  222.  * expression -- either user-defined or because RS=="" and FS==" "
  223.  */
  224. static long
  225. re_parse_field(up_to, buf, len, fs, rp, set, n)
  226. int up_to;    /* parse only up to this field number */
  227. char **buf;    /* on input: string to parse; on output: point to start next */
  228. int len;
  229. NODE *fs;
  230. Regexp *rp;
  231. Setfunc set;    /* routine to set the value of the parsed field */
  232. NODE *n;
  233. {
  234.     register char *scan = *buf;
  235.     register int nf = parse_high_water;
  236.     register char *field;
  237.     register char *end = scan + len;
  238.  
  239.     if (up_to == HUGE)
  240.         nf = 0;
  241.     if (len == 0)
  242.         return nf;
  243.  
  244.     if (*RS == 0 && default_FS)
  245.         while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n'))
  246.             scan++;
  247.     field = scan;
  248.     while (scan < end
  249.            && research(rp, scan, 0, (end - scan), 1) != -1
  250.            && nf < up_to) {
  251.         if (REEND(rp, scan) == RESTART(rp, scan)) {   /* null match */
  252.             scan++;
  253.             if (scan == end) {
  254.                 (*set)(++nf, field, (int)(scan - field), n);
  255.                 up_to = nf;
  256.                 break;
  257.             }
  258.             continue;
  259.         }
  260.         (*set)(++nf, field,
  261.                (int)(scan + RESTART(rp, scan) - field), n);
  262.         scan += REEND(rp, scan);
  263.         field = scan;
  264.         if (scan == end)    /* FS at end of record */
  265.             (*set)(++nf, field, 0, n);
  266.     }
  267.     if (nf != up_to && scan < end) {
  268.         (*set)(++nf, scan, (int)(end - scan), n);
  269.         scan = end;
  270.     }
  271.     *buf = scan;
  272.     return (nf);
  273. }
  274.  
  275. /*
  276.  * this is called both from get_field() and from do_split()
  277.  * via (*parse_field)().  This variation is for when FS is a single space
  278.  * character.
  279.  */
  280. static long
  281. def_parse_field(up_to, buf, len, fs, rp, set, n)
  282. int up_to;    /* parse only up to this field number */
  283. char **buf;    /* on input: string to parse; on output: point to start next */
  284. int len;
  285. NODE *fs;
  286. Regexp *rp;
  287. Setfunc set;    /* routine to set the value of the parsed field */
  288. NODE *n;
  289. {
  290.     register char *scan = *buf;
  291.     register int nf = parse_high_water;
  292.     register char *field;
  293.     register char *end = scan + len;
  294.     char sav;
  295.  
  296.     if (up_to == HUGE)
  297.         nf = 0;
  298.     if (len == 0)
  299.         return nf;
  300.  
  301.     /* before doing anything save the char at *end */
  302.     sav = *end;
  303.     /* because it will be destroyed now: */
  304.  
  305.     *end = ' ';    /* sentinel character */
  306.     for (; nf < up_to; scan++) {
  307.         /*
  308.          * special case:  fs is single space, strip leading whitespace 
  309.          */
  310.         while (scan < end && (*scan == ' ' || *scan == '\t'))
  311.             scan++;
  312.         if (scan >= end)
  313.             break;
  314.         field = scan;
  315.         while (*scan != ' ' && *scan != '\t')
  316.             scan++;
  317.         (*set)(++nf, field, (int)(scan - field), n);
  318.         if (scan == end)
  319.             break;
  320.     }
  321.  
  322.     /* everything done, restore original char at *end */
  323.     *end = sav;
  324.  
  325.     *buf = scan;
  326.     return nf;
  327. }
  328.  
  329. /*
  330.  * this