home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / gawk213s.lzh / GAWK213S / FIELD.C < prev    next >
C/C++ Source or Header  |  1993-07-29  |  15KB  |  615 lines

  1. /*
  2.  * field.c - routines for dealing with fields and record parsing
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991 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.  
  29. static int (*parse_field) P((int, char **, int, char *,
  30.                  Regexp *, void (*)(), NODE *));
  31. static void rebuild_record P((void));
  32. static int re_parse_field P((int, char **, int, char *,
  33.                  Regexp *, void (*)(), NODE *));
  34. static int def_parse_field P((int, char **, int, char *,
  35.                   Regexp *, void (*)(), NODE *));
  36. static int sc_parse_field P((int, char **, int, char *,
  37.                  Regexp *, void (*)(), NODE *));
  38. static int fw_parse_field P((int, char **, int, char *,
  39.                  Regexp *, void (*)(), NODE *));
  40. static void set_element P((int, char *, int, NODE *));
  41.  
  42. static Regexp *FS_regexp = NULL;
  43. static char *parse_extent;    /* marks where to restart parse of record */
  44. static int parse_high_water=0;    /* field number that we have parsed so far */
  45. static int nf_high_water = 0;    /* size of fields_arr */
  46. static char f_empty[] = "\0";
  47. static int resave_fs;
  48. static NODE *save_FS;
  49. static char *save_fs;        /* save current value of FS when line is read,
  50.                  * to be used in deferred parsing
  51.                  */
  52.  
  53. NODE **fields_arr;        /* array of pointers to the field nodes */
  54. int field0_valid = 1;        /* $(>0) has not been changed yet */
  55. NODE *field0;
  56. static NODE **nodes;        /* permanent repository of field nodes */
  57. static int *FIELDWIDTHS = NULL;
  58.  
  59. void
  60. init_fields()
  61. {
  62.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  63.     emalloc(nodes, NODE **, sizeof(NODE *), "init_fields");
  64.     emalloc(field0, NODE *, sizeof(NODE), "init_fields");
  65.     field0->type = Node_val;
  66.     field0->stref = 0;
  67.     field0->stptr = "";
  68.     field0->flags = (STRING|STR|PERM);    /* never free buf */
  69.     fields_arr[0] = field0;
  70.     save_FS = dupnode(FS_node->var_value);
  71.     save_fs = save_FS->stptr;
  72. }
  73.  
  74. static void
  75. grow_fields_arr(num)
  76. int num;
  77. {
  78.     register int t;
  79.     register NODE *n;
  80.  
  81.     erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
  82.     erealloc(nodes, NODE **, (num+1) * sizeof(NODE *), "set_field");
  83.     for (t = nf_high_water+1; t <= num; t++) {
  84.         getnode(n);
  85.         n->type = Node_val;
  86.         nodes[t] = n;
  87.         fields_arr[t] = nodes[t];
  88.     }
  89.     nf_high_water = num;
  90. }
  91.  
  92. /*ARGSUSED*/
  93. static void
  94. set_field(num, str, len, dummy)
  95. int num;
  96. char *str;
  97. int len;
  98. NODE *dummy;    /* not used -- just to make interface same as set_element */
  99. {
  100.     register NODE *n;
  101.     register int t;
  102.  
  103.     if (num > nf_high_water)
  104.         grow_fields_arr(num);
  105.     n = nodes[num];
  106.     n->stptr = str;
  107.     n->stlen = len;
  108.     n->flags = (PERM|STR|STRING|MAYBE_NUM);
  109.     fields_arr[num] = n;
  110. }
  111.  
  112. /* Someone assigned a value to $(something).  Fix up $0 to be right */
  113. static void
  114. rebuild_record()
  115. {
  116.     register int tlen;
  117.     register NODE *tmp;
  118.     NODE *ofs;
  119.     char *ops;
  120.     register char *cops;
  121.     register NODE **ptr;
  122.     register int ofslen;
  123.  
  124.     tlen = 0;
  125.     ofs = force_string(OFS_node->var_value);
  126.     ofslen = ofs->stlen;
  127.     ptr = &fields_arr[NF];
  128.     while (ptr > &fields_arr[0]) {
  129.         tmp = force_string(*ptr);
  130.         tlen += tmp->stlen;
  131.         ptr--;
  132.     }
  133.     tlen += (NF - 1) * ofslen;
  134.     emalloc(ops, char *, tlen + 2, "fix_fields");
  135.     cops = ops;
  136.     ops[0] = '\0';
  137.     for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) {
  138.         tmp = *ptr;
  139.         if (tmp->stlen == 1)
  140.             *cops++ = tmp->stptr[0];
  141.         else if (tmp->stlen != 0) {
  142.             memcpy(cops, tmp->stptr, tmp->stlen);
  143.             cops += tmp->stlen;
  144.         }
  145.         if (ptr != &fields_arr[NF]) {
  146.             if (ofslen == 1)
  147.                 *cops++ = ofs->stptr[0];
  148.             else if (ofslen != 0) {
  149.                 memcpy(cops, ofs->stptr, ofslen);
  150.                 cops += ofslen;
  151.             }
  152.         }
  153.     }
  154.     tmp = make_str_node(ops, tlen, ALREADY_MALLOCED);
  155.     unref(fields_arr[0]);
  156.     fields_arr[0] = tmp;
  157.     field0_valid = 1;
  158. }
  159.  
  160. /*
  161.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  162.  * or to NF.  At that point, parse only as much as necessary.
  163.  */
  164. void
  165. set_record(buf, cnt, freeold)
  166. char *buf;
  167. int cnt;
  168. int freeold;
  169. {
  170.     register int i;
  171.  
  172.     NF = -1;
  173.     for (i = 1; i <= parse_high_water; i++) {
  174.         unref(fields_arr[i]);
  175.     }
  176.     parse_high_water = 0;
  177.     if (freeold) {
  178.         unref(fields_arr[0]);
  179.         if (resave_fs) {
  180.             resave_fs = 0;
  181.             unref(save_FS);
  182.             save_FS = dupnode(FS_node->var_value);
  183.             save_fs = save_FS->stptr;
  184.         }
  185.         field0->stptr = buf;
  186.         field0->stlen = cnt;
  187.         field0->stref = 1;
  188.         field0->flags = (STRING|STR|PERM|MAYBE_NUM);
  189.         fields_arr[0] = field0;
  190.     }
  191.     fields_arr[0]->flags |= MAYBE_NUM;
  192.     field0_valid = 1;
  193. }
  194.  
  195. void
  196. reset_record()
  197. {
  198.     (void) force_string(fields_arr[0]);
  199.     set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, 0);
  200. }
  201.  
  202. void
  203. set_NF()
  204. {
  205.     NF = (int) force_number(NF_node->var_value);
  206.     field0_valid = 0;
  207. }
  208.  
  209. /*
  210.  * this is called both from get_field() and from do_split()
  211.  * via (*parse_field)().  This variation is for when FS is a regular
  212.  * expression -- either user-defined or because RS=="" and FS==" "
  213.  */
  214. static int
  215. re_parse_field(up_to, buf, len, fs, rp, set, n)
  216. int up_to;    /* parse only up to this field number */
  217. char **buf;    /* on input: string to parse; on output: point to start next */
  218. int len;
  219. register char *fs;
  220. Regexp *rp;
  221. void (*set) ();    /* routine to set the value of the parsed field */
  222. NODE *n;
  223. {
  224.     register char *scan = *buf;
  225.     register int nf = parse_high_water;
  226.     register char *field;
  227.     register char *end = scan + len;
  228.     char *cp;
  229.  
  230.     if (up_to == HUGE)
  231.         nf = 0;
  232.     if (len == 0)
  233.         return nf;
  234.  
  235.     cp = FS_node->var_value->stptr;
  236.     if (*RS == 0 && *cp == ' ' && *(cp+1) == '\0') {
  237.         while (scan < end
  238.                && (*scan == '\n' || *scan == ' ' || *scan == '\t'))
  239.             scan++;
  240.     }
  241.     field = scan;
  242.     while (scan < end
  243.            && research(rp, scan, (int)(end - scan), 1) != -1
  244.            && nf < up_to) {
  245.         if (REEND(rp, scan) == RESTART(rp, scan)) {    /* null match */
  246.             scan++;
  247.             if (scan == end) {
  248.                 (*set)(++nf, field, scan - field, n);
  249.                 up_to = nf;
  250.                 break;
  251.             }
  252.             continue;
  253.         }
  254.         (*set)(++nf, field, RESTART(rp, scan), n);
  255.         scan += REEND(rp, scan);
  256.         field = scan;
  257.     }
  258.     if (nf != up_to && *RS != 0 && scan < end) {
  259.         (*set)(++nf, scan, (int)(end - scan), n);
  260.         scan = end;
  261.     }
  262.     *buf = scan;
  263.     return (nf);
  264. }
  265.  
  266. /*
  267.  * this is called both from get_field() and from do_split()
  268.  * via (*parse_field)().  This variation is for when FS is a single space
  269.  * character.
  270.  */
  271. static int
  272. def_parse_field(up_to, buf, len, fs, rp, set, n)
  273. int up_to;    /* parse only up to this field number */
  274. char **buf;    /* on input: string to parse; on output: point to start next */
  275. int len;
  276. register char *fs;
  277. Regexp *rp;
  278. void (*set) ();    /* routine to set the value of the parsed field */
  279. NODE *n;
  280. {
  281.     register char *scan = *buf;
  282.     register int nf = parse_high_water;
  283.     register char *field;
  284.     register char *end = scan + len;
  285.  
  286.     if (up_to == HUGE)
  287.         nf = 0;
  288.     if (len == 0)
  289.         return nf;
  290.  
  291.     *end = ' ';    /* sentinel character */
  292.     for (; nf < up_to; scan++) {
  293.         /*
  294.          * special case:  fs is single space, strip leading whitespace 
  295.          */
  296.         while (scan < end && (*scan == ' ' || *scan == '\t'))
  297.             scan++;
  298.         if (scan >= end)
  299.             break;
  300.         field = scan;
  301.         while (*scan != ' ' && *scan != '\t')
  302.             scan++;
  303.         (*set)(++nf, field, (int)(scan - field), n);
  304.         if (scan == end)
  305.             break;
  306.     }
  307.     *buf = scan;
  308.     return nf;
  309. }
  310.  
  311. /*
  312.  * this is called both from get_field() and from do_split()
  313.  * via (*pase_field)().  This variation is for when FS is a single character
  314.  * other than space.
  315.  */
  316. static int
  317. sc_parse_field(up_to, buf, len, fs, rp, set, n)
  318. int up_to;    /* parse only up to this field number */
  319. char **buf;    /* on input: string to parse; on output: point to start next */
  320. int len;
  321. register char *fs;
  322. Regexp *rp;
  323. void (*set) ();    /* routine to set the value of the parsed field */
  324. NODE *n;
  325. {
  326.     register char *scan = *buf;
  327.     register char fschar = *fs;
  328.     register int nf = parse_high_water;
  329.     register char *field;
  330.     register char *end = scan + len;
  331.  
  332.     if (up_to == HUGE)
  333.         nf = 0;
  334.     if (len == 0)
  335.         return nf;
  336.     *end = fschar;    /* sentinel character */
  337.     for (; nf < up_to; scan++) {
  338.         field = scan;
  339.         while (*scan++ != fschar)
  340.             ;
  341.         scan--;
  342.         (*set)(++nf, field, (int)(scan - field), n);
  343.         if (scan == end)
  344.             break;
  345.     }
  346.     *buf = scan;
  347.     return nf;
  348. }
  349.  
  350. /*
  351.  * this is called both from get_field() and from do_split()
  352.  * via (*pase_field)().  This variation is for when FS is a single character
  353.  * other than space.
  354.  */
  355. static int
  356. fw_parse_field(up_to, buf, len, fs, rp, set, n)
  357. int up_to;    /* parse only up to this field number */
  358. char **buf;    /* on input: string to parse; on output: point to start next */
  359. int len;
  360. register char *fs;
  361. Regexp *rp;
  362. void (*set) ();    /* routine to set the value of the parsed field */
  363. NODE *n;
  364. {
  365.     register char *scan = *buf;
  366.     register int nf = parse_high_water;
  367.     register char *end = scan + len;
  368.  
  369.     if (up_to == HUGE)
  370.         nf = 0;
  371.     if (len == 0)
  372.         return nf;
  373.     for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) {
  374.         if (len > end - scan)
  375.             len = end - scan;
  376.         (*set)(++nf, scan, len, n);
  377.         scan += len;
  378.     }
  379.     if (len == -1)
  380.         *buf = end;
  381.     else
  382.         *buf = scan;
  383.     return nf;
  384. }
  385.  
  386. NODE **
  387. get_field(num, assign)
  388. register int num;
  389. Func_ptr *assign;    /* this field is on the LHS of an assign */
  390. {
  391.     int n;
  392.  
  393.     /*
  394.      * if requesting whole line but some other field has been altered,
  395.      * then the whole line must be rebuilt
  396.      */
  397.     if (num == 0) {
  398.         if (!field0_valid) {
  399.             /* first, parse remainder of input record */
  400.             if (NF == -1) {
  401.                 NF = (*parse_field)(HUGE-1, &parse_extent,
  402.                         fields_arr[0]->stlen -
  403.                     (parse_extent - fields_arr[0]->stptr),
  404.                         save_fs, FS_regexp, set_field,
  405.                     (NODE *)NULL);
  406.                 parse_high_water = NF;
  407.             }
  408.             rebuild_record();
  409.         }
  410.         if (assign)
  411.             *assign = reset_record;
  412.         return &fields_arr[0];
  413.     }
  414.  
  415.     /* assert(num > 0); */
  416.  
  417.     if (assign)
  418.         field0_valid = 0;
  419.     if (num <= parse_high_water)    /* we have already parsed this field */
  420.         return &fields_arr[num];
  421.     if (parse_high_water == 0)    /* starting at the beginning */
  422.         parse_extent = fields_arr[0]->stptr;
  423.     /*
  424.      * parse up to num fields, calling set_field() for each, and saving
  425.      * in parse_extent the point where the parse left off
  426.      */
  427.     n = (*parse_field)(num, &parse_extent,
  428.         fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
  429.         save_fs, FS_regexp, set_field, (NODE *)NULL);
  430.     parse_high_water = n;
  431.     if (num == HUGE-1)
  432.         num = n;
  433.     if (n < num) {    /* requested field number beyond end of record; */
  434.         register int i;
  435.  
  436.         if (num > nf_high_water)
  437.             grow_fields_arr(num);
  438.  
  439.         /* fill in fields that don't exist */
  440.         for (i = n + 1; i <= num; i++)
  441.             fields_arr[i] = Nnull_string;
  442.  
  443.         /*
  444.          * if this field is onthe LHS of an assignment, then we want to
  445.          * set NF to this value, below
  446.          */
  447.         if (assign)
  448.             n = num;
  449.     }
  450.     /*
  451.      * if we reached the end of the record, set NF to the number of fields
  452.      * so far.  Note that num might actually refer to a field that
  453.      * is beyond the end of the record, but we won't set NF to that value at
  454.      * this point, since this is only a reference to the field and NF
  455.      * only gets set if the field is assigned to -- in this case n has
  456.      * been set to num above
  457.      */
  458.     if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen)
  459.         NF = n;
  460.  
  461.     return &fields_arr[num];
  462. }
  463.  
  464. static void
  465. set_element(num, s, len, n)
  466. int num;
  467. char *s;
  468. int len;
  469. NODE *n;
  470. {
  471.     register NODE *it;
  472.  
  473.     it = make_string(s, len);
  474.     it->flags |= MAYBE_NUM;
  475.     *assoc_lookup(n, tmp_number((AWKNUM) (num))) = it;
  476. }
  477.  
  478. NODE *
  479. do_split(tree)
  480. NODE *tree;
  481. {
  482.     NODE *t1, *t2, *t3, *tmp;
  483.     register char *splitc = "";
  484.     char *s;
  485.     int (*parseit)();
  486.     Regexp *rp = NULL;
  487.  
  488.     t1 = tree_eval(tree->lnode);
  489.     t2 = tree->rnode->lnode;
  490.     t3 = tree->rnode->rnode->lnode;
  491.  
  492.     (void) force_string(t1);
  493.  
  494.     if (t2->type == Node_param_list)
  495.         t2 = stack_ptr[t2->param_cnt];
  496.     if (t2->type != Node_var && t2->type != Node_var_array)
  497.         fatal("second argument of split is not a variable");
  498.     assoc_clear(t2);
  499.  
  500.     if (t3->re_flags & FS_DFLT) {
  501.         parseit = parse_field;
  502.         splitc = FS;
  503.         rp = FS_regexp;
  504.     } else {
  505.         tmp = force_string(tree_eval(t3->re_exp));
  506.         if (tmp->stlen == 1) {
  507.             if (tmp->stptr[0] == ' ') {
  508.                 parseit = def_parse_field;
  509.             } else {
  510.                 parseit = sc_parse_field;
  511.                 splitc = tmp->stptr;
  512.             }
  513.         } else {
  514.             parseit = re_parse_field;
  515.             rp = re_update(t3);
  516.         }
  517.         free_temp(tmp);
  518.     }
  519.  
  520.     s = t1->stptr;
  521.     tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, t1->stlen,
  522.                          splitc, rp, set_element, t2));
  523.     free_temp(t1);
  524.     return tmp;
  525. }
  526.  
  527. void
  528. set_FS()
  529. {
  530.     register NODE *tmp;
  531.     static char buf[10];
  532.  
  533.     if (FS_regexp) {
  534.         refree(FS_regexp);
  535.         FS_regexp = NULL;
  536.     }
  537.     parse_field = def_parse_field;
  538.     tmp = force_string(FS_node->var_value);
  539.     FS = tmp->stptr;
  540.     if (*RS == 0) {
  541.         parse_field = re_parse_field;
  542.         FS = buf;
  543.         if (tmp->stlen == 1) {
  544.             if (tmp->stptr[0] == ' ')
  545.                 (void) strcpy(buf, "[     \n]+");
  546.             else if (tmp->stptr[0] != '\n')
  547.                 sprintf(buf, "[%c\n]", tmp->stptr[0]);
  548.             else {
  549.                 parse_field = sc_parse_field;
  550.                 FS = tmp->stptr;
  551.             }
  552.         } else if (tmp->stlen == 0) {
  553.             buf[0] = '\n';
  554.             buf[1] = '\0';
  555.             parse_field = sc_parse_field;
  556.         } else
  557.             FS = tmp->stptr;
  558.     } else {
  559.         if (tmp->stlen > 1)
  560.             parse_field = re_parse_field;
  561.         else if (*FS != ' ' && tmp->stlen == 1)
  562.             parse_field = sc_parse_field;
  563.     }
  564.     if (parse_field == re_parse_field) {
  565.         tmp = tmp_string(FS, strlen(FS));
  566.         FS_regexp = make_regexp(tmp, 0, 1);
  567.         free_temp(tmp);
  568.     } else
  569.         FS_regexp = NULL;
  570.     resave_fs = 1;
  571. }
  572.  
  573. void
  574. set_RS()
  575. {
  576.     (void) force_string(RS_node->var_value);
  577.     RS = RS_node->var_value->stptr;
  578.     set_FS();
  579. }
  580.  
  581. void
  582. set_FIELDWIDTHS()
  583. {
  584.     register char *scan;
  585.     char *end;
  586.     register int i;
  587.     static int fw_alloc = 1;
  588.     static int warned = 0;
  589.  
  590.     if (do_lint && ! warned) {
  591.         warned = 1;
  592.         warning("use of FIELDWIDTHS is a gawk extension");
  593.     }
  594.     if (strict)    /* quick and dirty, does the trick */
  595.         return;
  596.  
  597.     parse_field = fw_parse_field;
  598.     scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
  599.     end = scan + 1;
  600.     if (FIELDWIDTHS == NULL)
  601.         emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  602.     FIELDWIDTHS[0] = 0;
  603.     for (i = 1; ; i++) {
  604.         if (i >= fw_alloc) {
  605.             fw_alloc *= 2;
  606.             erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  607.         }
  608.         FIELDWIDTHS[i] = (int) strtol(scan, &end, 10);
  609.         if (end == scan)
  610.             break;
  611.         scan = end;
  612.     }
  613.     FIELDWIDTHS[i] = -1;
  614. }
  615.