home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / rxclass.C < prev    next >
C/C++ Source or Header  |  1998-03-25  |  7KB  |  302 lines

  1. // $Id: rxclass.C,v 1.18 1998/03/25 12:46:27 zeller Exp $ -*- C++ -*-
  2. // Regular expression class, based on POSIX regcomp()/regexec() interface
  3.  
  4. // Copyright (C) 1996 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char regex_rcsid[] = 
  30.     "$Id: rxclass.C,v 1.18 1998/03/25 12:46:27 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "config.h"
  37. #include "bool.h"
  38. #include "strclass.h"
  39. #include "assert.h"
  40. #include "misc.h"
  41. #include "cook.h"
  42.  
  43. #include <stdlib.h>
  44. #include <iostream.h>
  45. #include <ctype.h>
  46. #include <string.h>        // strncmp()
  47.  
  48. #if WITH_RUNTIME_REGEX
  49. // Get a prefix character from T; let T point at the next prefix character.
  50. char regex::get_prefix(const char *& t, int flags)
  51. {
  52.     if (flags & REG_EXTENDED)
  53.     {
  54.     switch (*t++)
  55.     {
  56.     case '.':
  57.     case '(':
  58.     case '^':
  59.     case '$':
  60.         return '\0';
  61.  
  62.     case '[':
  63.         if (*t != ']' && *t != '\0' && *t != '^' && t[1] == ']')
  64.         {
  65.         char ret = *t;
  66.         t += 2;
  67.         return ret;
  68.         }
  69.         return '\0';
  70.  
  71.     case '\\':
  72.         return *t++;
  73.  
  74.     default:
  75.         // Ordinary character
  76.         switch (*t)
  77.         {
  78.         case '+':
  79.         case '*':
  80.         case '?':
  81.         case '|':
  82.         return '\0';
  83.         
  84.         default:
  85.         return t[-1];
  86.         }
  87.     }
  88.     }
  89.     else
  90.     {
  91.     // FIXME: give some rules for ordinary regexps
  92.     return '\0';
  93.     }
  94. }
  95.  
  96. void regex::fatal(int errcode, const char *src)
  97. {
  98.     if (errcode == 0)
  99.     return;
  100.  
  101.     size_t length = regerror(errcode, &compiled, (char *)0, 0);
  102.     char *buffer = new char[length];
  103.     regerror(errcode, &compiled, buffer, length);
  104.  
  105.     cerr << "regex ";
  106.     if (src)
  107.      cerr << quote(src) << ": ";
  108.     cerr << "error " << errcode;
  109.     if (buffer[0] != '\0')
  110.     cerr << " - " << buffer;
  111.     cerr << "\n";
  112. #if !defined(REGCOMP_BROKEN) && !defined(GNU_LIBrx_USED)
  113.     cerr << "As a workaround, link with GNU librx - "
  114.     "in `config.h', #define REGCOMP_BROKEN.\n";
  115. #endif
  116.     delete[] buffer;
  117.  
  118.     abort();
  119. }
  120.  
  121. regex::regex(const char* t, int flags)
  122.     : exprs(0), matcher(0), data(0)
  123. {
  124.     string rx = "^" + string(t);
  125.     int errcode = regcomp(&compiled, rx, flags);
  126.     if (errcode)
  127.     fatal(errcode, rx.chars());
  128.  
  129.     exprs = new regmatch_t[nexprs()];
  130.  
  131.     unsigned int i = 0;
  132.     const char *s = t;
  133.     while ((prefix[i++] = get_prefix(s, flags)) != '\0'
  134.        && i < sizeof(prefix) - 1)
  135.     ;
  136.     prefix[i] = '\0';
  137. }
  138. #endif // WITH_RUNTIME_REGEX
  139.  
  140. regex::regex(rxmatchproc p, void *d)
  141.     : 
  142. #if WITH_RUNTIME_REGEX
  143.     exprs(0),
  144. #endif
  145.     matcher(p), data(d)
  146. {
  147. #if WITH_RUNTIME_REGEX
  148.     prefix[0] = '\0';
  149. #endif
  150. }
  151.  
  152. regex::~regex()
  153. {
  154. #if WITH_RUNTIME_REGEX
  155.     if (matcher == 0)
  156.     regfree(&compiled);
  157.     delete[] exprs;
  158. #endif // WITH_RUNTIME_REGEX
  159. }
  160.  
  161. // Search T in S; return position of first occurrence.
  162. // If STARTPOS is positive, start search from that position.
  163. // If STARTPOS is negative, perform reverse search from that position 
  164. // and return last occurrence.
  165. // MATCHLEN contains the length of the matched expression.
  166. // If T is not found, return -1.
  167. int regex::search(const char* s, int len, int& matchlen, int startpos) const
  168. {
  169.     string substr;
  170.     int direction = +1;
  171.  
  172.     if (startpos < 0)
  173.     {
  174.     startpos += len;
  175.     direction = -1;
  176.     }
  177.     if (startpos < 0 || startpos > len)
  178.     return -1;
  179.  
  180.     if (s[len] != '\0')
  181.     {
  182.     substr = string(s, len);
  183.     s = (char *)substr;
  184.     }
  185.     assert(s[len] == '\0');
  186.  
  187. #if WITH_RUNTIME_REGEX
  188.     int errcode = 0;
  189.     int prefix_len = strlen(prefix);
  190. #endif
  191.  
  192.     for (; startpos >= 0 && startpos < len; startpos += direction)
  193.     {
  194.     if (matcher != 0)
  195.     {
  196.         matchlen = matcher(data, s, len, startpos);
  197.         if (matchlen >= 0)
  198.         break;
  199.     }
  200. #if WITH_RUNTIME_REGEX
  201.     else
  202.     { 
  203.         char *t = (char *)s + startpos;
  204.         if (strncmp(t, prefix, min(prefix_len, len - startpos)) == 0)
  205.         {
  206.         errcode = regexec((regex_t *)&compiled, t, nexprs(), exprs, 0);
  207.         if (errcode == 0)
  208.             break;
  209.         }
  210.     }
  211. #endif // WITH_RUNTIME_REGEX
  212.     }
  213.  
  214.     if (startpos < 0 || startpos >= len)
  215.     return -1;
  216.  
  217.     int matchpos = startpos;
  218.  
  219. #if WITH_RUNTIME_REGEX
  220.     if (exprs[0].rm_so >= 0)
  221.     {
  222.     matchpos = exprs[0].rm_so + startpos;
  223.     matchlen = exprs[0].rm_eo - exprs[0].rm_so;
  224.     }
  225.     else
  226.     {
  227.     matchpos = -1;
  228.     matchlen = 0;
  229.     }
  230. #endif // WITH_RUNTIME_REGEX
  231.  
  232.     return matchpos;
  233. }
  234.  
  235. // Return length of matched string iff T matches S at POS, 
  236. // -1 otherwise.  LEN is the length of S.
  237. int regex::match(const char *s, int len, int pos) const
  238. {
  239.     if (matcher != 0)
  240.     return matcher(data, s, len, pos);
  241.  
  242. #if WITH_RUNTIME_REGEX
  243.     string substr;
  244.     if (pos < 0)
  245.     pos += len;
  246.     if (pos > len)
  247.     return -1;
  248.  
  249.     if (s[len] != '\0')
  250.     {
  251.     substr = string(s, len);
  252.     s = (char *)substr;
  253.     }
  254.     assert(s[len] == '\0');
  255.  
  256.     int errcode = regexec((regex_t *)&compiled, (char *)s + pos, 
  257.               nexprs(), exprs, 0);
  258.  
  259.     if (errcode == 0 && exprs[0].rm_so >= 0)
  260.     return exprs[0].rm_eo - exprs[0].rm_so;
  261. #endif
  262.  
  263.     return -1;
  264. }
  265.  
  266. #if WITH_RUNTIME_REGEX
  267. bool regex::match_info(int& start, int& length, int nth) const
  268. {
  269.     if ((unsigned)(nth) >= nexprs())
  270.     return false;
  271.     else
  272.     {
  273.     start  = exprs[nth].rm_so;
  274.     length = exprs[nth].rm_eo - start;
  275.     return start >= 0 && length >= 0;
  276.     }
  277. }
  278. #endif
  279.  
  280. bool regex::OK() const
  281. {
  282. #if WITH_RUNTIME_REGEX
  283.     assert(exprs != 0);
  284. #endif
  285.     return true;
  286. }
  287.  
  288.  
  289. #if WITH_RUNTIME_REGEX && RUNTIME_REGEX
  290. // Built-in regular expressions
  291.  
  292. const regex rxwhite("[ \n\t\r\v\f]+");
  293. const regex rxint("-?[0-9]+");
  294. const regex rxdouble("-?(([0-9]+\\.[0-9]*)|([0-9]+)|(\\.[0-9]+))"
  295.              "([eE][---+]?[0-9]+)?");
  296. const regex rxalpha("[A-Za-z]+");
  297. const regex rxlowercase("[a-z]+");
  298. const regex rxuppercase("[A-Z]+");
  299. const regex rxalphanum("[0-9A-Za-z]+");
  300. const regex rxidentifier("[A-Za-z_$][A-Za-z0-9_$]*");
  301. #endif // WITH_RUNTIME_REGEX
  302.