home *** CD-ROM | disk | FTP | other *** search
/ ftp.uni-stuttgart.de/pub/systems/acorn/ / Acorn.tar / Acorn / acornet / dev / gawk.spk / gawk-2154 / c / field < prev    next >
Text File  |  1993-12-29  |  16KB  |  648 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 int (*parse_field) P((int, char **, int, NODE *,
  31.                  Regexp *, Setfunc, NODE *));
  32. static void rebuild_record P((void));
  33. static int re_parse_field P((int, char **, int, NODE *,
  34.                  Regexp *, Setfunc, NODE *));
  35. static int def_parse_field P((int, char **, int, NODE *,
  36.                   Regexp *, Setfunc, NODE *));
  37. static int sc_parse_field P((int, char **, int, NODE *,
  38.                  Regexp *, Setfunc, NODE *));
  39. static int 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((int 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 int parse_high_water=0;    /* field number that we have parsed so far */
  49. static int 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. int 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, "fix_fields");
  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 = (int) 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 int
  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 && isspace(*scan))
  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 int
  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 is called both from get_field() and from do_split()
  331.  * via (*parse_field)().  This variation is for when FS is a single character
  332.  * other than space.
  333.  */
  334. static int
  335. sc_parse_field(up_to, buf, len, fs, rp, set, n)
  336. int up_to;    /* parse only up to this field number */
  337. char **buf;    /* on input: string to parse; on output: point to start next */
  338. int len;
  339. NODE *fs;
  340. Regexp *rp;
  341. Setfunc set;    /* routine to set the value of the parsed field */
  342. NODE *n;
  343. {
  344.     register char *scan = *buf;
  345.     register char fschar;
  346.     register int nf = parse_high_water;
  347.     register char *field;
  348.     register char *end = scan + len;
  349.     char sav;
  350.  
  351.     if (up_to == HUGE)
  352.         nf = 0;
  353.     if (len == 0)
  354.         return nf;
  355.  
  356.     if (*RS == 0 && fs->stlen == 0)
  357.         fschar = '\n';
  358.     else
  359.         fschar = fs->stptr[0];
  360.  
  361.     /* before doing anything save the char at *end */
  362.     sav = *end;
  363.     /* because it will be destroyed now: */
  364.     *end = fschar;    /* sentinel character */
  365.  
  366.     for (; nf < up_to; scan++) {
  367.         field = scan;
  368.         while (*scan++ != fschar)
  369.             ;
  370.         scan--;
  371.         (*set)(++nf, field, (int)(scan - field), n);
  372.         if (scan == end)
  373.             break;
  374.     }
  375.  
  376.     /* everything done, restore original char at *end */
  377.     *end = sav;
  378.  
  379.     *buf = scan;
  380.     return nf;
  381. }
  382.  
  383. /*
  384.  * this is called both from get_field() and from do_split()
  385.  * via (*parse_field)().  This variation is for fields are fixed widths.
  386.  */
  387. static int
  388. fw_parse_field(up_to, buf, len, fs, rp, set, n)
  389. int up_to;    /* parse only up to this field number */
  390. char **buf;    /* on input: string to parse; on output: point to start next */
  391. int len;
  392. NODE *fs;
  393. Regexp *rp;
  394. Setfunc set;    /* routine to set the value of the parsed field */
  395. NODE *n;
  396. {
  397.     register char *scan = *buf;
  398.     register int nf = parse_high_water;
  399.     register char *end = scan + len;
  400.  
  401.     if (up_to == HUGE)
  402.         nf = 0;
  403.     if (len == 0)
  404.         return nf;
  405.     for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) {
  406.         if (len > end - scan)
  407.             len = end - scan;
  408.         (*set)(++nf, scan, len, n);
  409.         scan += len;
  410.     }
  411.     if (len == -1)
  412.         *buf = end;
  413.     else
  414.         *buf = scan;
  415.     return nf;
  416. }
  417.  
  418. NODE **
  419. get_field(requested, assign)
  420. register int requested;
  421. Func_ptr *assign;    /* this field is on the LHS of an assign */
  422. {
  423.     /*
  424.      * if requesting whole line but some other field has been altered,
  425.      * then the whole line must be rebuilt
  426.      */
  427.     if (requested == 0) {
  428.         if (!field0_valid) {
  429.             /* first, parse remainder of input record */
  430.             if (NF == -1) {
  431.                 NF = (*parse_field)(HUGE-1, &parse_extent,
  432.                         fields_arr[0]->stlen -
  433.                     (parse_extent - fields_arr[0]->stptr),
  434.                         save_FS, FS_regexp, set_field,
  435.                     (NODE *)NULL);
  436.                 parse_high_water = NF;
  437.             }
  438.             rebuild_record();
  439.         }
  440.         if (assign)
  441.             *assign = reset_record;
  442.         return &fields_arr[0];
  443.     }
  444.  
  445.     /* assert(requested > 0); */
  446.  
  447.     if (assign)
  448.         field0_valid = 0;        /* $0 needs reconstruction */
  449.  
  450.     if (requested <= parse_high_water)    /* already parsed this field */
  451.         return &fields_arr[requested];
  452.  
  453.     if (NF == -1) {    /* have not yet parsed to end of record */
  454.         /*
  455.          * parse up to requested fields, calling set_field() for each,
  456.          * saving in parse_extent the point where the parse left off
  457.          */
  458.         if (parse_high_water == 0)    /* starting at the beginning */
  459.             parse_extent = fields_arr[0]->stptr;
  460.         parse_high_water = (*parse_field)(requested, &parse_extent,
  461.              fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
  462.              save_FS, FS_regexp, set_field, (NODE *)NULL);
  463.  
  464.         /*
  465.          * if we reached the end of the record, set NF to the number of 
  466.          * fields so far.  Note that requested might actually refer to
  467.          * a field that is beyond the end of the record, but we won't
  468.          * set NF to that value at this point, since this is only a
  469.          * reference to the field and NF only gets set if the field
  470.          * is assigned to -- this case is handled below
  471.          */
  472.         if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen)
  473.             NF = parse_high_water;
  474.         if (requested == HUGE-1)    /* HUGE-1 means set NF */
  475.             requested = parse_high_water;
  476.     }
  477.     if (parse_high_water < requested) { /* requested beyond end of record */
  478.         if (assign) {    /* expand record */
  479.             register int i;
  480.  
  481.             if (requested > nf_high_water)
  482.                 grow_fields_arr(requested);
  483.  
  484.             /* fill in fields that don't exist */
  485.             for (i = parse_high_water + 1; i <= requested; i++)
  486.                 fields_arr[i] = Nnull_string;
  487.  
  488.             NF = requested;
  489.             parse_high_water = requested;
  490.         } else
  491.             return &Nnull_string;
  492.     }
  493.  
  494.     return &fields_arr[requested];
  495. }
  496.  
  497. static void
  498. set_element(num, s, len, n)
  499. int num;
  500. char *s;
  501. int len;
  502. NODE *n;
  503. {
  504.     register NODE *it;
  505.  
  506.     it = make_string(s, len);
  507.     it->flags |= MAYBE_NUM;
  508.     *assoc_lookup(n, tmp_number((AWKNUM) (num))) = it;
  509. }
  510.  
  511. NODE *
  512. do_split(tree)
  513. NODE *tree;
  514. {
  515.     NODE *t1, *t2, *t3, *tmp;
  516.     NODE *fs;
  517.     char *s;
  518.     int (*parseit)P((int, char **, int, NODE *,
  519.              Regexp *, Setfunc, NODE *));
  520.     Regexp *rp = NULL;
  521.  
  522.     t1 = tree_eval(tree->lnode);
  523.     t2 = tree->rnode->lnode;
  524.     t3 = tree->rnode->rnode->lnode;
  525.  
  526.     (void) force_string(t1);
  527.  
  528.     if (t2->type == Node_param_list)
  529.         t2 = stack_ptr[t2->param_cnt];
  530.     if (t2->type != Node_var && t2->type != Node_var_array)
  531.         fatal("second argument of split is not a variable");
  532.     assoc_clear(t2);
  533.  
  534.     if (t3->re_flags & FS_DFLT) {
  535.         parseit = parse_field;
  536.         fs = force_string(FS_node->var_value);
  537.         rp = FS_regexp;
  538.     } else {
  539.         tmp = force_string(tree_eval(t3->re_exp));
  540.         if (tmp->stlen == 1) {
  541.             if (tmp->stptr[0] == ' ')
  542.                 parseit = def_parse_field;
  543.             else
  544.                 parseit = sc_parse_field;
  545.         } else {
  546.             parseit = re_parse_field;
  547.             rp = re_update(t3);
  548.         }
  549.         fs = tmp;
  550.     }
  551.  
  552.     s = t1->stptr;
  553.     tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int)t1->stlen,
  554.                          fs, rp, set_element, t2));
  555.     free_temp(t1);
  556.     free_temp(t3);
  557.     return tmp;
  558. }
  559.  
  560. void
  561. set_FS()
  562. {
  563.     char buf[10];
  564.     NODE *fs;
  565.  
  566.     buf[0] = '\0';
  567.     default_FS = 0;
  568.     if (FS_regexp) {
  569.         refree(FS_regexp);
  570.         FS_regexp = NULL;
  571.     }
  572.     fs = force_string(FS_node->var_value);
  573.     if (fs->stlen > 1)
  574.         parse_field = re_parse_field;
  575.     else if (*RS == 0) {
  576.         parse_field = sc_parse_field;
  577.         if (fs->stlen == 1) {
  578.             if (fs->stptr[0] == ' ') {
  579.                 default_FS = 1;
  580.                 strcpy(buf, "[ \t\n]+");
  581.             } else if (fs->stptr[0] != '\n')
  582.                 sprintf(buf, "[%c\n]", fs->stptr[0]);
  583.         }
  584.     } else {
  585.         parse_field = def_parse_field;
  586.         if (fs->stptr[0] == ' ' && fs->stlen == 1)
  587.             default_FS = 1;
  588.         else if (fs->stptr[0] != ' ' && fs->stlen == 1) {
  589.             if (IGNORECASE == 0)
  590.                 parse_field = sc_parse_field;
  591.             else
  592.                 sprintf(buf, "[%c]", fs->stptr[0]);
  593.         }
  594.     }
  595.     if (buf[0]) {
  596.         FS_regexp = make_regexp(buf, strlen(buf), IGNORECASE, 1);
  597.         parse_field = re_parse_field;
  598.     } else if (parse_field == re_parse_field) {
  599.         FS_regexp = make_regexp(fs->stptr, fs->stlen, IGNORECASE, 1);
  600.     } else
  601.         FS_regexp = NULL;
  602.     resave_fs = 1;
  603. }
  604.  
  605. void
  606. set_RS()
  607. {
  608.     (void) force_string(RS_node->var_value);
  609.     RS = RS_node->var_value->stptr;
  610.     set_FS();
  611. }
  612.  
  613. void
  614. set_FIELDWIDTHS()
  615. {
  616.     register char *scan;
  617.     char *end;
  618.     register int i;
  619.     static int fw_alloc = 1;
  620.     static int warned = 0;
  621.     extern double strtod();
  622.  
  623.     if (do_lint && ! warned) {
  624.         warned = 1;
  625.         warning("use of FIELDWIDTHS is a gawk extension");
  626.     }
  627.     if (do_unix)    /* quick and dirty, does the trick */
  628.         return;
  629.  
  630.     parse_field = fw_parse_field;
  631.     scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
  632.     end = scan + 1;
  633.     if (FIELDWIDTHS == NULL)
  634.         emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  635.     FIELDWIDTHS[0] = 0;
  636.     for (i = 1; ; i++) {
  637.         if (i >= fw_alloc) {
  638.             fw_alloc *= 2;
  639.             erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  640.         }
  641.         FIELDWIDTHS[i] = (int) strtod(scan, &end);
  642.         if (end == scan)
  643.             break;
  644.         scan = end;
  645.     }
  646.     FIELDWIDTHS[i] = -1;
  647. }
  648.