home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 11 / AUCD11B.iso / LANGUAGES / WraithSet / AwkStuff / GawkSrc / c / field < prev    next >
Encoding:
Text File  |  1999-06-30  |  22.3 KB  |  928 lines

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