home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnuawk.zip / field.c < prev    next >
C/C++ Source or Header  |  1997-05-01  |  22KB  |  916 lines

  1. /*
  2.  * field.c - routines for dealing with fields and record parsing
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1997 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Programming 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 this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  24.  */
  25.  
  26. #include "awk.h"
  27. #include <assert.h>
  28.  
  29. typedef void (* Setfunc) P((long, char *, long, NODE *));
  30.  
  31. static long (*parse_field) P((long, char **, int, NODE *,
  32.                  Regexp *, Setfunc, NODE *));
  33. static void rebuild_record P((void));
  34. static long re_parse_field P((long, char **, int, NODE *,
  35.                  Regexp *, Setfunc, NODE *));
  36. static long def_parse_field P((long, char **, int, NODE *,
  37.                   Regexp *, Setfunc, NODE *));
  38. static long posix_def_parse_field P((long, char **, int, NODE *,
  39.                   Regexp *, Setfunc, NODE *));
  40. static long null_parse_field P((long, char **, int, NODE *,
  41.                  Regexp *, Setfunc, NODE *));
  42. static long sc_parse_field P((long, char **, int, NODE *,
  43.                  Regexp *, Setfunc, NODE *));
  44. static long fw_parse_field P((long, char **, int, NODE *,
  45.                  Regexp *, Setfunc, NODE *));
  46. static void set_element P((long num, char * str, long len, NODE *arr));
  47. static void grow_fields_arr P((long num));
  48. static void set_field P((long num, char *str, long len, NODE *dummy));
  49.  
  50.  
  51. static char *parse_extent;    /* marks where to restart parse of record */
  52. static long parse_high_water = 0; /* field number that we have parsed so far */
  53. static long nf_high_water = 0;    /* size of fields_arr */
  54. static int resave_fs;
  55. static NODE *save_FS;        /* save current value of FS when line is read,
  56.                  * to be used in deferred parsing
  57.                  */
  58. static int *FIELDWIDTHS = NULL;
  59.  
  60. NODE **fields_arr;        /* array of pointers to the field nodes */
  61. int field0_valid;        /* $(>0) has not been changed yet */
  62. int default_FS;            /* TRUE when FS == " " */
  63. Regexp *FS_regexp = NULL;
  64. static NODE *Null_field = NULL;
  65.  
  66. /* init_fields --- set up the fields array to start with */
  67.  
  68. void
  69. init_fields()
  70. {
  71.     NODE *n;
  72.  
  73.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  74.     getnode(n);
  75.     *n = *Nnull_string;
  76.     n->flags |= (SCALAR|FIELD);
  77.     n->flags &= ~PERM;
  78.     fields_arr[0] = n;
  79.     parse_extent = fields_arr[0]->stptr;
  80.     save_FS = dupnode(FS_node->var_value);
  81.     getnode(Null_field);
  82.     *Null_field = *Nnull_string;
  83.     Null_field->flags |= (SCALAR|FIELD);
  84.     Null_field->flags &= ~(NUM|NUMBER|MAYBE_NUM|PERM);
  85.     field0_valid = TRUE;
  86. }
  87.  
  88. /* grow_fields --- acquire new fields as needed */
  89.  
  90. static void
  91. grow_fields_arr(num)
  92. long num;
  93. {
  94.     register int t;
  95.     register NODE *n;
  96.  
  97.     erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "grow_fields_arr");
  98.     for (t = nf_high_water + 1; t <= num; t++) {
  99.         getnode(n);
  100.         *n = *Null_field;
  101.         fields_arr[t] = n;
  102.     }
  103.     nf_high_water = num;
  104. }
  105.  
  106. /* set_field --- set the value of a particular field */
  107.  
  108. /*ARGSUSED*/
  109. static void
  110. set_field(num, str, len, dummy)
  111. long num;
  112. char *str;
  113. long len;
  114. NODE *dummy;    /* not used -- just to make interface same as set_element */
  115. {
  116.     register NODE *n;
  117.  
  118.     if (num > nf_high_water)
  119.         grow_fields_arr(num);
  120.     n = fields_arr[num];
  121.     n->stptr = str;
  122.     n->stlen = len;
  123.     n->flags = (STR|STRING|MAYBE_NUM|SCALAR|FIELD);
  124. }
  125.  
  126. /* rebuild_record --- Someone assigned a value to $(something).
  127.             Fix up $0 to be right */
  128.  
  129. static void
  130. rebuild_record()
  131. {
  132.     /*
  133.      * use explicit unsigned longs for lengths, in case
  134.      * a size_t isn't big enough.
  135.      */
  136.     register unsigned long tlen;
  137.     register unsigned long ofslen;
  138.     register NODE *tmp;
  139.     NODE *ofs;
  140.     char *ops;
  141.     register char *cops;
  142.     long i;
  143.     char *f0start, *f0end;
  144.  
  145.     assert(NF != -1);
  146.  
  147.     tlen = 0;
  148.     ofs = force_string(OFS_node->var_value);
  149.     ofslen = ofs->stlen;
  150.     for (i = NF; i > 0; i--) {
  151.         tmp = fields_arr[i];
  152.         tmp = force_string(tmp);
  153.         tlen += tmp->stlen;
  154.     }
  155.     tlen += (NF - 1) * ofslen;
  156.     if ((long) tlen < 0)
  157.         tlen = 0;
  158.     emalloc(ops, char *, tlen + 2, "rebuild_record");
  159.     cops = ops;
  160.     ops[0] = '\0';
  161.     for (i = 1;  i <= NF; i++) {
  162.         tmp = fields_arr[i];
  163.         /* copy field */
  164.         if (tmp->stlen == 1)
  165.             *cops++ = tmp->stptr[0];
  166.         else if (tmp->stlen != 0) {
  167.             memcpy(cops, tmp->stptr, tmp->stlen);
  168.             cops += tmp->stlen;
  169.         }
  170.         /* copy OFS */
  171.         if (i != NF) {
  172.             if (ofslen == 1)
  173.                 *cops++ = ofs->stptr[0];
  174.             else if (ofslen != 0) {
  175.                 memcpy(cops, ofs->stptr, ofslen);
  176.                 cops += ofslen;
  177.             }
  178.         }
  179.     }
  180.     tmp = make_str_node(ops, tlen, ALREADY_MALLOCED);
  181.  
  182.     /*
  183.      * Since we are about to unref fields_arr[0], we want to find
  184.      * any fields that still point into it, and have them point
  185.      * into the new field zero.
  186.      */
  187.     f0start = fields_arr[0]->stptr;
  188.     f0end = fields_arr[0]->stptr + fields_arr[0]->stlen;
  189.     for (cops = ops, i = 1; i <= NF; i++) {
  190.         char *field_data = fields_arr[i]->stptr;
  191.  
  192.         if (fields_arr[i]->stlen > 0
  193.             && f0start <= field_data && field_data < f0end)
  194.             fields_arr[i]->stptr = cops;
  195.  
  196.         cops += fields_arr[i]->stlen + ofslen;
  197.     }
  198.  
  199.     unref(fields_arr[0]);
  200.  
  201.     fields_arr[0] = tmp;
  202.     field0_valid = TRUE;
  203. }
  204.  
  205. /*
  206.  * set_record:
  207.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  208.  * or to NF.  At that point, parse only as much as necessary.
  209.  */
  210. void
  211. set_record(buf, cnt, freeold)
  212. char *buf;        /* ignored if ! freeold */
  213. int cnt;        /* ignored if ! freeold */
  214. int freeold;
  215. {
  216.     register int i;
  217.     NODE *n;
  218.  
  219.     NF = -1;
  220.     for (i = 1; i <= parse_high_water; i++) {
  221.         unref(fields_arr[i]);
  222.         getnode(n);
  223.         *n = *Null_field;
  224.         fields_arr[i] = n;
  225.     }
  226.  
  227.     parse_high_water = 0;
  228.     /*
  229.      * $0 = $0 should resplit using the current value of FS, thus,
  230.      * this is executed orthogonally to the value of freeold.
  231.      */
  232.     if (resave_fs) {
  233.         resave_fs = FALSE;
  234.         unref(save_FS);
  235.         save_FS = dupnode(FS_node->var_value);
  236.     }
  237.     if (freeold) {
  238.         unref(fields_arr[0]);
  239.         getnode(n);
  240.         n->stptr = buf;
  241.         n->stlen = cnt;
  242.         n->stref = 1;
  243.         n->type = Node_val;
  244.         n->stfmt = -1;
  245.         n->flags = (STRING|STR|MAYBE_NUM|SCALAR|FIELD);
  246.         fields_arr[0] = n;
  247.     }
  248.     fields_arr[0]->flags |= MAYBE_NUM;
  249.     field0_valid = TRUE;
  250. }
  251.  
  252. /* reset_record --- start over again with current $0 */
  253.  
  254. void
  255. reset_record()
  256. {
  257.     (void) force_string(fields_arr[0]);
  258.     set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, FALSE);
  259. }
  260.  
  261. /* set_NF --- handle what happens to $0 and fields when NF is changed */
  262.  
  263. void
  264. set_NF()
  265. {
  266.     register int i;
  267.     NODE *n;
  268.  
  269.     assert(NF != -1);
  270.  
  271.     NF = (long) force_number(NF_node->var_value);
  272.     if (NF > nf_high_water)
  273.         grow_fields_arr(NF);
  274.     if (parse_high_water < NF) {
  275.         for (i = parse_high_water + 1; i <= NF; i++) {
  276.             unref(fields_arr[i]);
  277.             getnode(n);
  278.             *n = *Null_field;
  279.             fields_arr[i] = n;
  280.         }
  281.     } else if (parse_high_water > 0) {
  282.         for (i = NF + 1; i <= parse_high_water; i++) {
  283.             unref(fields_arr[i]);
  284.             getnode(n);
  285.             *n = *Null_field;
  286.             fields_arr[i] = n;
  287.         }
  288.         parse_high_water = NF;
  289.     }
  290.     field0_valid = FALSE;
  291. }
  292.  
  293. /*
  294.  * re_parse_field --- parse fields using a regexp.
  295.  *
  296.  * This is called both from get_field() and from do_split()
  297.  * via (*parse_field)().  This variation is for when FS is a regular
  298.  * expression -- either user-defined or because RS=="" and FS==" "
  299.  */
  300. static long
  301. re_parse_field(up_to, buf, len, fs, rp, set, n)
  302. long up_to;    /* parse only up to this field number */
  303. char **buf;    /* on input: string to parse; on output: point to start next */
  304. int len;
  305. NODE *fs;
  306. Regexp *rp;
  307. Setfunc set;    /* routine to set the value of the parsed field */
  308. NODE *n;
  309. {
  310.     register char *scan = *buf;
  311.     register long nf = parse_high_water;
  312.     register char *field;
  313.     register char *end = scan + len;
  314.  
  315.     if (up_to == HUGE)
  316.         nf = 0;
  317.     if (len == 0)
  318.         return nf;
  319.  
  320.     if (RS_is_null && default_FS)
  321.         while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n'))
  322.             scan++;
  323.     field = scan;
  324.     while (scan < end
  325.            && research(rp, scan, 0, (end - scan), TRUE) != -1
  326.            && nf < up_to) {
  327.         if (REEND(rp, scan) == RESTART(rp, scan)) {   /* null match */
  328.             scan++;
  329.             if (scan == end) {
  330.                 (*set)(++nf, field, (long)(scan - field), n);
  331.                 up_to = nf;
  332.                 break;
  333.             }
  334.             continue;
  335.         }
  336.         (*set)(++nf, field,
  337.                (long)(scan + RESTART(rp, scan) - field), n);
  338.         scan += REEND(rp, scan);
  339.         field = scan;
  340.         if (scan == end)    /* FS at end of record */
  341.             (*set)(++nf, field, 0L, n);
  342.     }
  343.     if (nf != up_to && scan < end) {
  344.         (*set)(++nf, scan, (long)(end - scan), n);
  345.         scan = end;
  346.     }
  347.     *buf = scan;
  348.     return (nf);
  349. }
  350.  
  351. /*
  352.  * def_parse_field --- default field parsing.
  353.  *
  354.  * This is called both from get_field() and from do_split()
  355.  * via (*parse_field)().  This variation is for when FS is a single space
  356.  * character.
  357.  */
  358.  
  359. static long
  360. def_parse_field(up_to, buf, len, fs, rp, set, n)
  361. long up_to;    /* parse only up to this field number */
  362. char **buf;    /* on input: string to parse; on output: point to start next */
  363. int len;
  364. NODE *fs;
  365. Regexp *rp;
  366. Setfunc set;    /* routine to set the value of the parsed field */
  367. NODE *n;
  368. {
  369.     register char *scan = *buf;
  370.     register long nf = parse_high_water;
  371.     register char *field;
  372.     register char *end = scan + len;
  373.     char sav;
  374.  
  375.     if (up_to == HUGE)
  376.         nf = 0;
  377.     if (len == 0)
  378.         return nf;
  379.  
  380.     /*
  381.      * Nasty special case. If FS set to "", return whole record
  382.      * as first field. This is not worth a separate function.
  383.      */
  384.     if (fs->stlen == 0) {
  385.         (*set)(++nf, *buf, len, n);
  386.         *buf += len;
  387.         return nf;
  388.     }
  389.  
  390.     /* before doing anything save the char at *end */
  391.     sav = *end;
  392.     /* because it will be destroyed now: */
  393.  
  394.     *end = ' ';    /* sentinel character */
  395.     for (; nf < up_to; scan++) {
  396.         /*
  397.          * special case:  fs is single space, strip leading whitespace 
  398.          */
  399.         while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n'))
  400.             scan++;
  401.         if (scan >= end)
  402.             break;
  403.         field = scan;
  404.         while (*scan != ' ' && *scan != '\t' && *scan != '\n')
  405.             scan++;
  406.         (*set)(++nf, field, (long)(scan - field), n);
  407.         if (scan == end)
  408.             break;
  409.     }
  410.  
  411.     /* everything done, restore original char at *end */
  412.     *end = sav;
  413.  
  414.     *buf = scan;
  415.     return nf;
  416. }
  417.  
  418. /*
  419.  * posix_def_parse_field --- default field parsing.
  420.  *
  421.  * This is called both from get_field() and from do_split()
  422.  * via (*parse_field)().  This variation is for when FS is a single space
  423.  * character.  The only difference between this and def_parse_field()
  424.  * is that this one does not allow newlines to separate fields.
  425.  */
  426.  
  427. static long
  428. posix_def_parse_field(up_to, buf, len, fs, rp, set, n)
  429. long up_to;    /* parse only up to this field number */
  430. char **buf;    /* on input: string to parse; on output: point to start next */
  431. int len;
  432. NODE *fs;
  433. Regexp *rp;
  434. Setfunc set;    /* routine to set the value of the parsed field */
  435. NODE *n;
  436. {
  437.     register char *scan = *buf;
  438.     register long nf = parse_high_water;
  439.     register char *field;
  440.     register char *end = scan + len;
  441.     char sav;
  442.  
  443.     if (up_to == HUGE)
  444.         nf = 0;
  445.     if (len == 0)
  446.         return nf;
  447.  
  448.     /*
  449.      * Nasty special case. If FS set to "", return whole record
  450.      * as first field. This is not worth a separate function.
  451.      */
  452.     if (fs->stlen == 0) {
  453.         (*set)(++nf, *buf, len, n);
  454.         *buf += len;
  455.         return nf;
  456.     }
  457.  
  458.     /* before doing anything save the char at *end */
  459.     sav = *end;
  460.     /* because it will be destroyed now: */
  461.  
  462.     *end = ' ';    /* sentinel character */
  463.     for (; nf < up_to; scan++) {
  464.         /*
  465.          * special case:  fs is single space, strip leading whitespace 
  466.          */
  467.         while (scan < end && (*scan == ' ' || *scan == '\t'))
  468.             scan++;
  469.         if (scan >= end)
  470.             break;
  471.         field = scan;
  472.         while (*scan != ' ' && *scan != '\t')
  473.             scan++;
  474.         (*set)(++nf, field, (long)(scan - field), n);
  475.         if (scan == end)
  476.             break;
  477.     }
  478.  
  479.     /* everything done, restore original char at *end */
  480.     *end = sav;
  481.  
  482.     *buf = scan;
  483.     return nf;
  484. }
  485.  
  486. /*
  487.  * null_parse_field --- each character is a separate field
  488.  *
  489.  * This is called both from get_field() and from do_split()
  490.  * via (*parse_field)().  This variation is for when FS is the null string.
  491.  */
  492. static long
  493. null_parse_field(up_to, buf, len, fs, rp, set, n)
  494. long up_to;    /* parse only up to this field number */
  495. char **buf;    /* on input: string to parse; on output: point to start next */
  496. int len;
  497. NODE *fs;
  498. Regexp *rp;
  499. Setfunc set;    /* routine to set the value of the parsed field */
  500. NODE *n;
  501. {
  502.     register char *scan = *buf;
  503.     register long nf = parse_high_water;
  504.     register char *end = scan + len;
  505.  
  506.     if (up_to == HUGE)
  507.         nf = 0;
  508.     if (len == 0)
  509.         return nf;
  510.  
  511.     for (; nf < up_to && scan < end; scan++)
  512.         (*set)(++nf, scan, 1L, n);
  513.  
  514.     *buf = scan;
  515.     return nf;
  516. }
  517.  
  518. /*
  519.  * sc_parse_field --- single character field separator
  520.  *
  521.  * This is called both from get_field() and from do_split()
  522.  * via (*parse_field)().  This variation is for when FS is a single character
  523.  * other than space.
  524.  */
  525. static long
  526. sc_parse_field(up_to, buf, len, fs, rp, set, n)
  527. long up_to;    /* parse only up to this field number */
  528. char **buf;    /* on input: string to parse; on output: point to start next */
  529. int len;
  530. NODE *fs;
  531. Regexp *rp;
  532. Setfunc set;    /* routine to set the value of the parsed field */
  533. NODE *n;
  534. {
  535.     register char *scan = *buf;
  536.     register char fschar;
  537.     register long nf = parse_high_water;
  538.     register char *field;
  539.     register char *end = scan + len;
  540.     int onecase;
  541.     char sav;
  542.  
  543.     if (up_to == HUGE)
  544.         nf = 0;
  545.     if (len == 0)
  546.         return nf;
  547.  
  548.     if (RS_is_null && fs->stlen == 0)
  549.         fschar = '\n';
  550.     else
  551.         fschar = fs->stptr[0];
  552.  
  553.     onecase = (IGNORECASE && isalpha(fschar));
  554.     if (onecase)
  555.         fschar = casetable[(int) fschar];
  556.  
  557.     /* before doing anything save the char at *end */
  558.     sav = *end;
  559.     /* because it will be destroyed now: */
  560.     *end = fschar;    /* sentinel character */
  561.  
  562.     for (; nf < up_to;) {
  563.         field = scan;
  564.         if (onecase) {
  565.             while (casetable[(int) *scan] != fschar)
  566.                 scan++;
  567.         } else {
  568.             while (*scan != fschar)
  569.                 scan++;
  570.         }
  571.         (*set)(++nf, field, (long)(scan - field), n);
  572.         if (scan == end)
  573.             break;
  574.         scan++;
  575.         if (scan == end) {    /* FS at end of record */
  576.             (*set)(++nf, field, 0L, n);
  577.             break;
  578.         }
  579.     }
  580.  
  581.     /* everything done, restore original char at *end */
  582.     *end = sav;
  583.  
  584.     *buf = scan;
  585.     return nf;
  586. }
  587.  
  588. /*
  589.  * fw_parse_field --- field parsing using FIELDWIDTHS spec
  590.  *
  591.  * This is called both from get_field() and from do_split()
  592.  * via (*parse_field)().  This variation is for fields are fixed widths.
  593.  */
  594. static long
  595. fw_parse_field(up_to, buf, len, fs, rp, set, n)
  596. long up_to;    /* parse only up to this field number */
  597. char **buf;    /* on input: string to parse; on output: point to start next */
  598. int len;
  599. NODE *fs;
  600. Regexp *rp;
  601. Setfunc set;    /* routine to set the value of the parsed field */
  602. NODE *n;
  603. {
  604.     register char *scan = *buf;
  605.     register long nf = parse_high_water;
  606.     register char *end = scan + len;
  607.  
  608.     if (up_to == HUGE)
  609.         nf = 0;
  610.     if (len == 0)
  611.         return nf;
  612.     for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) {
  613.         if (len > end - scan)
  614.             len = end - scan;
  615.         (*set)(++nf, scan, (long) len, n);
  616.         scan += len;
  617.     }
  618.     if (len == -1)
  619.         *buf = end;
  620.     else
  621.         *buf = scan;
  622.     return nf;
  623. }
  624.  
  625. /* get_field --- return a particular $n */
  626.  
  627. NODE **
  628. get_field(requested, assign)
  629. register long requested;
  630. Func_ptr *assign;    /* this field is on the LHS of an assign */
  631. {
  632.     /*
  633.      * if requesting whole line but some other field has been altered,
  634.      * then the whole line must be rebuilt
  635.      */
  636.     if (requested == 0) {
  637.         if (! field0_valid) {
  638.             /* first, parse remainder of input record */
  639.             if (NF == -1) {
  640.                 NF = (*parse_field)(HUGE-1, &parse_extent,
  641.                         fields_arr[0]->stlen -
  642.                     (parse_extent - fields_arr[0]->stptr),
  643.                         save_FS, FS_regexp, set_field,
  644.                     (NODE *) NULL);
  645.                 parse_high_water = NF;
  646.             }
  647.             rebuild_record();
  648.         }
  649.         if (assign != NULL)
  650.             *assign = reset_record;
  651.         return &fields_arr[0];
  652.     }
  653.  
  654.     /* assert(requested > 0); */
  655.  
  656.     if (assign != NULL)
  657.         field0_valid = FALSE;        /* $0 needs reconstruction */
  658.  
  659.     if (requested <= parse_high_water)    /* already parsed this field */
  660.         return &fields_arr[requested];
  661.  
  662.     if (NF == -1) {    /* have not yet parsed to end of record */
  663.         /*
  664.          * parse up to requested fields, calling set_field() for each,
  665.          * saving in parse_extent the point where the parse left off
  666.          */
  667.         if (parse_high_water == 0)    /* starting at the beginning */
  668.             parse_extent = fields_arr[0]->stptr;
  669.         parse_high_water = (*parse_field)(requested, &parse_extent,
  670.              fields_arr[0]->stlen - (parse_extent - fields_arr[0]->stptr),
  671.              save_FS, FS_regexp, set_field, (NODE *) NULL);
  672.  
  673.         /*
  674.          * if we reached the end of the record, set NF to the number of
  675.          * fields so far.  Note that requested might actually refer to
  676.          * a field that is beyond the end of the record, but we won't
  677.          * set NF to that value at this point, since this is only a
  678.          * reference to the field and NF only gets set if the field
  679.          * is assigned to -- this case is handled below
  680.          */
  681.         if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen)
  682.             NF = parse_high_water;
  683.         if (requested == HUGE-1)    /* HUGE-1 means set NF */
  684.             requested = parse_high_water;
  685.     }
  686.     if (parse_high_water < requested) { /* requested beyond end of record */
  687.         if (assign != NULL) {    /* expand record */
  688.             if (requested > nf_high_water)
  689.                 grow_fields_arr(requested);
  690.  
  691.             NF = requested;
  692.             parse_high_water = requested;
  693.         } else
  694.             return &Null_field;
  695.     }
  696.  
  697.     return &fields_arr[requested];
  698. }
  699.  
  700. /* set_element --- set an array element, used by do_split() */
  701.  
  702. static void
  703. set_element(num, s, len, n)
  704. long num;
  705. char *s;
  706. long len;
  707. NODE *n;
  708. {
  709.     register NODE *it;
  710.  
  711.     it = make_string(s, len);
  712.     it->flags |= MAYBE_NUM;
  713.     *assoc_lookup(n, tmp_number((AWKNUM) (num))) = it;
  714. }
  715.  
  716. /* do_split --- implement split(), semantics are same as for field splitting */
  717.  
  718. NODE *
  719. do_split(tree)
  720. NODE *tree;
  721. {
  722.     NODE *src, *arr, *sep, *tmp;
  723.     NODE *fs;
  724.     char *s;
  725.     long (*parseit) P((long, char **, int, NODE *,
  726.              Regexp *, Setfunc, NODE *));
  727.     Regexp *rp = NULL;
  728.  
  729.     /*
  730.      * do dupnode(), to avoid problems like
  731.      *    x = split(a[1], a, "blah")
  732.      * since we assoc_clear the array. gack.
  733.      * this also gives us complete call by value semantics.
  734.      */
  735.     tmp = tree_eval(tree->lnode);
  736.     src = dupnode(tmp);
  737.     free_temp(tmp);
  738.  
  739.     arr = tree->rnode->lnode;
  740.     if (tree->rnode->rnode != NULL)
  741.         sep = tree->rnode->rnode->lnode;    /* 3rd arg */
  742.     else
  743.         sep = NULL;
  744.  
  745.     (void) force_string(src);
  746.  
  747.     if (arr->type == Node_param_list)
  748.         arr = stack_ptr[arr->param_cnt];
  749.     if (arr->type != Node_var && arr->type != Node_var_array)
  750.         fatal("second argument of split is not an array");
  751.     arr->type = Node_var_array;
  752.     assoc_clear(arr);
  753.  
  754.     if (sep->re_flags & FS_DFLT) {
  755.         parseit = parse_field;
  756.         fs = force_string(FS_node->var_value);
  757.         rp = FS_regexp;
  758.     } else {
  759.         tmp = force_string(tree_eval(sep->re_exp));
  760.         if (tmp->stlen == 0)
  761.             parseit = null_parse_field;
  762.         else if (tmp->stlen == 1 && (sep->re_flags & CONST) == 0) {
  763.             if (tmp->stptr[0] == ' ') {
  764.                 if (do_posix)
  765.                     parseit = posix_def_parse_field;
  766.                 else
  767.                     parseit = def_parse_field;
  768.             } else
  769.                 parseit = sc_parse_field;
  770.         } else {
  771.             parseit = re_parse_field;
  772.             rp = re_update(sep);
  773.         }
  774.         fs = tmp;
  775.     }
  776.  
  777.     s = src->stptr;
  778.     tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int) src->stlen,
  779.                          fs, rp, set_element, arr));
  780.     unref(src);
  781.     free_temp(sep);
  782.     return tmp;
  783. }
  784.  
  785. /* set_FIELDWIDTHS --- handle an assignment to FIELDWIDTHS */
  786.  
  787. void
  788. set_FIELDWIDTHS()
  789. {
  790.     register char *scan;
  791.     char *end;
  792.     register int i;
  793.     static int fw_alloc = 1;
  794.     static int warned = FALSE;
  795.     extern double strtod();
  796.  
  797.     if (do_lint && ! warned) {
  798.         warned = TRUE;
  799.         warning("use of FIELDWIDTHS is a gawk extension");
  800.     }
  801.     if (do_traditional)    /* quick and dirty, does the trick */
  802.         return;
  803.  
  804.     /*
  805.      * If changing the way fields are split, obey least-suprise
  806.      * semantics, and force $0 to be split totally.
  807.      */
  808.     if (fields_arr != NULL)
  809.         (void) get_field(HUGE - 1, 0);
  810.  
  811.     parse_field = fw_parse_field;
  812.     scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
  813.     end = scan + 1;
  814.     if (FIELDWIDTHS == NULL)
  815.         emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  816.     FIELDWIDTHS[0] = 0;
  817.     for (i = 1; ; i++) {
  818.         if (i >= fw_alloc) {
  819.             fw_alloc *= 2;
  820.             erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  821.         }
  822.         FIELDWIDTHS[i] = (int) strtod(scan, &end);
  823.         if (end == scan)
  824.             break;
  825.         scan = end;
  826.     }
  827.     FIELDWIDTHS[i] = -1;
  828. }
  829.  
  830. void
  831. set_FS_if_not_FIELDWIDTHS()
  832. {
  833.     if (parse_field != fw_parse_field)
  834.         set_FS();
  835. }
  836.  
  837. /* set_FS --- handle things when FS is assigned to */
  838.  
  839. void
  840. set_FS()
  841. {
  842.     char buf[10];
  843.     NODE *fs;
  844.     static NODE *save_fs = NULL;
  845.     static NODE *save_rs = NULL;
  846.  
  847.     /*
  848.      * If changing the way fields are split, obey least-suprise
  849.      * semantics, and force $0 to be split totally.
  850.      */
  851.     if (fields_arr != NULL)
  852.         (void) get_field(HUGE - 1, 0);
  853.  
  854.     if (save_fs && cmp_nodes(FS_node->var_value, save_fs) == 0
  855.      && save_rs && cmp_nodes(RS_node->var_value, save_rs) == 0)
  856.         return;
  857.     unref(save_fs);
  858.     save_fs = dupnode(FS_node->var_value);
  859.     unref(save_rs);
  860.     save_rs = dupnode(RS_node->var_value);
  861.     resave_fs = TRUE;
  862.       buf[0] = '\0';
  863.       default_FS = FALSE;
  864.       if (FS_regexp) {
  865.         refree(FS_regexp);
  866.         FS_regexp = NULL;
  867.     }
  868.     fs = force_string(FS_node->var_value);
  869.     if (! do_traditional && fs->stlen == 0)
  870.         parse_field = null_parse_field;
  871.     else if (fs->stlen > 1)
  872.         parse_field = re_parse_field;
  873.     else if (RS_is_null) {
  874.         parse_field = sc_parse_field;
  875.         if (fs->stlen == 1) {
  876.             if (fs->stptr[0] == ' ') {
  877.                 default_FS = TRUE;
  878.                 strcpy(buf, "[ \t\n]+");
  879.             } else if (fs->stptr[0] != '\n')
  880.                 sprintf(buf, "[%c\n]", fs->stptr[0]);
  881.         }
  882.     } else {
  883.         if (do_posix)
  884.             parse_field = posix_def_parse_field;
  885.         else
  886.             parse_field = def_parse_field;
  887.         if (fs->stptr[0] == ' ' && fs->stlen == 1)
  888.             default_FS = TRUE;
  889.         else if (fs->stptr[0] != ' ' && fs->stlen == 1) {
  890.             if (! IGNORECASE)
  891.                 parse_field = sc_parse_field;
  892.             else if (fs->stptr[0] == '\\')
  893.                 /* yet another special case */
  894.                 strcpy(buf, "[\\\\]");
  895.             else
  896.                 sprintf(buf, "[%c]", fs->stptr[0]);
  897.         }
  898.     }
  899.     if (buf[0] != '\0') {
  900.         FS_regexp = make_regexp(buf, strlen(buf), IGNORECASE, TRUE);
  901.         parse_field = re_parse_field;
  902.     } else if (parse_field == re_parse_field) {
  903.         FS_regexp = make_regexp(fs->stptr, fs->stlen, IGNORECASE, TRUE);
  904.     } else
  905.         FS_regexp = NULL;
  906. }
  907.  
  908. /* using_fieldwidths --- is FS or FIELDWIDTHS in use? */
  909.  
  910. int
  911. using_fieldwidths()
  912. {
  913.     return     parse_field == fw_parse_field;
  914. }
  915.  
  916.