home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD1.bin / gnu / src / baseline / jove-4.14.6.lha / jove-4.14.6 / re.c < prev    next >
C/C++ Source or Header  |  1992-01-10  |  19KB  |  975 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. /* search package */
  9.  
  10. #include "jove.h"
  11. #include "re.h"
  12. #include "ctype.h"
  13.  
  14. private void
  15.     search proto((int, bool, bool));
  16.  
  17. private int
  18.     do_comp proto((struct RE_block *,int));
  19.  
  20. private char
  21.     searchstr[128];        /* global search string */
  22.  
  23. char    rep_search[128],    /* replace search string */
  24.     rep_str[128];        /* contains replacement string */
  25.  
  26. bool    CaseIgnore = OFF,    /* ignore case? */
  27.     WrapScan = OFF,        /* wrap at end of buffer? */
  28.     UseRE = OFF;        /* use regular expressions */
  29.  
  30. #define cind_cmp(a, b)    (CharUpcase(a) == CharUpcase(b))
  31.  
  32. private int    REpeekc;
  33. private char    *REptr;
  34.  
  35. private int
  36. REgetc()
  37. {
  38.     int    c;
  39.  
  40.     if ((c = REpeekc) != -1)
  41.         REpeekc = -1;
  42.     else if (*REptr)
  43.         c = *REptr++;
  44.     else
  45.         c = '\0';
  46.  
  47.     return c;
  48. }
  49.  
  50. #define STAR     01    /* Match any number of last RE. */
  51. #define AT_BOL    2    /* ^ */
  52. #define AT_EOL    4    /* $ */
  53. #define AT_BOW    6    /* \< */
  54. #define AT_EOW    8    /* \> */
  55. #define OPENP    10    /* \( */
  56. #define CLOSEP    12    /* \) */
  57. #define CURLYB    14    /* \{ */
  58.  
  59. #define NOSTR    14    /* Codes <= NOSTR can't be *'d. */
  60.  
  61. #define ANYC    (NOSTR+2)        /* . */
  62. #define NORMC    (ANYC+2)        /* normal character */
  63. #define CINDC    (NORMC+2)        /* case independent character */
  64. #define ONE_OF    (CINDC+2)        /* [xxx] */
  65. #define NONE_OF    (ONE_OF+2)    /* [^xxx] */
  66. #define BACKREF    (NONE_OF+2)    /* \# */
  67. #define EOP    (BACKREF+2)    /* end of pattern */
  68.  
  69. /* ONE_OF/NONE_OF is represented as a bit vector.
  70.  * These symbols parameterize the representation.
  71.  */
  72.  
  73. #define    BYTESIZE    8
  74. #define    SETSIZE        (NCHARS / BYTESIZE)
  75. #define    SETBYTE(c)    ((c) / BYTESIZE)
  76. #define    SETBIT(c)    (1 << ((c) % BYTESIZE))
  77.  
  78. #define NPAR    10    /* [0-9] - 0th is the entire matched string, i.e. & */
  79. private char    *comp_ptr,
  80.         **alt_p,
  81.         **alt_endp;
  82.  
  83. void
  84. REcompile(pattern, re, re_blk)
  85. char    *pattern;
  86. bool    re;
  87. struct RE_block    *re_blk;
  88. {
  89.     REptr = pattern;
  90.     REpeekc = -1;
  91.     comp_ptr = re_blk->r_compbuf;
  92.     alt_p = re_blk->r_alternates;
  93.     alt_endp = alt_p + NALTS;
  94.     *alt_p++ = comp_ptr;
  95.     re_blk->r_nparens = 0;
  96.     (void) do_comp(re_blk, re ? OKAY_RE : NORM);
  97.     *alt_p = NULL;
  98.  
  99.     re_blk->r_anchored = NO;
  100.     re_blk->r_firstc = '\0';
  101.     /* do a little post processing */
  102.     if (re_blk->r_alternates[1] == NULL) {
  103.         char    *p;
  104.  
  105.         p = re_blk->r_alternates[0];
  106.         for (;;) {
  107.             switch (*p) {
  108.             case OPENP:
  109.             case CLOSEP:
  110.                 p += 2;
  111.                 continue;
  112.  
  113.             case AT_BOW:
  114.             case AT_EOW:
  115.                 p += 1;
  116.                 continue;
  117.  
  118.             case AT_BOL:
  119.                 re_blk->r_anchored = YES;
  120.                 /* don't set firstc -- won't work */
  121.                 break;
  122.  
  123.             case NORMC:
  124.             case CINDC:
  125.                 re_blk->r_firstc = CharUpcase(p[2]);
  126.                 break;
  127.  
  128.             default:
  129.                 break;
  130.             }
  131.             break;
  132.         }
  133.     }
  134. }
  135.  
  136. /* compile the pattern into an internal code */
  137.  
  138. private int
  139. do_comp(re_blk, kind)
  140. struct RE_block    *re_blk;
  141. int    kind;
  142. {
  143.     char    *this_verb,
  144.         *prev_verb,
  145.         *start_p,
  146.         *comp_endp;
  147.     int    parens[NPAR],
  148.         *parenp,
  149.         c,
  150.         ret_code;
  151.  
  152.     parenp = parens;
  153.     this_verb = NULL;
  154.     ret_code = 1;
  155.     comp_endp = &re_blk->r_compbuf[COMPSIZE - 6];
  156.  
  157.     /* wrap the whole expression around (implied) parens */
  158.     if (kind == OKAY_RE) {
  159.         *comp_ptr++ = OPENP;
  160.         *comp_ptr++ = re_blk->r_nparens;
  161.         *parenp++ = re_blk->r_nparens++;
  162.     }
  163.  
  164.     start_p = comp_ptr;
  165.  
  166.     while ((c = REgetc()) != '\0') {
  167.         if (comp_ptr > comp_endp) {
  168. toolong:
  169.             complain("Search string too long/complex.");
  170.         }
  171.         prev_verb = this_verb;
  172.         this_verb = comp_ptr;
  173.  
  174.         if (kind == NORM && strchr(".[*", c) != NULL)
  175.             goto defchar;
  176.         switch (c) {
  177.         case '\\':
  178.             switch (c = REgetc()) {
  179.             case '\0':
  180.                 complain("[Premature end of pattern]");
  181.                 /*NOTREACHED*/
  182.  
  183.             case '{':
  184.                 {
  185.                 char    *wcntp;        /* word count */
  186.  
  187.                 *comp_ptr++ = CURLYB;
  188.                 wcntp = comp_ptr;
  189.                 *comp_ptr++ = 0;
  190.                 for (;;) {
  191.                     int    comp_val;
  192.                     char    *comp_len;
  193.  
  194.                     comp_len = comp_ptr++;
  195.                     comp_val = do_comp(re_blk, IN_CB);
  196.                     *comp_len = comp_ptr - comp_len;
  197.                     (*wcntp) += 1;
  198.                     if (comp_val == 0)
  199.                         break;
  200.                 }
  201.                 break;
  202.                 }
  203.  
  204.             case '}':
  205.                 if (kind != IN_CB)
  206.                     complain("Unexpected \\}.");
  207.                 ret_code = 0;
  208.                 goto outahere;
  209.  
  210.             case '(':
  211.                 if (re_blk->r_nparens >= NPAR)
  212.                     complain("Too many ('s; max is %d.", NPAR);
  213.                 *comp_ptr++ = OPENP;
  214.                 *comp_ptr++ = re_blk->r_nparens;
  215.                 *parenp++ = re_blk->r_nparens++;
  216.                 break;
  217.  
  218.             case ')':
  219.                 if (parenp == parens)
  220.                     complain("Too many )'s.");
  221.                 *comp_ptr++ = CLOSEP;
  222.                 *comp_ptr++ = *--parenp;
  223.                 break;
  224.  
  225.             case '|':
  226.                 if (alt_p >= alt_endp)
  227.                     complain("Too many alternates; max %d.", NALTS);
  228.                 /* close off previous alternate */
  229.                 *comp_ptr++ = CLOSEP;
  230.                 *comp_ptr++ = *--parenp;
  231.                 *comp_ptr++ = EOP;
  232.                 *alt_p++ = comp_ptr;
  233.  
  234.                 /* start a new one */
  235.                 re_blk->r_nparens = 0;
  236.                 *comp_ptr++ = OPENP;
  237.                 *comp_ptr++ = re_blk->r_nparens;
  238.                 *parenp++ = re_blk->r_nparens++;
  239.                 start_p = comp_ptr;
  240.                 break;
  241.  
  242.             case '1':
  243.             case '2':
  244.             case '3':
  245.             case '4':
  246.             case '5':
  247.             case '6':
  248.             case '7':
  249.             case '8':
  250.             case '9':
  251.                 *comp_ptr++ = BACKREF;
  252.                 *comp_ptr++ = c - '0';
  253.                 break;
  254.  
  255.             case '<':
  256.                 *comp_ptr++ = AT_BOW;
  257.                 break;
  258.  
  259.             case '>':
  260.                 *comp_ptr++ = AT_EOW;
  261.                 break;
  262.  
  263.             default:
  264.                 goto defchar;
  265.             }
  266.             break;
  267.  
  268.         case ',':
  269.             if (kind != IN_CB)
  270.                 goto defchar;
  271.             goto outahere;
  272.  
  273.         case '.':
  274.             *comp_ptr++ = ANYC;
  275.             break;
  276.  
  277.         case '^':
  278.             if (comp_ptr == start_p) {
  279.                 *comp_ptr++ = AT_BOL;
  280.                 break;
  281.             }
  282.             goto defchar;
  283.  
  284.         case '$':
  285.             if ((REpeekc = REgetc()) != '\0' && REpeekc != '\\')
  286.                 goto defchar;
  287.             *comp_ptr++ = AT_EOL;
  288.             break;
  289.  
  290.         case '[':
  291.             {
  292.             int    chrcnt;
  293.  
  294.             *comp_ptr++ = ONE_OF;
  295.             if (comp_ptr + SETSIZE >= comp_endp)
  296.                 goto toolong;
  297.             byte_zero(comp_ptr, (size_t) SETSIZE);
  298.             if ((REpeekc = REgetc()) == '^') {
  299.                 *this_verb = NONE_OF;
  300.                 /* Get it for real this time. */
  301.                 (void) REgetc();
  302.             }
  303.             chrcnt = 0;
  304.             while ((c = REgetc()) != ']' && c != '\0') {
  305.                 if (c == '\\') {
  306.                     c = REgetc();
  307.                     if (c == '\0')
  308.                         break;
  309.                 } else if ((REpeekc = REgetc()) == '-') {
  310.                     int    i;
  311.  
  312.                     i = c;
  313.                     (void) REgetc();     /* reread '-' */
  314.                     c = REgetc();
  315.                     if (c == '\0')
  316.                         break;
  317.                     while (i < c) {
  318.                         comp_ptr[SETBYTE(i)] |= SETBIT(i);
  319.                         i += 1;
  320.                     }
  321.                 }
  322.                 comp_ptr[SETBYTE(c)] |= SETBIT(c);
  323.                 chrcnt += 1;
  324.             }
  325.             if (c == '\0')
  326.                 complain("Missing ].");
  327.             if (chrcnt == 0)
  328.                 complain("Empty [].");
  329.             comp_ptr += SETSIZE;
  330.             break;
  331.             }
  332.  
  333.         case '*':
  334.             if (prev_verb == NULL || *prev_verb <= NOSTR || (*prev_verb&STAR)!=0)
  335.                 goto defchar;
  336.  
  337.             if (*prev_verb == NORMC || *prev_verb == CINDC) {
  338.                 char    lastc = comp_ptr[-1];
  339.  
  340.                 /* The * operator applies only to the
  341.                  * previous character.  Since we were
  342.                  * building a string-matching command
  343.                  * (NORMC or CINDC), we must split it
  344.                  * up and work with the last character.
  345.                  *
  346.                  * Note that the STARed versions of these
  347.                  * commands do not operate on strings, and
  348.                  * so do not need or have character counts.
  349.                  */
  350.  
  351.                 if (prev_verb[1] == 1) {
  352.                     /* Only one char in string:
  353.                      * delete old command.
  354.                      */
  355.                     this_verb = prev_verb;
  356.                 } else {
  357.                     /* Several chars in string:
  358.                      * strip off the last.
  359.                      * New verb is derived from old.
  360.                      */
  361.                     prev_verb[1] -= 1;
  362.                     this_verb -= 1;
  363.                     *this_verb = *prev_verb;
  364.                 }
  365.                 comp_ptr = this_verb + 1;
  366.                 *comp_ptr++ = lastc;
  367.             } else {
  368.                 /* This command is just the previous one,
  369.                  * whose verb we will modify.
  370.                  */
  371.                 this_verb = prev_verb;
  372.             }
  373.             *this_verb |= STAR;
  374.             break;
  375.         default:
  376. defchar:
  377.             if ((prev_verb == NULL) ||
  378.                 !(*prev_verb == NORMC || *prev_verb == CINDC)) {
  379.                 /* create new string command */
  380.                 *comp_ptr++ = (CaseIgnore) ? CINDC : NORMC;
  381.                 *comp_ptr++ = 0;
  382.             } else {
  383.                 /* merge this into previous string command */
  384.                 this_verb = prev_verb;
  385.             }
  386.             this_verb[1] += 1;
  387.             *comp_ptr++ = c;
  388.             break;
  389.         }
  390.     }
  391. outahere:
  392.  
  393.     /* End of pattern, l