home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 6 / FreshFish_September1994.bin / bbs / gnu / gawk-2.15.5-src.lha / GNU / src / amiga / gawk-2.15.5 / field.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-18  |  16.1 KB  |  679 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 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.     /* 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 long
  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;) {
  367.         field = scan;
  368.         while (*scan != fschar)
  369.             scan++;
  370.         (*set)(++nf, field, (int)(scan - field), n);
  371.         if (scan == end)
  372.             break;
  373.         scan++;
  374.         if (scan == end) {    /* FS at end of record */
  375.             (*set)(++nf, field, 0, n);
  376.             break;
  377.         }
  378.     }
  379.  
  380.     /* everything done, restore original char at *end */
  381.     *end = sav;
  382.  
  383.     *buf = scan;
  384.     return nf;
  385. }
  386.  
  387. /*
  388.  * this is called both from get_field() and from do_split()
  389.  * via (*parse_field)().  This variation is for fields are fixed widths.
  390.  */
  391. static long
  392. fw_parse_field(up_to, buf, len, fs, rp, set, n)
  393. int up_to;    /* parse only up to this field number */
  394. char **buf;    /* on input: string to parse; on output: point to start next */
  395. int len;
  396. NODE *fs;
  397. Regexp *rp;
  398. Setfunc set;    /* routine to set the value of the parsed field */
  399. NODE *n;
  400. {
  401.     register char *scan = *buf;
  402.     register long nf = parse_high_water;
  403.     register char *end = scan + len;
  404.  
  405.     if (up_to == HUGE)
  406.         nf = 0;
  407.     if (len == 0)
  408.         return nf;
  409.     for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) {
  410.         if (len > end - scan)
  411.             len = end - scan;
  412.         (*set)(++nf, scan, len, n);
  413.         scan += len;
  414.     }
  415.     if (len == -1)
  416.         *buf = end;
  417.     else
  418.         *buf = scan;
  419.     return nf;
  420. }
  421.  
  422. NODE **
  423. get_field(requested, assign)
  424. register int requested;
  425. Func_ptr *assign;    /* this field is on the LHS of an assign */
  426. {
  427.     /*
  428.      * if requesting whole line but some other field has been altered,
  429.      * then the whole line must be rebuilt
  430.      */
  431.     if (requested == 0) {
  432.         if (!field0_valid) {
  433.             /* first, parse remainder of input record */
  434.             if (NF == -1) {
  435.                 NF = (*parse_field)(HUGE-1, &parse_extent,
  436.                         fields_arr[0]->stlen -
  437.                     (parse_extent - fields_arr[0]->stptr),
  438.                         save_FS, FS_regexp, set_field,
  439.                     (NODE *)NULL);
  440.                 parse_high_water = NF;
  441.             }
  442.             rebuild_record();
  443.         }
  444.         if (assign)
  445.             *assign = reset_record;
  446.         return &fields_arr[0];
  447.     }
  448.  
  449.     /* assert(requested > 0); */
  450.  
  451.     if (assign)
  452.         field0_valid = 0;        /* $0 needs reconstruction */
  453.  
  454.     if (requested <= parse_high_water)    /* already parsed this field */
  455.         return &fields_arr[requested];
  456.  
  457.     if (NF == -1) {    /* have not yet parsed to end of record */
  458.         /*
  459.          * parse up to requested fields, calling set_field() for each,
  460.          * saving in parse_extent the point where the parse left off
  461.          */
  462.         if (parse_high_water == 0)    /* starting at the beginning */
  463.             parse_extent = fields_arr[0]->stptr;
  464.         parse_high_water = (*parse_field)(requested, &parse_extent,
  465.              fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
  466.              save_FS, FS_regexp, set_field, (NODE *)NULL);
  467.  
  468.         /*
  469.          * if we reached the end of the record, set NF to the number of 
  470.          * fields so far.  Note that requested might actually refer to
  471.          * a field that is beyond the end of the record, but we won't
  472.          * set NF to that value at this point, since this is only a
  473.          * reference to the field and NF only gets set if the field
  474.          * is assigned to -- this case is handled below
  475.          */
  476.         if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen)
  477.             NF = parse_high_water;
  478.         if (requested == HUGE-1)    /* HUGE-1 means set NF */
  479.             requested = parse_high_water;
  480.     }
  481.     if (parse_high_water < requested) { /* requested beyond end of record */
  482.         if (assign) {    /* expand record */
  483.             register int i;
  484.  
  485.             if (requested > nf_high_water)
  486.                 grow_fields_arr(requested);
  487.  
  488.             /* fill in fields that don't exist */
  489.             for (i = parse_high_water + 1; i <= requested; i++)
  490.                 fields_arr[i] = Nnull_string;
  491.  
  492.             NF = requested;
  493.             parse_high_water = requested;
  494.         } else
  495.             return &Nnull_string;
  496.     }
  497.  
  498.     return &fields_arr[requested];
  499. }
  500.  
  501. static void
  502. set_element(num, s, len, n)
  503. int num;
  504. char *s;
  505. int len;
  506. NODE *n;
  507. {
  508.     register NODE *it;
  509.  
  510.     it = make_string(s, len);
  511.     it->flags |= MAYBE_NUM;
  512.     *assoc_lookup(n, tmp_number((AWKNUM) (num))) = it;
  513. }
  514.  
  515. NODE *
  516. do_split(tree)
  517. NODE *tree;
  518. {
  519.     NODE *t1, *t2, *t3, *tmp;
  520.     NODE *fs;
  521.     char *s;
  522.     long (*parseit)P((int, char **, int, NODE *,
  523.              Regexp *, Setfunc, NODE *));
  524.     Regexp *rp = NULL;
  525.  
  526.  
  527.     /*
  528.      * do dupnode(), to avoid problems like
  529.      *    x = split(a[1], a, "blah")
  530.      * since we assoc_clear the array. gack.
  531.      * this also gives up complete call by value semantics.
  532.      */
  533.     tmp = tree_eval(tree->lnode);
  534.     t1 = dupnode(tmp);
  535.     free_temp(tmp);
  536.  
  537.     t2 = tree->rnode->lnode;
  538.     t3 = tree->rnode->rnode->lnode;
  539.  
  540.     (void) force_string(t1);
  541.  
  542.     if (t2->type == Node_param_list)
  543.         t2 = stack_ptr[t2->param_cnt];
  544.     if (t2->type != Node_var && t2->type != Node_var_array)
  545.         fatal("second argument of split is not a variable");
  546.     assoc_clear(t2);
  547.  
  548.     if (t3->re_flags & FS_DFLT) {
  549.         parseit = parse_field;
  550.         fs = force_string(FS_node->var_value);
  551.         rp = FS_regexp;
  552.     } else {
  553.         tmp = force_string(tree_eval(t3->re_exp));
  554.         if (tmp->stlen == 1) {
  555.             if (tmp->stptr[0] == ' ')
  556.                 parseit = def_parse_field;
  557.             else
  558.                 parseit = sc_parse_field;
  559.         } else {
  560.             parseit = re_parse_field;
  561.             rp = re_update(t3);
  562.         }
  563.         fs = tmp;
  564.     }
  565.  
  566.     s = t1->stptr;
  567.     tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int)t1->stlen,
  568.                          fs, rp, set_element, t2));
  569.     unref(t1);
  570.     free_temp(t3);
  571.     return tmp;
  572. }
  573.  
  574. void
  575. set_FS()
  576. {
  577.     char buf[10];
  578.     NODE *fs;
  579.  
  580.     /*
  581.      * If changing the way fields are split, obey least-suprise
  582.      * semantics, and force $0 to be split totally.
  583.      */
  584.     if (fields_arr != NULL)
  585.         (void) get_field(HUGE - 1, 0);
  586.  
  587.     buf[0] = '\0';
  588.     default_FS = 0;
  589.     if (FS_regexp) {
  590.         refree(FS_regexp);
  591.         FS_regexp = NULL;
  592.     }
  593.     fs = force_string(FS_node->var_value);
  594.     if (fs->stlen > 1)
  595.         parse_field = re_parse_field;
  596.     else if (*RS == 0) {
  597.         parse_field = sc_parse_field;
  598.         if (fs->stlen == 1) {
  599.             if (fs->stptr[0] == ' ') {
  600.                 default_FS = 1;
  601.                 strcpy(buf, "[ \t\n]+");
  602.             } else if (fs->stptr[0] != '\n')
  603.                 sprintf(buf, "[%c\n]", fs->stptr[0]);
  604.         }
  605.     } else {
  606.         parse_field = def_parse_field;
  607.         if (fs->stptr[0] == ' ' && fs->stlen == 1)
  608.             default_FS = 1;
  609.         else if (fs->stptr[0] != ' ' && fs->stlen == 1) {
  610.             if (IGNORECASE == 0)
  611.                 parse_field = sc_parse_field;
  612.             else if (fs->stptr[0] == '\\')
  613.                 /* yet another special case */
  614.                 strcpy(buf, "[\\\\]");
  615.             else
  616.                 sprintf(buf, "[%c]", fs->stptr[0]);
  617.         }
  618.     }
  619.     if (buf[0]) {
  620.         FS_regexp = make_regexp(buf, strlen(buf), IGNORECASE, 1);
  621.         parse_field = re_parse_field;
  622.     } else if (parse_field == re_parse_field) {
  623.         FS_regexp = make_regexp(fs->stptr, fs->stlen, IGNORECASE, 1);
  624.     } else
  625.         FS_regexp = NULL;
  626.     resave_fs = 1;
  627. }
  628.  
  629. void
  630. set_RS()
  631. {
  632.     (void) force_string(RS_node->var_value);
  633.     RS = RS_node->var_value->stptr;
  634.     set_FS();
  635. }
  636.  
  637. void
  638. set_FIELDWIDTHS()
  639. {
  640.     register char *scan;
  641.     char *end;
  642.     register int i;
  643.     static int fw_alloc = 1;
  644.     static int warned = 0;
  645.     extern double strtod();
  646.  
  647.     if (do_lint && ! warned) {
  648.         warned = 1;
  649.         warning("use of FIELDWIDTHS is a gawk extension");
  650.     }
  651.     if (do_unix)    /* quick and dirty, does the trick */
  652.         return;
  653.  
  654.     /*
  655.      * If changing the way fields are split, obey least-suprise
  656.      * semantics, and force $0 to be split totally.
  657.      */
  658.     if (fields_arr != NULL)
  659.         (void) get_field(HUGE - 1, 0);
  660.  
  661.     parse_field = fw_parse_field;
  662.     scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
  663.     end = scan + 1;
  664.     if (FIELDWIDTHS == NULL)
  665.         emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  666.     FIELDWIDTHS[0] = 0;
  667.     for (i = 1; ; i++) {
  668.         if (i >= fw_alloc) {
  669.             fw_alloc *= 2;
  670.             erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  671.         }
  672.         FIELDWIDTHS[i] = (int) strtod(scan, &end);
  673.         if (end == scan)
  674.             break;
  675.         scan = end;
  676.     }
  677.     FIELDWIDTHS[i] = -1;
  678. }
  679.