home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gawk-2.15.6-base.tgz / gawk-2.15.6-base.tar / fsf / gawk / field.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  17KB  |  696 lines

  1. /*
  2.  * field.c - routines for dealing with fields and record parsing
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1995 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. typedef void (* Setfunc) P((int, char*, int, NODE *));
  29.  
  30. static long (*parse_field) P((int, char **, int, NODE *,
  31.                  Regexp *, Setfunc, NODE *));
  32. static void rebuild_record P((void));
  33. static long re_parse_field P((int, char **, int, NODE *,
  34.                  Regexp *, Setfunc, NODE *));
  35. static long def_parse_field P((int, char **, int, NODE *,
  36.                   Regexp *, Setfunc, NODE *));
  37. static long sc_parse_field P((int, char **, int, NODE *,
  38.                  Regexp *, Setfunc, NODE *));
  39. static long fw_parse_field P((int, char **, int, NODE *,
  40.                  Regexp *, Setfunc, NODE *));
  41. static void set_element P((int, char *, int, NODE *));
  42. static void grow_fields_arr P((long num));
  43. static void set_field P((int num, char *str, int len, NODE *dummy));
  44.  
  45.  
  46. static Regexp *FS_regexp = NULL;
  47. static char *parse_extent;    /* marks where to restart parse of record */
  48. static long parse_high_water=0;    /* field number that we have parsed so far */
  49. static long nf_high_water = 0;    /* size of fields_arr */
  50. static int resave_fs;
  51. static NODE *save_FS;        /* save current value of FS when line is read,
  52.                  * to be used in deferred parsing
  53.                  */
  54.  
  55. NODE **fields_arr;        /* array of pointers to the field nodes */
  56. int field0_valid;        /* $(>0) has not been changed yet */
  57. int default_FS;
  58. static NODE **nodes;        /* permanent repository of field nodes */
  59. static int *FIELDWIDTHS = NULL;
  60.  
  61. void
  62. init_fields()
  63. {
  64.     NODE *n;
  65.  
  66.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  67.     emalloc(nodes, NODE **, sizeof(NODE *), "init_fields");
  68.     getnode(n);
  69.     *n = *Nnull_string;
  70.     fields_arr[0] = nodes[0] = n;
  71.     parse_extent = fields_arr[0]->stptr;
  72.     save_FS = dupnode(FS_node->var_value);
  73.     field0_valid = 1;
  74. }
  75.  
  76.  
  77. static void
  78. grow_fields_arr(num)
  79. long num;
  80. {
  81.     register int t;
  82.     register NODE *n;
  83.  
  84.     erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
  85.     erealloc(nodes, NODE **, (num+1) * sizeof(NODE *), "set_field");
  86.     for (t = nf_high_water+1; t <= num; t++) {
  87.         getnode(n);
  88.         *n = *Nnull_string;
  89.         fields_arr[t] = nodes[t] = n;
  90.     }
  91.     nf_high_water = num;
  92. }
  93.  
  94. /*ARGSUSED*/
  95. static void
  96. set_field(num, str, len, dummy)
  97. int num;
  98. char *str;
  99. int len;
  100. NODE *dummy;    /* not used -- just to make interface same as set_element */
  101. {
  102.     register NODE *n;
  103.  
  104.     if (num > nf_high_water)
  105.         grow_fields_arr(num);
  106.     n = nodes[num];
  107.     n->stptr = str;
  108.     n->stlen = len;
  109.     n->flags = (PERM|STR|STRING|MAYBE_NUM);
  110.     fields_arr[num] = n;
  111. }
  112.  
  113. /* Someone assigned a value to $(something).  Fix up $0 to be right */
  114. static void
  115. rebuild_record()
  116. {
  117.     register size_t tlen;
  118.     register NODE *tmp;
  119.     NODE *ofs;
  120.     char *ops;
  121.     register char *cops;
  122.     register NODE **ptr;
  123.     register size_t ofslen;
  124.  
  125.     tlen = 0;
  126.     ofs = force_string(OFS_node->var_value);
  127.     ofslen = ofs->stlen;
  128.     ptr = &fields_arr[NF];
  129.     while (ptr > &fields_arr[0]) {
  130.         tmp = force_string(*ptr);
  131.         tlen += tmp->stlen;
  132.         ptr--;
  133.     }
  134.     tlen += (NF - 1) * ofslen;
  135.     if ((long)tlen < 0)
  136.         tlen = 0;
  137.     emalloc(ops, char *, tlen + 2, "rebuild_record");
  138.     cops = ops;
  139.     ops[0] = '\0';
  140.     for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) {
  141.         tmp = *ptr;
  142.         if (tmp->stlen == 1)
  143.             *cops++ = tmp->stptr[0];
  144.         else if (tmp->stlen != 0) {
  145.             memcpy(cops, tmp->stptr, tmp->stlen);
  146.             cops += tmp->stlen;
  147.         }
  148.         if (ptr != &fields_arr[NF]) {
  149.             if (ofslen == 1)
  150.                 *cops++ = ofs->stptr[0];
  151.             else if (ofslen != 0) {
  152.                 memcpy(cops, ofs->stptr, ofslen);
  153.                 cops += ofslen;
  154.             }
  155.         }
  156.     }
  157.     tmp = make_str_node(ops, tlen, ALREADY_MALLOCED);
  158.     unref(fields_arr[0]);
  159.     fields_arr[0] = tmp;
  160.     field0_valid = 1;
  161. }
  162.  
  163. /*
  164.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  165.  * or to NF.  At that point, parse only as much as necessary.
  166.  */
  167. void
  168. set_record(buf, cnt, freeold)
  169. char *buf;
  170. int cnt;
  171. int freeold;
  172. {
  173.     register int i;
  174.  
  175.     NF = -1;
  176.     for (i = 1; i <= parse_high_water; i++) {
  177.         unref(fields_arr[i]);
  178.     }
  179.     parse_high_water = 0;
  180.     if (freeold) {
  181.         unref(fields_arr[0]);
  182.         if (resave_fs) {
  183.             resave_fs = 0;
  184.             unref(save_FS);
  185.             save_FS = dupnode(FS_node->var_value);
  186.         }
  187.         nodes[0]->stptr = buf;
  188.         nodes[0]->stlen = cnt;
  189.         nodes[0]->stref = 1;
  190.         nodes[0]->flags = (STRING|STR|PERM|MAYBE_NUM);
  191.         fields_arr[0] = nodes[0];
  192.     }
  193.     fields_arr[0]->flags |= MAYBE_NUM;
  194.     field0_valid = 1;
  195. }
  196.  
  197. void
  198. reset_record()
  199. {
  200.     (void) force_string(fields_arr[0]);
  201.     set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, 0);
  202. }
  203.  
  204. void
  205. set_NF()
  206. {
  207.     register int i;
  208.  
  209.     NF = (long) force_number(NF_node->var_value);
  210.     if (NF > nf_high_water)
  211.         grow_fields_arr(NF);
  212.     for (i = parse_high_water + 1; i <= NF; i++) {
  213.         unref(fields_arr[i]);
  214.         fields_arr[i] = Nnull_string;
  215.     }
  216.     field0_valid = 0;
  217. }
  218.  
  219. /*
  220.  * this is called both from get_field() and from do_split()
  221.  * via (*parse_field)().  This variation is for when FS is a regular
  222.  * expression -- either user-defined or because RS=="" and FS==" "
  223.  */
  224. static long
  225. re_parse_field(up_to, buf, len, fs, rp, set, n)
  226. int up_to;    /* parse only up to this field number */
  227. char **buf;    /* on input: string to parse; on output: point to start next */
  228. int len;
  229. NODE *fs;
  230. Regexp *rp;
  231. Setfunc set;    /* routine to set the value of the parsed field */
  232. NODE *n;
  233. {
  234.     register char *scan = *buf;
  235.     register int nf = parse_high_water;
  236.     register char *field;
  237.     register char *end = scan + len;
  238.  
  239.     if (up_to == HUGE)
  240.         nf = 0;
  241.     if (len == 0)
  242.         return nf;
  243.  
  244.     if (*RS == 0 && default_FS)
  245.         while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n'))
  246.             scan++;
  247.     field = scan;
  248.     while (scan < end
  249.            && research(rp, scan, 0, (end - scan), 1) != -1
  250.            && nf < up_to) {
  251.         if (REEND(rp, scan) == RESTART(rp, scan)) {   /* null match */
  252.             scan++;
  253.             if (scan == end) {
  254.                 (*set)(++nf, field, (int)(scan - field), n);
  255.                 up_to = nf;
  256.                 break;
  257.             }
  258.             continue;
  259.         }
  260.         (*set)(++nf, field,
  261.                (int)(scan + RESTART(rp, scan) - field), n);
  262.         scan += REEND(rp, scan);
  263.         field = scan;
  264.         if (scan == end)    /* FS at end of record */
  265.             (*set)(++nf, field, 0, n);
  266.     }
  267.     if (nf != up_to && scan < end) {
  268.         (*set)(++nf, scan, (int)(end - scan), n);
  269.         scan = end;
  270.     }
  271.     *buf = scan;
  272.     return (nf);
  273. }
  274.  
  275. /*
  276.  * this is called both from get_field() and from do_split()
  277.  * via (*parse_field)().  This variation is for when FS is a single space
  278.  * character.
  279.  */
  280. static long
  281. def_parse_field(up_to, buf, len, fs, rp, set, n)
  282. int up_to;    /* parse only up to this field number */
  283. char **buf;    /* on input: string to parse; on output: point to start next */
  284. int len;
  285. NODE *fs;
  286. Regexp *rp;
  287. Setfunc set;    /* routine to set the value of the parsed field */
  288. NODE *n;
  289. {
  290.     register char *scan = *buf;
  291.     register int nf = parse_high_water;
  292.     register char *field;
  293.     register char *end = scan + len;
  294.     char sav;
  295.  
  296.     if (up_to == HUGE)
  297.         nf = 0;
  298.     if (len == 0)
  299.         return nf;
  300.  
  301.     /*
  302.      * Nasty special case. If FS set to "", return whole record
  303.      * as first field. This is not worth a separate function.
  304.      */
  305.     if (fs->stlen == 0) {
  306.         (*set)(++nf, *buf, len, n);
  307.         *buf += len;
  308.         return nf;
  309.     }
  310.  
  311.     /* before doing anything save the char at *end */
  312.     sav = *end;
  313.     /* because it will be destroyed now: */
  314.  
  315.     *end = ' ';    /* sentinel character */
  316.     for (; nf < up_to; scan++) {
  317.         /*
  318.          * special case:  fs is single space, strip leading whitespace 
  319.          */
  320.         while (scan < end && (*scan == ' ' || *scan == '\t'))
  321.             scan++;
  322.         if (scan >= end)
  323.             break;
  324.         field = scan;
  325.         while (*scan != ' ' && *scan != '\t')
  326.             scan++;
  327.         (*set)(++nf, field, (int)(scan - field), n);
  328.         if (scan == end)
  329.             break;
  330.     }
  331.  
  332.     /* everything done, restore original char at *end */
  333.     *end = sav;
  334.  
  335.     *buf = scan;
  336.     return nf;
  337. }
  338.  
  339. /*
  340.  * this is called both from get_field() and from do_split()
  341.  * via (*parse_field)().  This variation is for when FS is a single character
  342.  * other than space.
  343.  */
  344. static long
  345. sc_parse_field(up_to, buf, len, fs, rp, set, n)
  346. int up_to;    /* parse only up to this field number */
  347. char **buf;    /* on input: string to parse; on output: point to start next */
  348. int len;
  349. NODE *fs;
  350. Regexp *rp;
  351. Setfunc set;    /* routine to set the value of the parsed field */
  352. NODE *n;
  353. {
  354.     register char *scan = *buf;
  355.     register char fschar;
  356.     register int nf = parse_high_water;
  357.     register char *field;
  358.     register char *end = scan + len;
  359.     char sav;
  360.  
  361.     if (up_to == HUGE)
  362.         nf = 0;
  363.     if (len == 0)
  364.         return nf;
  365.  
  366.     if (*RS == 0 && fs->stlen == 0)
  367.         fschar = '\n';
  368.     else
  369.         fschar = fs->stptr[0];
  370.  
  371.     /* before doing anything save the char at *end */
  372.     sav = *end;
  373.     /* because it will be destroyed now: */
  374.     *end = fschar;    /* sentinel character */
  375.  
  376.     for (; nf < up_to;) {
  377.         field = scan;
  378.         while (*scan != fschar)
  379.             scan++;
  380.         (*set)(++nf, field, (int)(scan - field), n);
  381.         if (scan == end)
  382.             break;
  383.         scan++;
  384.         if (scan == end) {    /* FS at end of record */
  385.             (*set)(++nf, field, 0, n);
  386.             break;
  387.         }
  388.     }
  389.  
  390.     /* everything done, restore original char at *end */
  391.     *end = sav;
  392.  
  393.     *buf = scan;
  394.     return nf;
  395. }
  396.  
  397. /*
  398.  * this is called both from get_field() and from do_split()
  399.  * via (*parse_field)().  This variation is for fields are fixed widths.
  400.  */
  401. static long
  402. fw_parse_field(up_to, buf, len, fs, rp, set, n)
  403. int up_to;    /* parse only up to this field number */
  404. char **buf;    /* on input: string to parse; on output: point to start next */
  405. int len;
  406. NODE *fs;
  407. Regexp *rp;
  408. Setfunc set;    /* routine to set the value of the parsed field */
  409. NODE *n;
  410. {
  411.     register char *scan = *buf;
  412.     register long nf = parse_high_water;
  413.     register char *end = scan + len;
  414.  
  415.     if (up_to == HUGE)
  416.         nf = 0;
  417.     if (len == 0)
  418.         return nf;
  419.     for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) {
  420.         if (len > end - scan)
  421.             len = end - scan;
  422.         (*set)(++nf, scan, len, n);
  423.         scan += len;
  424.     }
  425.     if (len == -1)
  426.         *buf = end;
  427.     else
  428.         *buf = scan;
  429.     return nf;
  430. }
  431.  
  432. NODE **
  433. get_field(requested, assign)
  434. register int requested;
  435. Func_ptr *assign;    /* this field is on the LHS of an assign */
  436. {
  437.     /*
  438.      * if requesting whole line but some other field has been altered,
  439.      * then the whole line must be rebuilt
  440.      */
  441.     if (requested == 0) {
  442.         if (!field0_valid) {
  443.             /* first, parse remainder of input record */
  444.             if (NF == -1) {
  445.                 NF = (*parse_field)(HUGE-1, &parse_extent,
  446.                         fields_arr[0]->stlen -
  447.                     (parse_extent - fields_arr[0]->stptr),
  448.                         save_FS, FS_regexp, set_field,
  449.                     (NODE *)NULL);
  450.                 parse_high_water = NF;
  451.             }
  452.             rebuild_record();
  453.         }
  454.         if (assign)
  455.             *assign = reset_record;
  456.         return &fields_arr[0];
  457.     }
  458.  
  459.     /* assert(requested > 0); */
  460.  
  461.     if (assign)
  462.         field0_valid = 0;        /* $0 needs reconstruction */
  463.  
  464.     if (requested <= parse_high_water)    /* already parsed this field */
  465.         return &fields_arr[requested];
  466.  
  467.     if (NF == -1) {    /* have not yet parsed to end of record */
  468.         /*
  469.          * parse up to requested fields, calling set_field() for each,
  470.          * saving in parse_extent the point where the parse left off
  471.          */
  472.         if (parse_high_water == 0)    /* starting at the beginning */
  473.             parse_extent = fields_arr[0]->stptr;
  474.         parse_high_water = (*parse_field)(requested, &parse_extent,
  475.              fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
  476.              save_FS, FS_regexp, set_field, (NODE *)NULL);
  477.  
  478.         /*
  479.          * if we reached the end of the record, set NF to the number of 
  480.          * fields so far.  Note that requested might actually refer to
  481.          * a field that is beyond the end of the record, but we won't
  482.          * set NF to that value at this point, since this is only a
  483.          * reference to the field and NF only gets set if the field
  484.          * is assigned to -- this case is handled below
  485.          */
  486.         if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen)
  487.             NF = parse_high_water;
  488.         if (requested == HUGE-1)    /* HUGE-1 means set NF */
  489.             requested = parse_high_water;
  490.     }
  491.     if (parse_high_water < requested) { /* requested beyond end of record */
  492.         if (assign) {    /* expand record */
  493.             register int i;
  494.  
  495.             if (requested > nf_high_water)
  496.                 grow_fields_arr(requested);
  497.  
  498.             /* fill in fields that don't exist */
  499.             for (i = parse_high_water + 1; i <= requested; i++)
  500.                 fields_arr[i] = Nnull_string;
  501.  
  502.             NF = requested;
  503.             parse_high_water = requested;
  504.         } else
  505.             return &Nnull_string;
  506.     }
  507.  
  508.     return &fields_arr[requested];
  509. }
  510.  
  511. static void
  512. set_element(num, s, len, n)
  513. int num;
  514. char *s;
  515. int len;
  516. NODE *n;
  517. {
  518.     register NODE *it;
  519.  
  520.     it = make_string(s, len);
  521.     it->flags |= MAYBE_NUM;
  522.     *assoc_lookup(n, tmp_number((AWKNUM) (num))) = it;
  523. }
  524.  
  525. NODE *
  526. do_split(tree)
  527. NODE *tree;
  528. {
  529.     NODE *t1, *t2, *t3, *tmp;
  530.     NODE *fs;
  531.     char *s;
  532.     long (*parseit)P((int, char **, int, NODE *,
  533.              Regexp *, Setfunc, NODE *));
  534.     Regexp *rp = NULL;
  535.  
  536.  
  537.     /*
  538.      * do dupnode(), to avoid problems like
  539.      *    x = split(a[1], a, "blah")
  540.      * since we assoc_clear the array. gack.
  541.      * this also gives up complete call by value semantics.
  542.      */
  543.     tmp = tree_eval(tree->lnode);
  544.     t1 = dupnode(tmp);
  545.     free_temp(tmp);
  546.  
  547.     t2 = tree->rnode->lnode;
  548.     t3 = tree->rnode->rnode->lnode;
  549.  
  550.     (void) force_string(t1);
  551.  
  552.     if (t2->type == Node_param_list)
  553.         t2 = stack_ptr[t2->param_cnt];
  554.     if (t2->type != Node_var && t2->type != Node_var_array)
  555.         fatal("second argument of split is not a variable");
  556.     assoc_clear(t2);
  557.  
  558.     if (t3->re_flags & FS_DFLT) {
  559.         parseit = parse_field;
  560.         fs = force_string(FS_node->var_value);
  561.         rp = FS_regexp;
  562.     } else {
  563.         tmp = force_string(tree_eval(t3->re_exp));
  564.         if (tmp->stlen == 1) {
  565.             if (tmp->stptr[0] == ' ')
  566.                 parseit = def_parse_field;
  567.             else
  568.                 parseit = sc_parse_field;
  569.         } else {
  570.             parseit = re_parse_field;
  571.             rp = re_update(t3);
  572.         }
  573.         fs = tmp;
  574.     }
  575.  
  576.     s = t1->stptr;
  577.     tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int)t1->stlen,
  578.                          fs, rp, set_element, t2));
  579.     unref(t1);
  580.     free_temp(t3);
  581.     return tmp;
  582. }
  583.  
  584. void
  585. set_FS()
  586. {
  587.     char buf[10];
  588.     NODE *fs;
  589.  
  590.     /*
  591.      * If changing the way fields are split, obey least-suprise
  592.      * semantics, and force $0 to be split totally.
  593.      */
  594.     if (fields_arr != NULL)
  595.         (void) get_field(HUGE - 1, 0);
  596.  
  597.     buf[0] = '\0';
  598.     default_FS = 0;
  599.     if (FS_regexp) {
  600.         refree(FS_regexp);
  601.         FS_regexp = NULL;
  602.     }
  603.     fs = force_string(FS_node->var_value);
  604.     if (fs->stlen > 1)
  605.         parse_field = re_parse_field;
  606.     else if (*RS == 0) {
  607.         parse_field = sc_parse_field;
  608.         if (fs->stlen == 1) {
  609.             if (fs->stptr[0] == ' ') {
  610.                 default_FS = 1;
  611.                 strcpy(buf, "[ \t\n]+");
  612.             } else if (fs->stptr[0] != '\n')
  613.                 sprintf(buf, "[%c\n]", fs->stptr[0]);
  614.         }
  615.     } else {
  616.         parse_field = def_parse_field;
  617.         if (fs->stptr[0] == ' ' && fs->stlen == 1)
  618.             default_FS = 1;
  619.         else if (fs->stptr[0] != ' ' && fs->stlen == 1) {
  620.             if (IGNORECASE == 0)
  621.                 parse_field = sc_parse_field;
  622.             else if (fs->stptr[0] == '\\')
  623.                 /* yet another special case */
  624.                 strcpy(buf, "[\\\\]");
  625.             else
  626.                 sprintf(buf, "[%c]", fs->stptr[0]);
  627.         }
  628.     }
  629.     if (buf[0]) {
  630.         FS_regexp = make_regexp(buf, strlen(buf), IGNORECASE, 1);
  631.         parse_field = re_parse_field;
  632.     } else if (parse_field == re_parse_field) {
  633.         FS_regexp = make_regexp(fs->stptr, fs->stlen, IGNORECASE, 1);
  634.     } else
  635.         FS_regexp = NULL;
  636.     resave_fs = 1;
  637. }
  638.  
  639. void
  640. set_RS()
  641. {
  642.     (void) force_string(RS_node->var_value);
  643.     RS = RS_node->var_value->stptr;
  644.     set_FS();
  645. }
  646.  
  647. void
  648. set_FIELDWIDTHS()
  649. {
  650.     register char *scan;
  651.     char *end;
  652.     register int i;
  653.     static int fw_alloc = 1;
  654.     static int warned = 0;
  655.     extern double strtod();
  656.  
  657.     if (do_lint && ! warned) {
  658.         warned = 1;
  659.         warning("use of FIELDWIDTHS is a gawk extension");
  660.     }
  661.     if (do_unix)    /* quick and dirty, does the trick */
  662.         return;
  663.  
  664.     /*
  665.      * If changing the way fields are split, obey least-suprise
  666.      * semantics, and force $0 to be split totally.
  667.      */
  668.     if (fields_arr != NULL)
  669.         (void) get_field(HUGE - 1, 0);
  670.  
  671.     parse_field = fw_parse_field;
  672.     scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
  673.     end = scan + 1;
  674.     if (FIELDWIDTHS == NULL)
  675.         emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  676.     FIELDWIDTHS[0] = 0;
  677.     for (i = 1; ; i++) {
  678.         if (i >= fw_alloc) {
  679.             fw_alloc *= 2;
  680.             erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  681.         }
  682.         FIELDWIDTHS[i] = (int) strtod(scan, &end);
  683.         if (end == scan)
  684.             break;
  685.         scan = end;
  686.     }
  687.     FIELDWIDTHS[i] = -1;
  688. }
  689.  
  690. void
  691. set_FS_if_not_FIELDWIDTHS()
  692. {
  693.     if (parse_field != fw_parse_field)
  694.         set_FS();
  695. }
  696.