home *** CD-ROM | disk | FTP | other *** search
/ The UNIX CD Bookshelf / OREILLY_TUCB_UNIX_CD.iso / upt / examples / SOURCES / GLIMPSE / GLI40SRC.Z / GLI40SRC / glimpse-4.0.src / split.c < prev   
Encoding:
C/C++ Source or Header  |  1996-11-22  |  19.8 KB  |  607 lines

  1. /* Copyright (c) 1994 Burra Gopal, Udi Manber.  All Rights Reserved. */
  2.  
  3. #include "glimpse.h"
  4.  
  5. extern CHAR *getword();
  6. extern int checksg();
  7. extern int D;
  8. extern CHAR GProgname[MAXNAME];
  9. extern FILE *debug;
  10. extern int StructuredIndex;
  11. extern int WHOLEFILESCOPE;
  12. extern int ByteLevelIndex;
  13. extern int ComplexBoolean;
  14. extern int foundattr;
  15. extern int foundnot;
  16.  
  17. /* returns where it found the distinguishing token: until that from prev value of begin is the current pattern (not just the "words" in it) */
  18. CHAR *
  19. parse_flat(begin, end, prev, next)
  20.     CHAR    *begin;
  21.     CHAR    *end;
  22.     int    prev;
  23.     int    *next;
  24. {
  25.     if (begin > end) {
  26.         *next = prev;
  27.         return end;
  28.     }
  29.  
  30.     if (prev & ENDSUB_EXP) prev &= ~ATTR_EXP;
  31.     if ((prev & ATTR_EXP) && !(prev & VAL_EXP)) prev |= VAL_EXP;
  32.  
  33.     while (begin <= end) {
  34.         if (*begin == ',') {
  35.             prev |= OR_EXP;
  36.             prev |= VAL_EXP;
  37.             prev |= ENDSUB_EXP;
  38.             if (prev & AND_EXP) {
  39.                 fprintf(stderr, "%s: parse error at character '%c'\n", GProgname, *begin);
  40.                 return NULL;
  41.             }
  42.             *next = prev;
  43.             return begin;
  44.         }
  45.         else if (*begin == ';') {
  46.             prev |= AND_EXP;
  47.             prev |= VAL_EXP;
  48.             prev |= ENDSUB_EXP;
  49.             if (prev & OR_EXP) {
  50.                 fprintf(stderr, "%s: parse error at character '%c'\n", GProgname, *begin);
  51.                 return NULL;
  52.             }
  53.             *next = prev;
  54.             return begin;
  55.         }
  56.         else if (*begin == '=') {
  57.             if (StructuredIndex <= 0) begin++;    /* don't care about = since just another character */
  58.             else {
  59.                 if (prev & ATTR_EXP) {
  60.                     fprintf(stderr, "%s: syntax error: only ',' and ';' can follow 'attribute=value'\n", GProgname);
  61.                     return NULL;
  62.                 }
  63.                 prev |= ATTR_EXP;    /* remains an ATTR_EXP until a new ',' OR ';' */
  64.                 prev &= ~VAL_EXP;
  65.                 *next = prev;
  66.                 return begin;
  67.             }
  68.         }
  69.         else if (*begin == '\\') begin ++;    /* skip two things */
  70.         begin++;
  71.     }
  72.  
  73.     *next = prev;
  74.     return begin;
  75. }
  76.  
  77. int
  78. split_pattern_flat(GPattern, GM, APattern, terminals, pnum_terminals, pGParse, num_attr)
  79.     CHAR    *GPattern;
  80.     int    GM;
  81.     CHAR    *APattern;
  82.     ParseTree terminals[];
  83.     int    *pnum_terminals;
  84.     int    *pGParse;    /* doesn't interpret it as a tree */
  85.     int    num_attr;
  86. {
  87.     int   j, k = 0, l = 0, len = 0;
  88.     int   current_attr;
  89.     CHAR  *buffer;
  90.     CHAR  *buffer_pat;
  91.     CHAR  *buffer_end;
  92.     char  tempbuf[MAX_LINE_LEN];
  93.  
  94.     memset(APattern, '\0', MAXPAT);
  95.     buffer = GPattern;
  96.     buffer_end = buffer + GM;
  97.     j=0;
  98.     *pGParse = 0;
  99.     current_attr = 0;
  100.     foundattr = 0;
  101.  
  102.     /*
  103.      * buffer is the runnning pointer, buffer_pat is the place where
  104.      * the distinguishing delimiter was found, buffer_end is the end.
  105.      */
  106.      while (buffer_pat = parse_flat(buffer, buffer_end, *pGParse, pGParse)) {
  107.         /* there is no pattern until after the distinguishing delimiter position: some agrep garbage */
  108.         if (buffer_pat <= buffer) {
  109.             buffer = buffer_pat+1;
  110.             if (buffer_pat >= buffer_end) break;
  111.             continue;
  112.         }
  113.         if ((*pGParse & ATTR_EXP) && !(*pGParse & VAL_EXP)) {    /* fresh attribute */
  114.             foundattr=1;
  115.             memcpy(tempbuf, buffer, buffer_pat - buffer);
  116.             tempbuf[buffer_pat - buffer] = '\0';
  117.             len = strlen(tempbuf);
  118.             for (k = 0; k<len; k++) {
  119.                 if (tempbuf[k] == '\\') {
  120.                     for (l=k; l<len; l++)
  121.                         tempbuf[l] = tempbuf[l+1];
  122.                     len --;
  123.                 }
  124.             }
  125.             if ( ((current_attr = attr_name_to_id(tempbuf, len)) <= 0) || (current_attr >= num_attr)) {
  126.                 buffer[buffer_pat - buffer] = '\0';
  127.                 fprintf(stderr, "%s: unknown attribute name '%s'\n", GProgname, buffer);
  128.                 return -1;
  129.             }
  130.  
  131.             buffer = buffer_pat+1;    /* immediate next character after distinguishing delimiter */
  132.             if (buffer_pat >= buffer_end) break;
  133.             continue;
  134.         }
  135.         else {    /* attribute's value OR raw-value */
  136.             if (*pnum_terminals >= MAXNUM_PAT) {
  137.                 fprintf(stderr, "%s: boolean expression has too many terms\n", GProgname);
  138.                 return -1;
  139.             }
  140.             terminals[*pnum_terminals].op = 0;
  141.             terminals[*pnum_terminals].type = LEAF;
  142.             terminals[*pnum_terminals].terminalindex = *pnum_terminals;
  143.             terminals[*pnum_terminals].data.leaf.attribute = (unsigned char *)current_attr;    /* default is no structure */
  144.             terminals[*pnum_terminals].data.leaf.value = (CHAR *)malloc(buffer_pat - buffer + 2);
  145.             memcpy(terminals[*pnum_terminals].data.leaf.value, buffer, buffer_pat - buffer);    /* without distinguishing delimiter */
  146.             terminals[*pnum_terminals].data.leaf.value[buffer_pat - buffer] = '\0';
  147.             if (foundattr || WHOLEFILESCOPE) {
  148.                 memcpy(&APattern[j], buffer, buffer_pat - buffer);
  149.                 j += buffer_pat - buffer;    /* NOT including the distinguishing delimiter at buffer_pat, or '\0' */
  150.                 APattern[j++] = (*(buffer_pat + 1) == '\0' ? '\0' : ',');    /* always search for OR, do filtering at the end */
  151. #if    BG_DEBUG
  152.                 fprintf(debug, "current_attr = %d, val = %s\n", current_attr, terminals[*pnum_terminals].data.leaf.value);
  153. #endif    /*BG_DEBUG*/
  154.             }
  155.             else {
  156.                 memcpy(&APattern[j], buffer, buffer_pat + 1 - buffer);
  157.                 j += buffer_pat + 1 - buffer;    /* including the distinguishing delimiter at buffer_pat, or '\0' */
  158.             }
  159.             (*pnum_terminals)++;
  160.         }
  161.         if (*pGParse & ENDSUB_EXP) current_attr = 0;    /* remains 0 until next fresh attribute */
  162.         if (buffer_pat >= buffer_end) break;
  163.         buffer = buffer_pat+1;
  164.     }
  165.     if (buffer_pat == NULL) return -1;    /* got out of while loop because of NULL rather than break */
  166.     APattern[j] = '\0';
  167.  
  168.     if (foundattr || WHOLEFILESCOPE)    /* then search must always be OR since scope is over whole files */
  169.         for (j=0; APattern[j] != '\0'; j++)
  170.             if (APattern[j] == '\\') j++;
  171.             else if (APattern[j] == ';') APattern[j] = ',';
  172.     return(*pnum_terminals);
  173. }
  174.  
  175. extern int is_complex_boolean();    /* use the one in agrep/asplit.c */
  176. extern int get_token_bool();    /* use the one in agrep/asplit.c */
  177.  
  178. /* Spaces ARE significant: 'a1=v1' and 'a1=v1 ' and 'a1 =v1' etc. are NOT identical */
  179. int
  180. get_attribute_value(pattr, pval, tokenbuf, tokenlen, num_attr)
  181.     int    *pattr, tokenlen;
  182.     CHAR    **pval, *tokenbuf;
  183. {
  184.     CHAR    tempbuf[MAXNAME];
  185.     int    i = 0, j = 0, k = 0, l = 0;
  186.  
  187.     while (i < tokenlen) {
  188.         if (tokenbuf[i] == '\\') {
  189.             tempbuf[j++] = tokenbuf[i++];
  190.             tempbuf[j++] = tokenbuf[i++];
  191.         }
  192.         else if (StructuredIndex) {
  193.             if (tokenbuf[i] == '=') {
  194.                 i++;    /* skip over = : now @ 1st char of value */
  195.                 tempbuf[j] = '\0';
  196.                 for (k=0; k<j; k++) {
  197.                     if (tempbuf[k] == '\\') {
  198.                         for (l=k; l<j; l++)
  199.                             tempbuf[l] = tempbuf[l+1];
  200.                         j --;
  201.                     }
  202.                 }
  203.                 if ( ((*pattr = attr_name_to_id(tempbuf, j)) <= 0) || (*pattr >= num_attr) ) {    /* named a non-existent attribute */
  204.                     fprintf(stderr, "%s: unknown attribute name '%s'\n", GProgname, tempbuf);
  205.                     return 0;
  206.                 }
  207.                 *pval = (CHAR *)malloc(tokenlen - i + 2);
  208.                 memcpy(*pval, &tokenbuf[i], tokenlen - i);
  209.                 (*pval)[tokenlen - i] = '\0';
  210.                 foundattr = 1;
  211.                 return 1;
  212.             }
  213.             else tempbuf[j++] = tokenbuf[i++];    /* consider = as just another char */
  214.         }
  215.         else tempbuf[j++] = tokenbuf[i++];    /* no attribute parsing */
  216.     }
  217.     /* Not a structured expression */
  218.     tempbuf[j] = '\0';
  219.     *pval = (CHAR *)malloc(j + 2);
  220.     memcpy(*pval, tempbuf, j);
  221.     (*pval)[j] = '\0';
  222.     return 1;
  223. }
  224.  
  225. extern destroy_tree();    /* use the one in agrep/asplit.c */
  226.  
  227. /*
  228.  * Recursive descent; C-style => AND + OR have equal priority => must bracketize expressions appropriately or will go left->right.
  229.  * Also strips out attribute names since agrep doesn't understand them: copies resulting pattern for agrep-ing into apattern.
  230.  * Grammar:
  231.  *     E = {E} | ~a | ~{E} | E ; E | E , E | a
  232.  * Parser:
  233.  *    One look ahead at each literal will tell you what to do.
  234.  *    ~ has highest priority, ; and , have equal priority (left to right associativity), ~~ is not allowed.
  235.  */
  236. ParseTree *
  237. parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)
  238.     CHAR    *buffer;
  239.     int    len;
  240.     int    *bufptr;
  241.     CHAR    *apattern;
  242.     int    *apatptr;
  243.     ParseTree terminals[];
  244.     int    *pnum_terminals;
  245.     int    num_attr;
  246. {
  247.     int    token, tokenlen;
  248.     CHAR    tokenbuf[MAXNAME];
  249.     int    oldtokenlen;
  250.     CHAR    oldtokenbuf[MAXNAME];
  251.     ParseTree *t, *n, *leftn;
  252.  
  253.     token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen);
  254.     switch(token)
  255.     {
  256.     case    '{':    /* (exp) */
  257.         apattern[(*apatptr)++] = '{';
  258.         if ((t = parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)) == NULL) return NULL;
  259.         if ((token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen)) != '}') {
  260.             fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  261.             destroy_tree(t);
  262.             return (NULL);
  263.         }
  264.         apattern[(*apatptr)++] = '}';
  265.         if ((token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen)) == 'e') return t;
  266.         switch(token)
  267.         {
  268.         /* must find boolean infix operator */
  269.         case ',':
  270.         case ';':
  271.             apattern[(*apatptr)++] = token;
  272.             leftn = t;
  273.             if ((t = parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)) == NULL) return NULL;
  274.             n = (ParseTree *)malloc(sizeof(ParseTree));
  275.             n->op = (token == ';') ? ANDPAT : ORPAT ;
  276.             n->type = INTERNAL;
  277.             n->data.internal.left = leftn;
  278.             n->data.internal.right = t;
  279.             return n;
  280.  
  281.         /* or end of parent sub expression */
  282.         case '}':
  283.             unget_token_bool(bufptr, tokenlen);    /* part of someone else who called me */
  284.             return t;
  285.  
  286.         default:
  287.             destroy_tree(t);
  288.             fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  289.             return NULL;
  290.         }
  291.  
  292.     /* Go one level deeper */
  293.     case    '~':    /* not exp */
  294.         foundnot = 1;
  295.         apattern[(*apatptr)++] = '~';
  296.         if ((token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen)) == 'e') return NULL;
  297.         switch(token)
  298.         {
  299.         case 'a':
  300.             if (*pnum_terminals >= MAXNUM_PAT) {
  301.                 fprintf(stderr, "%s: pattern expression too long (> %d terms)\n", GProgname, MAXNUM_PAT);
  302.                 return NULL;
  303.             }
  304.             n = &terminals[*pnum_terminals];
  305.             n->op = 0;
  306.             n->type = LEAF;
  307.             n->terminalindex = (*pnum_terminals);
  308.             n->data.leaf.value = NULL;
  309.             n->data.leaf.attribute = 0;
  310.             if (!get_attribute_value((int *)&n->data.leaf.attribute, &n->data.leaf.value, tokenbuf, tokenlen, num_attr)) return NULL;
  311.             strcpy(&apattern[*apatptr], n->data.leaf.value);
  312.             *apatptr += strlen(n->data.leaf.value);
  313.             (*pnum_terminals)++;
  314.             n->op |= NOTPAT;
  315.             t = n;
  316.             break;
  317.  
  318.         case '{':
  319.             apattern[(*apatptr)++] = token;
  320.             if ((t = parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)) == NULL) return NULL;
  321.             if (t->op & NOTPAT) t->op &= ~NOTPAT;
  322.             else t->op |= NOTPAT;
  323.             if ((token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen)) != '}') {
  324.                 fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  325.                 destroy_tree(t);
  326.                 return NULL;
  327.             }
  328.             apattern[(*apatptr)++] = '}';
  329.             break;
  330.  
  331.         default:
  332.             fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  333.             return NULL;
  334.         }
  335.         /* The resulting tree is in t. Now do another lookahead at this level */
  336.  
  337.         if ((token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen)) == 'e') return t;
  338.         switch(token)
  339.         {
  340.         /* must find boolean infix operator */
  341.         case ',':
  342.         case ';':
  343.             apattern[(*apatptr)++] = token;
  344.             leftn = t;
  345.             if ((t = parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)) == NULL) return NULL;
  346.             n = (ParseTree *)malloc(sizeof(ParseTree));
  347.             n->op = (token == ';') ? ANDPAT : ORPAT ;
  348.             n->type = INTERNAL;
  349.             n->data.internal.left = leftn;
  350.             n->data.internal.right = t;
  351.             return n;
  352.  
  353.         case '}':
  354.             unget_token_bool(bufptr, tokenlen);
  355.             return t;
  356.  
  357.         default:
  358.             destroy_tree(t);
  359.             fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  360.             return NULL;
  361.         }
  362.  
  363.     case    'a':    /* individual term (attr=val) */
  364.         if (tokenlen == 0) return NULL;
  365.         memcpy(oldtokenbuf, tokenbuf, tokenlen);
  366.         oldtokenlen = tokenlen;
  367.         oldtokenbuf[oldtokenlen] = '\0';
  368.         token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen);
  369.         switch(token)
  370.         {
  371.         case '}':    /* part of case '{' above: else syntax error not detected but semantics ok */
  372.             unget_token_bool(bufptr, tokenlen);
  373.         case 'e':    /* endof input */
  374.         case ',':
  375.         case ';':
  376.             if (*pnum_terminals >= MAXNUM_PAT) {
  377.                 fprintf(stderr, "%s: pattern expression too long (> %d terms)\n", GProgname, MAXNUM_PAT);
  378.                 return NULL;
  379.             }
  380.             n = &terminals[*pnum_terminals];
  381.             n->op = 0;
  382.             n->type = LEAF;
  383.             n->terminalindex = (*pnum_terminals);
  384.             n->data.leaf.value = NULL;
  385.             n->data.leaf.attribute = 0;
  386.             if (!get_attribute_value((int *)&n->data.leaf.attribute, &n->data.leaf.value, oldtokenbuf, oldtokenlen, num_attr)) return NULL;
  387.             strcpy(&apattern[*apatptr], n->data.leaf.value);
  388.             *apatptr += strlen(n->data.leaf.value);
  389.             (*pnum_terminals)++;
  390.             if ((token == 'e') || (token == '}')) return n;    /* nothing after terminal in expression */
  391.  
  392.             leftn = n;
  393.             apattern[(*apatptr)++] = token;
  394.             if ((t = parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)) == NULL) return NULL;
  395.             n = (ParseTree *)malloc(sizeof(ParseTree));
  396.             n->op = (token == ';') ? ANDPAT : ORPAT ;
  397.             n->type = INTERNAL;
  398.             n->data.internal.left = leftn;
  399.             n->data.internal.right = t;
  400.             return n;
  401.  
  402.         default:
  403.             fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  404.             return NULL;
  405.         }
  406.  
  407.     case    'e':    /* can't happen as I always do a lookahead above and return current tree if e */
  408.     default:
  409.         fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  410.         return NULL;
  411.     }
  412. }
  413.  
  414. int
  415. split_pattern(GPattern, GM, APattern, terminals, pnum_terminals, pGParse, num_attr)
  416.     CHAR    *GPattern;
  417.     int    GM;
  418.     CHAR    *APattern;
  419.     ParseTree terminals[];
  420.     int    *pnum_terminals;
  421.     ParseTree **pGParse;
  422.     int    num_attr;
  423. {
  424.     int    bufptr = 0, apatptr = 0, ret, i, j;
  425.  
  426.     foundattr = 0;
  427.     if (is_complex_boolean(GPattern, GM)) {
  428.         ComplexBoolean = 1;
  429.         *pnum_terminals = 0;
  430.         if ((*pGParse = parse_tree(GPattern, GM, &bufptr, APattern, &apatptr, terminals, pnum_terminals, num_attr)) == NULL)
  431.             return -1;
  432.         /* print_tree(*pGParse, 0); */
  433.         APattern[apatptr] = '\0';
  434.         if (foundattr || WHOLEFILESCOPE) {    /* Search in agrep must always be OR since scope is whole file */
  435.             int    i, j;
  436.  
  437.             for (i=0; i<apatptr; i++) {
  438.                 if (APattern[i] == '\\') i++;
  439.                 else if (APattern[i] == ';') APattern[i] = ',';
  440.                 else if ((APattern[i] == '~') || (APattern[i] == '{') || (APattern[i] == '}')) {
  441.                     /* eliminate it from pattern by shifting (including '\0') since agrep must essentially do a flat search */
  442.                     if (APattern[i] == '~') foundnot = 1;
  443.                     for (j=i; j<apatptr; j++)
  444.                         APattern[j] = APattern[j+1];
  445.                     apatptr --;
  446.                     i--;    /* to counter the ++ on top */
  447.                 }
  448.             }
  449.         }
  450.         return *pnum_terminals;
  451.     }
  452.     else {
  453.         for (i=0; i<GM; i++) {
  454.             if (GPattern[i] == '\\') i++;
  455.             else if ((GPattern[i] == '{') || (GPattern[i] == '}')) {
  456.                 /* eliminate it from pattern by shifting (including '\0') since agrep must essentially do a flat search */
  457.                 for (j=i; j<GM; j++)
  458.                     GPattern[j] = GPattern[j+1];
  459.                 GM --;
  460.                 i--;    /* counter the ++ on top */
  461.             }
  462.         }
  463.  
  464.         ComplexBoolean = 0;
  465.         *pnum_terminals = 0;
  466.         if ((ret = split_pattern_flat(GPattern, GM, APattern, terminals, pnum_terminals, (int *)pGParse, num_attr)) == -1)
  467.             return -1;
  468.         return ret;
  469.     }
  470. }
  471.  
  472. int eval_tree();    /* use the one in agrep/asplit.c */
  473.  
  474. /* MUST CHANGE ALL memgreps TO USE EXEC DIRECTLY IF POSSIBLE (LAST PRIORITY) */
  475.  
  476. /* All borrowed from main.c and are needed for searching the index */
  477. extern    CHAR    *pat_list[MAXNUM_PAT];  /* complete words within global pattern */
  478. extern    int    pat_lens[MAXNUM_PAT];   /* their lengths */
  479. extern    int    pat_attr[MAXNUM_PAT];   /* set of attributes */
  480. extern    int    num_pat;
  481. extern    CHAR    pat_buf[(MAXNUM_PAT + 2)*MAXPAT];
  482. extern    int    pat_ptr;
  483. extern    int    is_mgrep_pat[MAXNUM_PAT];
  484. extern    int    mgrep_pat_index[MAXNUM_PAT];
  485. extern    int    num_mgrep_pat;
  486. extern    struct offsets **src_offset_table;
  487. extern    struct offsets **curr_offset_table;
  488. extern    char    tempfile[];
  489. extern    int    patindex;
  490. extern    int    patbufpos;
  491. extern    ParseTree terminals[MAXNUM_PAT];
  492. extern    int    num_terminals;
  493. extern int INVERSE;    /* agrep's global: need here to implement ~ in index-search */
  494.  
  495. /* [first, last) = C-style range for which we want the words in terminal-values' patterns: 0..num_terminals for !ComplexBoolean, term/term otherwise */
  496. split_terminal(first, last)
  497.     int    first, last;
  498. {
  499.         CHAR    *buffer;
  500.         CHAR    *buffer_new;
  501.         CHAR    *buffer_end;
  502.         CHAR    *bp;
  503.         CHAR    word[MAXNAME];
  504.         int    word_length;
  505.         int    type;
  506.     int    i, j, k, attribute;
  507.     char    *substring;    /* used with strstr(superstring, substring) */
  508.  
  509.     pat_ptr = 0;
  510.     num_mgrep_pat = 0;
  511.     num_pat = 0;
  512.  
  513.     for (; first<last; first++) {
  514.         attribute = (int)terminals[first].data.leaf.attribute;
  515.         buffer = terminals[first].data.leaf.value;
  516.         buffer_end = buffer + strlen(terminals[first].data.leaf.value);
  517.  
  518.                 /* Now find out which; are the "words" we can search for in the index: each attr_val can have many words in it: e.g., "AUTHOR=Udi Manber" */
  519.                 while ((buffer_new = getword("stdin", word, buffer, buffer_end, NULL, NULL)) <= buffer_end) {
  520.                         word_length = strlen(word);
  521.                         if (word_length <= 0) {
  522.                                 buffer = buffer_new;
  523.                                 if (buffer_new >= buffer_end) break;
  524.                                 continue;
  525.                         }
  526.                         if ((type = checksg(word, D, 0)) == -1) return -1;
  527.             if (!type && ComplexBoolean) {
  528.                 fprintf(stderr, "%s: query has complex patterns (like '.*') or options (like -n)\n... cannot search for arbitrary booleans\n", GProgname);
  529.                 return -1;
  530.             }
  531.  
  532. #if    0
  533. DISABLED IN GLIMPSE NOW SINCE MGREP HANDLES DUPLICATES -- IT WAS ALWAYS ABLE TO HANDLE SUPERSTRINGS/SUBSTRINGS...: bgopal, Nov 19, 1996
  534.             if (type) {
  535.                 /* Check if superstring: if so, ditch word */
  536.                 for (i=0; i<num_pat; i++) {
  537.                     if (!is_mgrep_pat[i]) continue;
  538.                     substring = strstr(word, pat_list[i]);
  539.                     if ((substring != NULL) && (substring[0] != '\0')) break;
  540.                 }
  541.                 if (i < num_pat) {    /* printf("%s superstring of %s\n", word, pat_list[i]); */
  542.                     if (pat_attr[i] != attribute) pat_attr[i] = 0;    /* union of two unequal attributes is all attributes */
  543.                     buffer = buffer_new;
  544.                     if (buffer_new >= buffer_end) break;
  545.                     continue;
  546.                 }
  547.                 /* Check if substring: delete all superstrings */
  548.                 for (i=0; i<num_pat; i++) {
  549.                     if (!is_mgrep_pat[i]) continue;
  550.                     substring = strstr(pat_list[i], word);
  551.                     if ((substring != NULL) && (substring[0] != '\0')) {    /* printf("%s substring of %s\n", word, pat_list[i]); */
  552.                         if (pat_attr[i] != attribute) attribute = 0;    /* union of two unequal attributes is all attributes */
  553.                         free(pat_list[i]);
  554.                         for (j=i; j<num_pat; j++) {
  555.                             pat_list[j] = pat_list[j+1];
  556.                             pat_lens[j] = pat_lens[j+1];
  557.                             is_mgrep_pat[j] = is_mgrep_pat[j+1];
  558.                             pat_attr[j] = pat_attr[j+1];
  559.                         }
  560.                         num_pat --;
  561.                         for (j=0; j<num_mgrep_pat; j++) {
  562.                             if (mgrep_pat_index[j] == i) {
  563.                                 for (k=j; k<num_mgrep_pat; k++) {
  564.                                     mgrep_pat_index[k] = mgrep_pat_index[k+1] - 1;
  565.                                 }
  566.                                 num_mgrep_pat --;
  567.                                 break;
  568.                             }
  569.                         }
  570.                         i--;    /* to counter the ++ on top */
  571.                     }
  572.                 }
  573.             }
  574. #endif
  575.  
  576.                         buffer = buffer_new;
  577.                         bp = (CHAR *) malloc(sizeof(CHAR) * word_length + 2);
  578.                         if(bp == NULL) {
  579.                                 fprintf(stderr, "%s: malloc failed in %s:%d\n", GProgname, __FILE__, __LINE__);
  580.                                 return -1;
  581.                         }
  582.                         pat_list[num_pat] = bp;
  583.                         pat_lens[num_pat] = word_length;
  584.                         is_mgrep_pat[num_pat] = type;
  585.                         pat_attr[num_pat] = attribute;
  586.                         strcpy(pat_list[num_pat], word);
  587.             pat_list[num_pat][word_length] = '\0';
  588.             num_pat ++;
  589. #if     BG_DEBUG
  590.                         fprintf(debug, "word=%s\n", word);
  591. #endif  /*BG_DEBUG*/
  592.                         if(buffer_new >= buffer_end) break;
  593.                         if(num_pat >= MAXNUM_PAT) {
  594.                                 fprintf(stderr, "%s: Warning! too many words in pattern (> %d): ignoring...\n", GProgname, MAXNUM_PAT);
  595.                                 break;
  596.                         }
  597.                 }
  598.     }
  599.     for (i=0; i<num_pat; i++) {
  600.         strcpy(&pat_buf[pat_ptr], pat_list[i]);
  601.         pat_buf[pat_ptr + pat_lens[i]] = '\n';
  602.         pat_buf[pat_ptr + pat_lens[i] + 1] = '\0';
  603.         pat_ptr += (pat_lens[i] + 1);
  604.     }
  605.     return num_pat;
  606. }
  607.