home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Utilities / Programming / EnterAct 3.5 / hAWK project / AWK Source / FIELD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-22  |  13.2 KB  |  479 lines  |  [TEXT/TOPC]

  1. /*
  2.  * field.c - routines for dealing with fields and record parsing
  3.  */
  4.  
  5. /* Copyright © 1986, 1988, 1989 1991 the Free Software Foundation, Inc.
  6.  *         This file is part of GAWK, the GNU implementation of the
  7.  * AWK Progamming Language, modified for the Macintosh (also called hAWK).
  8.  *         GAWK is free software; you can redistribute or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 1, or any later version.
  11.  *         GAWK is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14.  * GNU General Public License for more details.
  15.  *         You should have received a copy of the GNU General Public License
  16.  * along with GAWK; see the file "COPYING hAWK". If not, write to
  17.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  * Modified for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
  19.  */
  20.  
  21. #include "AWK.H"
  22.  
  23. /* A generalised "carriage return" for the Mac version - its definition
  24. varies now and then, tracking down all the variations left as an exercise...*/
  25. #define CR '\n'
  26.  
  27. extern void assoc_clear(NODE *symbol);
  28. extern short a_get_three(NODE *tree, NODE **res1, NODE **res2, NODE **res3);
  29. extern char get_rs(void);
  30.  
  31. /*FIELD.C*/
  32. void init_fields(void);
  33. static void set_field(short num, char *str, short len, NODE *dummy);
  34. static void rebuild_record(void);
  35. void set_record(char *buf, short cnt);
  36. NODE **get_field(short num, short assign);
  37. static short parse_fields(short up_to, char **buf, short len, 
  38.     register char *fs, void (*set) (short, char *, short, NODE *), NODE *n);
  39. static short re_split(char *buf, short len, char *fs, 
  40.     struct re_registers *reregsp);
  41. NODE *do_split(NODE *tree);
  42. static char *get_fs(void);
  43. static void set_element(short num, char *s, short len, NODE *n);
  44.  
  45. char *line_buf = NULL;    /* holds current input line */
  46.  
  47. static char *parse_extent;    /* marks where to restart parse of record */
  48. static short parse_high_water=0;    /* field number that we have parsed so far */
  49. static char f_empty[1] /*= ""*/;
  50. static char *save_fs /*= " "*/;    /* save current value of FS when line is read,
  51.                  * to be used in deferred parsing
  52.                  */
  53.  
  54.  
  55. NODE **fields_arr;        /* array of pointers to the field nodes */
  56. NODE node0;            /* node for $0 which never gets free'd */
  57. short node0_valid = 1;        /* $(>0) has not been changed yet */
  58.  
  59. void init_fields()
  60. {
  61.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  62.     node0.type = Node_val;
  63.     node0.stref = 0;
  64.     node0.stptr = "";
  65.     node0.flags = (STR|PERM);    /* never free buf */
  66.     fields_arr[0] = &node0;
  67. }
  68.  
  69. /*
  70.  * Danger!  Must only be called for fields we know have just been blanked, or
  71.  * fields we know don't exist yet.  
  72.  */
  73. static short nf_high_water = 0;
  74. /*ARGSUSED*/
  75. static void set_field(short num, char *str, short len, NODE *dummy)
  76. /*NODE *dummy;     not used -- just to make interface same as set_element */
  77. {
  78.     NODE *n;
  79.     short t;
  80.     
  81.  
  82.     if (num > nf_high_water) {
  83.         erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
  84.         nf_high_water = num;
  85.     }
  86.     /* fill in fields that don't exist */
  87.     for (t = parse_high_water + 1; t < num; t++)
  88.         fields_arr[t] = Nnull_string;
  89.     n = make_string(str, len);
  90.     (void) force_number(n);
  91.     fields_arr[num] = n;
  92.     parse_high_water = num;
  93. }
  94.  
  95. /* Someone assigned a value to $(something).  Fix up $0 to be right */
  96. static void rebuild_record()
  97. {
  98.     register short tlen;
  99.     register NODE *tmp;
  100.     NODE *ofs;
  101.     char *ops;
  102.     register char *cops;
  103.     register NODE **ptr;
  104.     register short ofslen;
  105.  
  106.     tlen = 0;
  107.     ofs = force_string(OFS_node->var_value);
  108.     ofslen = ofs->stlen;
  109.     ptr = &fields_arr[parse_high_water];
  110.     while (ptr > &fields_arr[0]) {
  111.         tmp = force_string(*ptr);
  112.         tlen += tmp->stlen;
  113.         ptr--;
  114.     }
  115.     tlen += (parse_high_water - 1) * ofslen;
  116.     emalloc(ops, char *, tlen + 1, "fix_fields");
  117.     cops = ops;
  118.     ops[0] = '\0';
  119.     for (ptr = &fields_arr[1]; ptr <= &fields_arr[parse_high_water]; ptr++) {
  120.         tmp = *ptr;
  121.         if (tmp->stlen == 1)
  122.             *cops++ = tmp->stptr[0];
  123.         else if (tmp->stlen != 0) {
  124.             memcpy(cops, tmp->stptr, tmp->stlen);
  125.             cops += tmp->stlen;
  126.         }
  127.         if (ptr != &fields_arr[parse_high_water]) {
  128.             if (ofslen == 1)
  129.                 *cops++ = ofs->stptr[0];
  130.             else if (ofslen != 0) {
  131.                 memcpy(cops, ofs->stptr, ofslen);
  132.                 cops += ofslen;
  133.             }
  134.         }
  135.     }
  136.     tmp = make_string(ops, tlen);
  137.     free(ops);
  138.     deref = fields_arr[0];
  139.     do_deref();
  140.     fields_arr[0] = tmp;
  141. }
  142.  
  143. /*
  144.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  145.  * or to NF.  At that point, parse only as much as necessary.
  146.  */
  147. void set_record(char *buf, short cnt)
  148. {
  149.     register short i;
  150.  
  151.     assign_number(&NF_node->var_value, (AWKNUM)-1);
  152.     for (i = 1; i <= parse_high_water; i++) {
  153.         deref = fields_arr[i];
  154.         do_deref();
  155.     }
  156.     parse_high_water = 0;
  157.     node0_valid = 1;
  158.     if (buf == line_buf) {
  159.         deref = fields_arr[0];
  160.         do_deref();
  161.         save_fs = get_fs();
  162.         node0.type = Node_val;
  163.         node0.stptr = buf;
  164.         node0.stlen = cnt;
  165.         node0.stref = 1;
  166.         node0.flags = (STR|PERM);    /* never free buf */
  167.         fields_arr[0] = &node0;
  168.     }
  169. }
  170.  
  171. NODE **get_field(short num, short assign)
  172. /*short assign;     this field is on the LHS of an assign */
  173. {
  174.     short n;
  175.  
  176.     /*
  177.      * if requesting whole line but some other field has been altered,
  178.      * then the whole line must be rebuilt
  179.      */
  180.     if (num == 0 && (node0_valid == 0 || assign)) {
  181.         /* first, parse remainder of input record */
  182.         if (NF_node->var_value->numbr == -1) {
  183.             if (parse_high_water == 0)
  184.                 parse_extent = node0.stptr;
  185.             n = parse_fields(HUGE-1, &parse_extent,
  186.                     node0.stlen - (parse_extent - node0.stptr),
  187.                     save_fs, set_field, (NODE *)NULL);
  188.             assign_number(&NF_node->var_value, (AWKNUM)n);
  189.         }
  190.         if (node0_valid == 0)
  191.             rebuild_record();
  192.         return &fields_arr[0];
  193.     }
  194.     if (num > 0 && assign)
  195.         node0_valid = 0;
  196.     if (num <= parse_high_water)    /* we have already parsed this field */
  197.         return &fields_arr[num];
  198.     if (parse_high_water == 0 && num > 0)    /* starting at the beginning */
  199.         parse_extent = fields_arr[0]->stptr;
  200.     /*
  201.      * parse up to num fields, calling set_field() for each, and saving
  202.      * in parse_extent the point where the parse left off
  203.      */
  204.     n = parse_fields(num, &parse_extent,
  205.         fields_arr[0]->stlen - (short)(parse_extent-fields_arr[0]->stptr),
  206.         save_fs, set_field, (NODE *)NULL);
  207.     if (num == HUGE-1)
  208.         num = n;
  209.     if (n < num) {    /* requested field number beyond end of record;
  210.              * set_field will just extend the number of fields,
  211.              * with empty fields
  212.              */
  213.         set_field(num, f_empty, 0, (NODE *) NULL);
  214.         /*
  215.          * if this field is onthe LHS of an assignment, then we want to
  216.          * set NF to this value, below
  217.          */
  218.         if (assign)
  219.             n = num;
  220.     }
  221.     /*
  222.      * if we reached the end of the record, set NF to the number of fields
  223.      * so far.  Note that num might actually refer to a field that
  224.      * is beyond the end of the record, but we won't set NF to that value at
  225.      * this point, since this is only a reference to the field and NF
  226.      * only gets set if the field is assigned to -- in this case n has
  227.      * been set to num above
  228.      */
  229.     if (*parse_extent == '\0')
  230.         assign_number(&NF_node->var_value, (AWKNUM)n);
  231.  
  232.     return &fields_arr[num];
  233. }
  234.  
  235. /*
  236.  * this is called both from get_field() and from do_split()
  237.  */
  238. static short parse_fields(short up_to, char **buf, short len, 
  239.     register char *fs, void (*set) (short, char *, short, NODE *), NODE *n)
  240. /*short up_to;     parse only up to this field number */
  241. /*char **buf;     on input: string to parse; on output: point to start next */
  242. /*void (*set) ();     routine to set the value of the parsed field */
  243. {
  244.     char *s = *buf;
  245.     register char *field;
  246.     register char *scan;
  247.     register char *end = s + len;
  248.     short NF = parse_high_water;
  249.     char rs = get_rs();
  250.  
  251.  
  252.     if (up_to == HUGE)
  253.         NF = 0;
  254.     if (*fs && *(fs + 1) != '\0') {    /* fs is a regexp */
  255.         struct re_registers reregs;
  256.         
  257.         /* TEST ONLY 
  258.         SysBeep(2);
  259.         */
  260.         scan = s;
  261.         if (rs == 0 && STREQ(FS_node->var_value->stptr, " ")) {
  262.             while ((*scan == CR || *scan == ' ' || *scan == '\t')
  263.                 && scan < end)
  264.                 scan++;
  265.         }
  266.         s = scan;
  267.         while (scan < end
  268.             && re_split(scan, (short)(end - scan), fs, &reregs) != -1
  269.             && NF < up_to) {
  270.             if (reregs.end[0] == 0) {    /* null match */
  271.                 scan++;
  272.                 if (scan == end) {
  273.                     (*set)(++NF, s, (short)(scan - s), n);
  274.                     up_to = NF;
  275.                     break;
  276.                 }
  277.                 continue;
  278.             }
  279.             (*set)(++NF, s, (short)(scan - s) + reregs.start[0], n);
  280.             scan += reregs.end[0];
  281.             s = scan;
  282.         }
  283.         if (NF != up_to && scan <= end) {
  284.             if (!(rs == 0 && scan == end)) {
  285.                 (*set)(++NF, scan, (short)(end - scan), n);
  286.                 scan = end;
  287.             }
  288.         }
  289.         *buf = scan;
  290.         return (NF);
  291.     }
  292.     for (scan = s; scan < end && NF < up_to; scan++) {
  293.         /*
  294.          * special case:  fs is single space, strip leading
  295.          * whitespace 
  296.          */
  297.         if (*fs == ' ') {
  298.             while ((*scan == ' ' || *scan == '\t') && scan < end)
  299.                 scan++;
  300.             if (scan >= end)
  301.                 break;
  302.         }
  303.         field = scan;
  304.         if (*fs == ' ')
  305.             while (*scan != ' ' && *scan != '\t' && scan < end)
  306.                 scan++;
  307.         else {
  308.             while (*scan != *fs && scan < end)
  309.                 scan++;
  310.             if (rs && scan == end-1 && *scan == *fs) {
  311.                 (*set)(++NF, field, (short)(scan - field), n);
  312.                 /* Mac note - cast to short just above added for THINK C,
  313.                 what the heck it works. Getting real annoyed by now at
  314.                 THINK C's charming little eccentricities concerning
  315.                 conversion between different species of integer...*/
  316.                 field = scan;
  317.             }
  318.         }
  319.         (*set)(++NF, field, (short)(scan - field), n);
  320.         if (scan == end)
  321.             break;
  322.     }
  323.     *buf = scan;
  324.     return NF;
  325. }
  326.  
  327. typedef struct re_pattern_buffer RPAT;
  328. static RPAT *rp;
  329. static char *last_fs = NULL;
  330. static short re_split(char *buf, short len, char *fs, 
  331.     struct re_registers *reregsp)
  332. {
  333.     
  334.     
  335.  
  336.     if ((last_fs != NULL && !STREQ(fs, last_fs))
  337.         || (rp && /* ! strict && */ ((IGNORECASE_node->var_value->numbr != 0)
  338.              ^ (rp->translate != NULL))))
  339.     {
  340.         /* fs has changed or IGNORECASE has changed */
  341.         free(rp->buffer);
  342.         free(rp->fastmap);
  343.         free((char *) rp);
  344.         free(last_fs);
  345.         last_fs = NULL;
  346.     }
  347.     if (last_fs == NULL) {    /* first time */
  348.         emalloc(rp, RPAT *, sizeof(RPAT), "re_split");
  349.         memset((char *) rp, 0, sizeof(RPAT));
  350.         emalloc(rp->buffer, char *, 16, "re_split");
  351.         rp->allocated = 16;
  352.         emalloc(rp->fastmap, char *, 256, "re_split");
  353.         emalloc(last_fs, char *, strlen(fs) + 1, "re_split");
  354.         (void) strcpy(last_fs, fs);
  355.         if (/* ! strict && */ IGNORECASE_node->var_value->numbr != 0.0)
  356.             rp->translate = casetable;
  357.         else
  358.             rp->translate = NULL;
  359.         if (re_compile_pattern(fs, strlen(fs), rp) != NULL)
  360.             fatal("illegal regular expression for FS: `%s'", fs);
  361.     }
  362.     return re_search(rp, buf, len, 0, len, reregsp);
  363. }
  364.  
  365. NODE *do_split(NODE *tree)
  366. {
  367.     NODE *t1, *t2, *t3;
  368.     register char *splitc;
  369.     char *s;
  370.     NODE *n;
  371.  
  372.     if (a_get_three(tree, &t1, &t2, &t3) < 3)
  373.         splitc = get_fs();
  374.     else
  375.         splitc = force_string(t3)->stptr;
  376.  
  377.     n = t2;
  378.     if (t2->type == Node_param_list)
  379.         n = stack_ptr[t2->param_cnt];
  380.     if (n->type != Node_var && n->type != Node_var_array)
  381.         fatal("second argument of split is not a variable");
  382.     assoc_clear(n);
  383.  
  384.     tree = force_string(t1);
  385.  
  386.     s = tree->stptr;
  387.     return tmp_number((AWKNUM)
  388.         parse_fields(HUGE, &s, tree->stlen, splitc, set_element, n));
  389. }
  390.  
  391. static char buf[10];
  392. static char *get_fs()
  393. {
  394.     register NODE *tmp;
  395.     
  396.  
  397.     tmp = force_string(FS_node->var_value);
  398.     if (get_rs() == 0) {
  399.         if (tmp->stlen == 1) {
  400.             if (tmp->stptr[0] == ' ')
  401.                 (void) strcpy(buf, "[     \n]+");
  402.             else
  403.                 sprintf(buf, "[%c\n]", tmp->stptr[0]);
  404.         } else if (tmp->stlen == 0) {
  405.             buf[0] = CR;
  406.             buf[1] = '\0';
  407.         } else
  408.             return tmp->stptr;
  409.         return buf;
  410.     }
  411.     return tmp->stptr;
  412. }
  413.  
  414. static void set_element(short num, char *s, short len, NODE *n)
  415. {
  416.     *assoc_lookup(n, tmp_number((AWKNUM) (num))) = make_string(s, len);
  417. }
  418.  
  419. /* Some inits; hAWK is set up as a CODE resource, requiring that
  420. some initializations dealing with addresses be done rather awkwardly
  421. due to this referencing globals off a4 jazz. I may not have noted this
  422. elsewhere, but the inits for hAWK are sufficient that hAWK could be
  423. recast as a standalone application, just call all the init functions
  424. before each run as done at the top of AWKmain(). Just a thought. */
  425.  
  426. extern void NullOut(char *str, long nBytes);
  427.  
  428. void InitField(void);
  429.  
  430. void InitField()
  431.     {
  432.     line_buf = NULL;    /* holds current input line */
  433.     
  434.     parse_extent = NULL;    /* marks where to restart parse of record */
  435.     parse_high_water=0;    /* field number that we have parsed so far */
  436.     f_empty[0] = 0;
  437.     save_fs = " ";    /* save current value of FS when line is read,
  438.                      * to be used in deferred parsing
  439.                      */
  440.     fields_arr = NULL;        /* array of pointers to the field nodes */
  441.     NullOut((Ptr)(&node0), sizeof(NODE));
  442.     node0_valid = 1;        /* $(>0) has not been changed yet */
  443.     /* in set_field: */
  444.         nf_high_water = 0;
  445.     /* in re_split */
  446.         rp = NULL;
  447.         last_fs = NULL;
  448.     /* in get_fs: */
  449.     NullOut((Ptr)buf, sizeof(buf));
  450.     }
  451.  
  452. void SaveField(void);
  453. void RestoreField(void);
  454. void SaveField()
  455.     {
  456.     hs->line_buf = line_buf;
  457.     hs->parse_extent = parse_extent;
  458.     hs->parse_high_water = parse_high_water;
  459.     hs->save_fs = save_fs;
  460.     hs->node0 = node0;
  461.     hs->nf_high_water = nf_high_water;
  462.     hs->rp = (struct re_pattern_buffer*)rp;
  463.     hs->last_fs = last_fs;
  464.     BlockMove((Ptr)buf, (Ptr)(hs->buf), sizeof(buf));
  465.     }
  466.  
  467. void RestoreField()
  468.     {
  469.     line_buf = hs->line_buf;
  470.     parse_extent = hs->parse_extent;
  471.     parse_high_water = hs->parse_high_water;
  472.     save_fs = hs->save_fs;
  473.     node0 = hs->node0;
  474.     nf_high_water = hs->nf_high_water;
  475.     rp = (RPAT *)(hs->rp);
  476.     last_fs = hs->last_fs;
  477.     BlockMove((Ptr)(hs->buf), (Ptr)buf, sizeof(buf));
  478.     }
  479.