]> mj.ucw.cz Git - libucw.git/blobdiff - lib/regex.c
Branched off v3.12.1.
[libucw.git] / lib / regex.c
index 6ed90243c86a727e99a4a34c91a567dccb85e0d7..270fb590b5e7fc8873afefc2d5c898c97a1d1287 100644 (file)
 /*
 /*
- *     Sherlock Library -- Regular Expressions
+ *     UCW Library -- Interface to Regular Expression Libraries
  *
  *
- *     (c) 1997 Martin Mares <mj@ucw.cz>
+ *     (c) 1997--2004 Martin Mares <mj@ucw.cz>
  *     (c) 2001 Robert Spalek <robert@ucw.cz>
  *     (c) 2001 Robert Spalek <robert@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
  */
 
 #include "lib/lib.h"
 #include "lib/chartype.h"
  */
 
 #include "lib/lib.h"
 #include "lib/chartype.h"
+#include "lib/hashfunc.h"
 
 #include <stdio.h>
 #include <string.h>
 
 #include <stdio.h>
 #include <string.h>
-#include <stdlib.h>
+
+#if defined(CONFIG_OWN_REGEX) || defined(CONFIG_POSIX_REGEX)
+
+/* POSIX regular expression library */
+
+#ifdef CONFIG_OWN_REGEX
+#include "lib/regex/regex-sh.h"
+#else
+#include <regex.h>
+#endif
+
+struct regex {
+  regex_t rx;
+  regmatch_t matches[10];
+};
+
+regex *
+rx_compile(const char *p, int icase)
+{
+  regex *r = xmalloc_zero(sizeof(regex));
+
+  int err = regcomp(&r->rx, p, REG_EXTENDED | (icase ? REG_ICASE : 0));
+  if (err)
+    {
+      char msg[256];
+      regerror(err, &r->rx, msg, sizeof(msg)-1);
+      /* regfree(&r->rx) not needed */
+      die("Error parsing regular expression `%s': %s", p, msg);
+    }
+  return r;
+}
+
+void
+rx_free(regex *r)
+{
+  regfree(&r->rx);
+  xfree(r);
+}
+
+int
+rx_match(regex *r, const char *s)
+{
+  int err = regexec(&r->rx, s, 10, r->matches, 0);
+  if (!err)
+    {
+      /* regexec doesn't support anchored expressions, so we have to check ourselves that the full string is matched */
+      return !(r->matches[0].rm_so || s[r->matches[0].rm_eo]);
+    }
+  else if (err == REG_NOMATCH)
+    return 0;
+  else if (err == REG_ESPACE)
+    die("Regex matching ran out of memory");
+  else
+    die("Regex matching failed with unknown error %d", err);
+}
+
+int
+rx_subst(regex *r, const char *by, const char *src, char *dest, uns destlen)
+{
+  char *end = dest + destlen - 1;
+
+  if (!rx_match(r, src))
+    return 0;
+
+  while (*by)
+    {
+      if (*by == '\\')
+       {
+         by++;
+         if (*by >= '0' && *by <= '9') /* \0 gets replaced by entire pattern */
+           {
+             uns j = *by++ - '0';
+             if (j <= r->rx.re_nsub && r->matches[j].rm_so >= 0)
+               {
+                 const char *s = src + r->matches[j].rm_so;
+                 uns i = r->matches[j].rm_eo - r->matches[j].rm_so;
+                 if (dest + i >= end)
+                   return -1;
+                 memcpy(dest, s, i);
+                 dest += i;
+                 continue;
+               }
+           }
+       }
+      if (dest < end)
+       *dest++ = *by++;
+      else
+       return -1;
+    }
+  *dest = 0;
+  return 1;
+}
+
+#elif defined(CONFIG_PCRE)
+
+/* PCRE library */
+
+#include <pcre.h>
+
+struct regex {
+  pcre *rx;
+  pcre_extra *extra;
+  uns match_array_size;
+  uns real_matches;
+  int matches[0];                      /* (max_matches+1) pairs (pos,len) plus some workspace */
+};
+
+regex *
+rx_compile(const char *p, int icase)
+{
+  const char *err;
+  int errpos, match_array_size, eno;
+
+  pcre *rx = pcre_compile(p, PCRE_ANCHORED | PCRE_EXTRA | (icase ? PCRE_CASELESS : 0), &err, &errpos, NULL);
+  if (!rx)
+    die("Error parsing regular expression `%s': %s at position %d", p, err, errpos);
+  eno = pcre_fullinfo(rx, NULL, PCRE_INFO_CAPTURECOUNT, &match_array_size);
+  if (eno)
+    die("Internal error: pcre_fullinfo() failed with error %d", eno);
+  match_array_size = 3*(match_array_size+1);
+  regex *r = xmalloc_zero(sizeof(regex) + match_array_size * sizeof(int));
+  r->rx = rx;
+  r->match_array_size = match_array_size;
+  r->extra = pcre_study(r->rx, 0, &err);
+  if (err)
+    die("Error studying regular expression `%s': %s", p, err);
+  return r;
+}
+
+void
+rx_free(regex *r)
+{
+  xfree(r->rx);
+  xfree(r->extra);
+  xfree(r);
+}
+
+int
+rx_match(regex *r, const char *s)
+{
+  int len = str_len(s);
+  int err = pcre_exec(r->rx, r->extra, s, len, 0, 0, r->matches, r->match_array_size);
+  if (err >= 0)
+    {
+      r->real_matches = err;
+      /* need to check that the full string matches */
+      return !(r->matches[0] || s[r->matches[1]]);
+    }
+  else if (err == PCRE_ERROR_NOMATCH)
+    return 0;
+  else if (err == PCRE_ERROR_NOMEMORY)
+    die("Regex matching ran out of memory");
+  else
+    die("Regex matching failed with unknown error %d", err);
+}
+
+int
+rx_subst(regex *r, const char *by, const char *src, char *dest, uns destlen)
+{
+  char *end = dest + destlen - 1;
+
+  if (!rx_match(r, src))
+    return 0;
+
+  while (*by)
+    {
+      if (*by == '\\')
+       {
+         by++;
+         if (*by >= '0' && *by <= '9') /* \0 gets replaced by entire pattern */
+           {
+             uns j = *by++ - '0';
+             if (j < r->real_matches && r->matches[2*j] >= 0)
+               {
+                 char *s = src + r->matches[2*j];
+                 uns i = r->matches[2*j+1] - r->matches[2*j];
+                 if (dest + i >= end)
+                   return -1;
+                 memcpy(dest, s, i);
+                 dest += i;
+                 continue;
+               }
+           }
+       }
+      if (dest < end)
+       *dest++ = *by++;
+      else
+       return -1;
+    }
+  *dest = 0;
+  return 1;
+}
+
+#else
+
+/* BSD regular expression library */
+
+#ifdef CONFIG_OWN_BSD_REGEX
+#include "lib/regex/regex-sh.h"
+#else
 #include <regex.h>
 #include <regex.h>
+#endif
 
 #define INITIAL_MEM 1024               /* Initial space allocated for each pattern */
 #define CHAR_SET_SIZE 256              /* How many characters in the character set.  */
 
 #define INITIAL_MEM 1024               /* Initial space allocated for each pattern */
 #define CHAR_SET_SIZE 256              /* How many characters in the character set.  */
@@ -23,7 +227,7 @@ struct regex {
 };
 
 regex *
 };
 
 regex *
-rx_compile(byte *p, int icase)
+rx_compile(const char *p, int icase)
 {
   regex *r = xmalloc_zero(sizeof(regex));
   const char *msg;
 {
   regex *r = xmalloc_zero(sizeof(regex));
   const char *msg;
@@ -57,7 +261,7 @@ rx_free(regex *r)
 }
 
 int
 }
 
 int
-rx_match(regex *r, byte *s)
+rx_match(regex *r, const char *s)
 {
   int len = strlen(s);
 
 {
   int len = strlen(s);
 
@@ -70,9 +274,9 @@ rx_match(regex *r, byte *s)
 }
 
 int
 }
 
 int
-rx_subst(regex *r, byte *by, byte *src, byte *dest, uns destlen)
+rx_subst(regex *r, const char *by, const char *src, char *dest, uns destlen)
 {
 {
-  byte *end = dest + destlen - 1;
+  char *end = dest + destlen - 1;
 
   if (!rx_match(r, src))
     return 0;
 
   if (!rx_match(r, src))
     return 0;
@@ -87,7 +291,7 @@ rx_subst(regex *r, byte *by, byte *src, byte *dest, uns destlen)
              uns j = *by++ - '0';
              if (j < r->regs.num_regs)
                {
              uns j = *by++ - '0';
              if (j < r->regs.num_regs)
                {
-                 byte *s = src + r->regs.start[j];
+                 const char *s = src + r->regs.start[j];
                  uns i = r->regs.end[j] - r->regs.start[j];
                  if (r->regs.start[j] > r->len_cache || r->regs.end[j] > r->len_cache)
                    return -1;
                  uns i = r->regs.end[j] - r->regs.start[j];
                  if (r->regs.start[j] > r->len_cache || r->regs.end[j] > r->len_cache)
                    return -1;
@@ -108,14 +312,23 @@ rx_subst(regex *r, byte *by, byte *src, byte *dest, uns destlen)
   return 1;
 }
 
   return 1;
 }
 
+#endif
+
 #ifdef TEST
 
 #ifdef TEST
 
-void main(int argc, char **argv)
+int main(int argc, char **argv)
 {
   regex *r;
 {
   regex *r;
-  byte buf1[256], buf2[256];
+  char buf1[4096], buf2[4096];
+  int opt_i = 0;
 
 
-  r = rx_compile(argv[1]);
+  if (!strcmp(argv[1], "-i"))
+    {
+      opt_i = 1;
+      argv++;
+      argc--;
+    }
+  r = rx_compile(argv[1], opt_i);
   while (fgets(buf1, sizeof(buf1), stdin))
     {
       char *p = strchr(buf1, '\n');
   while (fgets(buf1, sizeof(buf1), stdin))
     {
       char *p = strchr(buf1, '\n');