home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / TOP / USR / SRC / gawk2.0.t.Z / gawk2.0.t / awk7.c < prev    next >
Text File  |  1988-12-31  |  13KB  |  549 lines

  1. /*
  2.  * gawk - routines for dealing with record input and fields
  3.  */
  4.  
  5. /*
  6.  * GAWK is distributed in the hope that it will be useful, but WITHOUT ANY
  7.  * WARRANTY.  No author or distributor accepts responsibility to anyone for
  8.  * the consequences of using it or for whether it serves any particular
  9.  * purpose or works at all, unless he says so in writing. Refer to the GAWK
  10.  * General Public License for full details. 
  11.  *
  12.  * Everyone is granted permission to copy, modify and redistribute GAWK, but
  13.  * only under the conditions described in the GAWK General Public License.  A
  14.  * copy of this license is supposed to have been given to you along with GAWK
  15.  * so you can know your rights and responsibilities.  It should be in a file
  16.  * named COPYING.  Among other things, the copyright notice and this notice
  17.  * must be preserved on all copies. 
  18.  *
  19.  * In other words, go ahead and share GAWK, but don't try to stop anyone else
  20.  * from sharing it farther.  Help stamp out software hoarding! 
  21.  */
  22.  
  23. #include "awk.h"
  24.  
  25. static int getline_redirect = 0;/* "getline <file" being executed */
  26. static char *line_buf = NULL;    /* holds current input line */
  27. static int line_alloc = 0;    /* current allocation for line_buf */
  28.  
  29. int field_num;            /* save number of field in get_lhs */
  30. char *field_begin;
  31. NODE **fields_arr;        /* array of pointers to the field nodes */
  32. NODE node0;            /* node for $0 which never gets free'd */
  33. int node0_valid = 1;        /* $(>0) has not been changed yet */
  34. char f_empty[] = "";
  35. int parse_high_water = 0;    /* field number that we have parsed so far */
  36. char *parse_extent;        /* marks where to restart parse of record */
  37. char *save_fs = " ";        /* save current value of FS when line is read,
  38.                  * to be used in deferred parsing
  39.                  */
  40. static get_a_record();
  41.  
  42. init_fields()
  43. {
  44.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  45.     node0.type = Node_val;
  46.     node0.stref = 0;
  47.     node0.flags = (STR|PERM);    /* never free buf */
  48.     fields_arr[0] = &node0;
  49. }
  50.  
  51. /*
  52.  * Danger!  Must only be called for fields we know have just been blanked, or
  53.  * fields we know don't exist yet.  
  54.  */
  55. set_field(num, str, len, dummy)
  56. int num;
  57. char *str;
  58. int len;
  59. NODE *dummy;    /* not used -- just to make interface same as set_element */
  60. {
  61.     NODE *n;
  62.     int t;
  63.  
  64.     erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
  65.     /* fill in fields that don't exist */
  66.     for (t = parse_high_water + 1; t < num; t++)
  67.         fields_arr[t] = Nnull_string;
  68.     n = make_string(str, len);
  69.     fields_arr[num] = n;
  70.     parse_high_water = num;
  71. }
  72.  
  73. /* Someone assigned a value to $(something).  Fix up $0 to be right */
  74. rebuild_record()
  75. {
  76.     register int tlen;
  77.     register NODE *tmp;
  78.     NODE *ofs;
  79.     char *ops;
  80.     register char *cops;
  81.     register NODE **ptr, **maxp;
  82.     extern NODE *OFS_node;
  83.  
  84.     maxp = 0;
  85.     tlen = 0;
  86.     ofs = force_string(*get_lhs(OFS_node));
  87.     deref = 0;
  88.     ptr = &fields_arr[parse_high_water];
  89.     while (ptr > &fields_arr[0]) {
  90.         tmp = force_string(*ptr);
  91.         tlen += tmp->stlen;
  92.         if (tmp->stlen && !maxp)
  93.             maxp = ptr;
  94.         ptr--;
  95.     }
  96.     tlen += ((maxp - fields_arr) - 1) * ofs->stlen;
  97.     emalloc(ops, char *, tlen + 1, "fix_fields");
  98.     cops = ops;
  99.     for (ptr = &fields_arr[1]; ptr <= maxp; ptr++) {
  100.         tmp = force_string(*ptr);
  101.         bcopy(tmp->stptr, cops, tmp->stlen);
  102.         cops += tmp->stlen;
  103.         if (ptr != maxp) {
  104.             bcopy(ofs->stptr, cops, ofs->stlen);
  105.             cops += ofs->stlen;
  106.         }
  107.     }
  108.     tmp = make_string(ops, tlen);
  109.     deref = fields_arr[0];
  110.     do_deref();
  111.     fields_arr[0] = tmp;
  112. }
  113.  
  114.  
  115. /*
  116.  * This reads in a record from the input file
  117.  */
  118. int
  119. inrec()
  120. {
  121.     int cnt;
  122.     int retval = 0;
  123.  
  124.     cnt = get_a_record(&line_buf, &line_alloc);
  125.     if (cnt == EOF) {
  126.         cnt = 0;
  127.         retval = 1;
  128.     } else {
  129.         if (!getline_redirect) {
  130.             assign_number(&(NR_node->var_value),
  131.                 NR_node->var_value->numbr + 1.0);
  132.             assign_number(&(FNR_node->var_value),
  133.                 FNR_node->var_value->numbr + 1.0);
  134.         }
  135.     }
  136.     set_record(line_buf, cnt);
  137.  
  138.     return retval;
  139. }
  140.  
  141. /*
  142.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  143.  * or to NF.  At that point, parse only as much as necessary.
  144.  */
  145. set_record(buf, cnt)
  146. char *buf;
  147. int cnt;
  148. {
  149.     char *get_fs();
  150.  
  151.     assign_number(&(NF_node->var_value), (AWKNUM) -1);
  152.     parse_high_water = 0;
  153.     node0_valid = 1;
  154.     if (buf == line_buf) {
  155.         deref = fields_arr[0];
  156.         do_deref();
  157.         save_fs = get_fs();
  158.         node0.type = Node_val;
  159.         node0.stptr = buf;
  160.         node0.stlen = cnt;
  161.         node0.stref = 1;
  162.         node0.flags = (STR|PERM);    /* never free buf */
  163.         fields_arr[0] = &node0;
  164.     }
  165. }
  166.  
  167. NODE **
  168. get_field(num)
  169. int num;
  170. {
  171.     int n;
  172.  
  173.     /*
  174.      * if requesting whole line but some other field has been altered,
  175.      * then the whole line must be rebuilt
  176.      */
  177.     if (num == 0 && node0_valid == 0) {
  178.         /* first, parse remainder of input record */
  179.         (void) parse_fields(HUGE-1, &parse_extent,
  180.             fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
  181.             save_fs, set_field, (NODE *)NULL);
  182.         rebuild_record();
  183.         parse_high_water = 0;
  184.         return &fields_arr[0];
  185.     }
  186.     if (num <= parse_high_water)    /* we have already parsed this field */
  187.         return &fields_arr[num];
  188.     if (parse_high_water == 0 && num > 0)    /* starting at the beginning */
  189.         parse_extent = fields_arr[0]->stptr;
  190.     /*
  191.      * parse up to num fields, calling set_field() for each, and saving
  192.      * in parse_extent the point where the parse left off
  193.      */
  194.     n = parse_fields(num, &parse_extent,
  195.         fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
  196.         save_fs, set_field, (NODE *)NULL);
  197.     if (num == HUGE-1)
  198.         num = n;
  199.     if (n < num)    /* requested field number beyond end of record;
  200.              * set_field will just extend the number of fields,
  201.              * with empty fields
  202.              */
  203.         set_field(num, f_empty, 0, (NODE *) NULL);
  204.     /*
  205.      * if we reached the end of the record, set NF to the number of fields
  206.      * actually parsed.  Note that num might actually refer to a field that
  207.      * is beyond the end of the record, but we won't set NF to that value at
  208.      * this point, since this may only be a reference to the field and NF
  209.      * only gets set if the field is assigned to
  210.      */
  211.     if (*parse_extent == '\0')
  212.         assign_number(&(NF_node->var_value), (AWKNUM) n);
  213.  
  214.     return &fields_arr[num];
  215. }
  216.  
  217. /*
  218.  * this is called both from get_field() and from do_split()
  219.  */
  220. int
  221. parse_fields(up_to, buf, len, fs, set, n)
  222. int up_to;    /* parse only up to this field number */
  223. char **buf;    /* on input: string to parse; on output: point to start next */
  224. int len;
  225. char *fs;
  226. int (*set) ();    /* routine to set the value of the parsed field */
  227. NODE *n;
  228. {
  229.     char *s = *buf;
  230.     char *field;
  231.     int field_len;
  232.     char *scan;
  233.     char *end = s + len;
  234.     int NF = parse_high_water;
  235.  
  236.     if (up_to == HUGE)
  237.         NF = 0;
  238.     if (*fs && *(fs + 1) != '\0') {    /* fs is a regexp */
  239.         struct re_registers reregs;
  240.  
  241.         scan = s;
  242.         while (re_split(scan, end - scan, fs, &reregs) != -1 &&
  243.             NF < up_to) {
  244.             (*set)(++NF, scan, reregs.start[0], n);
  245.             scan += reregs.end[0];
  246.         }
  247.         if (NF != up_to && scan <= end) {
  248.             (*set)(++NF, scan, end - scan, n);
  249.             scan = end;
  250.         }
  251.         *buf = scan;
  252.         return (NF);
  253.     }
  254.     for (scan = s; scan < end && NF < up_to; scan++) {
  255.         /*
  256.          * special case:  fs is single space, strip leading
  257.          * whitespace 
  258.          */
  259.         if (*fs == ' ') {
  260.             while ((*scan == ' ' || *scan == '\t') && scan < end)
  261.                 scan++;
  262.             if (scan >= end)
  263.                 break;
  264.         }
  265.         field_len = 0;
  266.         field = scan;
  267.         if (*fs == ' ')
  268.             while (*scan != ' ' && *scan != '\t' && scan < end) {
  269.                 scan++;
  270.                 field_len++;
  271.             }
  272.         else {
  273.             while (*scan != *fs && scan < end) {
  274.                 scan++;
  275.                 field_len++;
  276.             }
  277.             if (scan == end-1 && *scan == *fs) {
  278.                 (*set)(++NF, field, field_len, n);
  279.                 field = scan;
  280.                 field_len = 0;
  281.             }
  282.         }
  283.         (*set)(++NF, field, field_len, n);
  284.         if (scan == end)
  285.             break;
  286.     }
  287.     *buf = scan;
  288.     return NF;
  289. }
  290.  
  291. int
  292. re_split(buf, len, fs, reregs)
  293. char *buf, *fs;
  294. int len;
  295. struct re_registers *reregs;
  296. {
  297.     typedef struct re_pattern_buffer RPAT;
  298.     static RPAT *rp;
  299.     static char *last_fs = NULL;
  300.  
  301.     if (last_fs != NULL && strcmp(fs, last_fs) != 0) {    /* fs has changed */
  302.         free(rp->buffer);
  303.         free(rp->fastmap);
  304.         free((char *) rp);
  305.         free(last_fs);
  306.         last_fs = NULL;
  307.     }
  308.     if (last_fs == NULL) {    /* first time */
  309.         emalloc(rp, RPAT *, sizeof(RPAT), "re_split");
  310.         bzero((char *) rp, sizeof(RPAT));
  311.         emalloc(rp->buffer, char *, 8, "re_split");
  312.         rp->allocated = 8;
  313.         emalloc(rp->fastmap, char *, 256, "re_split");
  314.         emalloc(last_fs, char *, strlen(fs) + 1, "re_split");
  315.         (void) strcpy(last_fs, fs);
  316.         if (re_compile_pattern(fs, strlen(fs), rp) != NULL)
  317.             fatal("illegal regular expression for FS: `%s'", fs);
  318.     }
  319.     return re_search(rp, buf, len, 0, len, reregs);
  320. }
  321.  
  322. static int                /* count of chars read or EOF */
  323. get_a_record(bp, sizep)
  324. char **bp;            /* *bp points to beginning of line on return */
  325. int *sizep;            /* *sizep is current allocation of *bp */
  326. {
  327.     register char *buf;    /* buffer; realloced if necessary */
  328.     int bsz;        /* current buffer size */
  329.     register char *cur;    /* current position in buffer */
  330.     register char *buf_end;    /* end of buffer */
  331.     register int rs;    /* rs is the current record separator */
  332.     register int c;
  333.     extern FILE *input_file;
  334.  
  335.     bsz = *sizep;
  336.     buf = *bp;
  337.     if (!buf) {
  338.         emalloc(buf, char *, 128, "get_a_record");
  339.         bsz = 128;
  340.     }
  341.     rs = get_rs();
  342.     buf_end = buf + bsz;
  343.     cur = buf;
  344.     while ((c = getc(input_file)) != EOF) {
  345.         if (rs == 0 && c == '\n' && cur != buf && cur[-1] == '\n') {
  346.             cur--;
  347.             break;
  348.         }
  349.         else if (c == rs)
  350.             break;
  351.         *cur++ = c;
  352.         if (cur == buf_end) {
  353.             erealloc(buf, char *, bsz * 2, "get_a_record");
  354.             cur = buf + bsz;
  355.             bsz *= 2;
  356.             buf_end = buf + bsz;
  357.         }
  358.     }
  359.     if (rs == 0 && c == EOF && cur != buf && cur[-1] == '\n')
  360.         cur--;
  361.     *cur = '\0';
  362.     *bp = buf;
  363.     *sizep = bsz;
  364.     if (c == EOF && cur == buf)
  365.         return EOF;
  366.     return cur - buf;
  367. }
  368.  
  369. NODE *
  370. do_getline(tree)
  371. NODE *tree;
  372. {
  373.     FILE *save_fp;
  374.     FILE *redirect();
  375.     int cnt;
  376.     NODE **lhs;
  377.     extern NODE **get_lhs();
  378.     extern FILE *input_file;
  379.     extern FILE *nextfile();
  380.  
  381.     if (tree->rnode == NULL && (input_file == NULL || feof(input_file))) {
  382.         input_file = nextfile();
  383.         if (input_file == NULL)
  384.             return tmp_number((AWKNUM) 0.0);
  385.     }
  386.     save_fp = input_file;
  387.     if (tree->rnode != NULL) {    /* with redirection */
  388.         input_file = redirect(tree->rnode);
  389.         getline_redirect++;
  390.     }
  391.     if (tree->lnode == NULL) {    /* read in $0 */
  392.         if (inrec() != 0) {
  393.             input_file = save_fp;
  394.             getline_redirect = 0;
  395.             return tmp_number((AWKNUM) 0.0);
  396.         }
  397.     } else {            /* read in a named variable */
  398.         char *s = NULL;
  399.         int n = 0;
  400.  
  401.         lhs = get_lhs(tree->lnode);
  402.         cnt = get_a_record(&s, &n);
  403.         if (!getline_redirect) {
  404.             assign_number(&(NR_node->var_value),
  405.                 NR_node->var_value->numbr + 1.0);
  406.             assign_number(&(FNR_node->var_value),
  407.                 FNR_node->var_value->numbr + 1.0);
  408.         }
  409.         if (cnt == EOF) {
  410.             input_file = save_fp;
  411.             getline_redirect = 0;
  412.             free(s);
  413.             return tmp_number((AWKNUM) 0.0);
  414.         }
  415.         *lhs = make_string(s, strlen(s));
  416.         free(s);
  417.         /* we may have to regenerate $0 here! */
  418.         if (field_num == 0)
  419.             set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
  420.         else if (field_num > 0) {
  421.             node0_valid = 0;
  422.             if (NF_node->var_value->numbr == -1 &&
  423.                 field_num > NF_node->var_value->numbr)
  424.                 assign_number(&(NF_node->var_value),
  425.                     (AWKNUM) field_num);
  426.         }
  427.         field_num = -1;
  428.         do_deref();
  429.     }
  430.     getline_redirect = 0;
  431.     input_file = save_fp;
  432.     return tmp_number((AWKNUM) 1.0);
  433. }
  434.  
  435. /*
  436.  * We can't dereference a variable until after we've given it its new value.
  437.  * This variable points to the value we have to free up 
  438.  */
  439. NODE *deref;
  440.  
  441. /*
  442.  * This returns a POINTER to a node pointer. get_lhs(ptr) is the current
  443.  * value of the var, or where to store the var's new value 
  444.  */
  445.  
  446. NODE **
  447. get_lhs(ptr)
  448. NODE *ptr;
  449. {
  450.     register NODE **aptr;
  451.     NODE *n;
  452.     NODE **assoc_lookup();
  453.     extern NODE *concat_exp();
  454.  
  455. #ifdef DEBUG
  456.     if (ptr == NULL)
  457.         cant_happen();
  458. #endif
  459.     deref = NULL;
  460.     field_num = -1;
  461.     switch (ptr->type) {
  462.     case Node_var:
  463.     case Node_var_array:
  464.         if (ptr == NF_node && (int) NF_node->var_value->numbr == -1)
  465.             (void) get_field(HUGE-1); /* parse entire record */
  466.         deref = ptr->var_value;
  467. #ifdef DEBUG
  468.         if (deref->type != Node_val)
  469.             cant_happen();
  470.         if (deref->flags == 0)
  471.             cant_happen();
  472. #endif
  473.         return &(ptr->var_value);
  474.  
  475.     case Node_param_list:
  476.         n = stack_ptr[ptr->param_cnt];
  477. #ifdef DEBUG
  478.         deref = n->var_value;
  479.         if (deref->type != Node_val)
  480.             cant_happen();
  481.         if (deref->flags == 0)
  482.             cant_happen();
  483.         deref = 0;
  484. #endif
  485.         return &(n->var_value);
  486.  
  487.     case Node_field_spec:
  488.         field_num = (int) force_number(tree_eval(ptr->lnode));
  489.         if (field_num < 0)
  490.             fatal("attempt to access field %d", field_num);
  491.         aptr = get_field(field_num);
  492.         deref = *aptr;
  493.         return aptr;
  494.  
  495.     case Node_subscript:
  496.         n = ptr->lnode;
  497.         if (n->type == Node_param_list)
  498.             n = stack_ptr[n->param_cnt];
  499.         aptr = assoc_lookup(n, concat_exp(ptr->rnode));
  500.         deref = *aptr;
  501. #ifdef DEBUG
  502.         if (deref->type != Node_val)
  503.             cant_happen();
  504.         if (deref->flags == 0)
  505.             cant_happen();
  506. #endif
  507.         return aptr;
  508.     case Node_func:
  509.         fatal ("`%s' is a function, assignment is not allowed",
  510.             ptr->lnode->param);
  511.     }
  512.     return 0;
  513. }
  514.  
  515. do_deref()
  516. {
  517.     if (deref == NULL)
  518.         return;
  519.     if (deref == Nnull_string) {
  520.         deref = 0;
  521.         return;
  522.     }
  523. #ifdef DEBUG
  524.     if (deref->flags == 0)
  525.         cant_happen();
  526. #endif
  527.     if (deref->flags & MALLOC) {
  528. #ifdef DEBUG
  529.         if (deref->flags & PERM)
  530.             cant_happen();
  531.         if (deref->flags & TEMP)
  532.             cant_happen();
  533. #endif
  534.         if (deref->flags & STR) {
  535.             if (deref->stref > 0 && deref->stref != 255)
  536.                 deref->stref--;
  537.             if (deref->stref > 0) {
  538.                 deref = 0;
  539.                 return;
  540.             }
  541.             free((char *)(deref->stptr));
  542.         }
  543.         deref->flags = 0;
  544.         deref->type = Node_illegal;
  545.         free((char *)deref);
  546.     }
  547.     deref = 0;
  548. }
  549.