Added SILC_REGEX_NOTBOL and SILC_REGEX_NOTEOL flags.
[crypto.git] / lib / silcutil / silcregex.c
index c11ea8ad726040278e3976e34efaa12e0a3655c2..1412f20d0dd192394c3af0927b10341abe627931 100644 (file)
@@ -25,8 +25,8 @@
   Emacs-specific code and syntax table code is almost directly borrowed
   from GNU regexp.
 
-  The SILC Regex API by Pekka Riikonen, under the same license as the original
-  code.
+  The SILC Regex API and modifications by Pekka Riikonen, under the same
+  license as the original code.
 
 */
 
@@ -34,7 +34,7 @@
 
 /* Modified for use in SILC Runtime Toolkit.  I think we have disabled many
    features we could use, for the sake of simple API, which we may want to
-   extend later. */
+   extend later.  But, we've added RE_NOTBOL and RE_NOTEOL. */
 
 #define RE_NREGS       128     /* number of registers available */
 
@@ -47,6 +47,8 @@
 #define RE_CONTEXT_INDEP_OPS   32   /* ^$?*+ are special in all contexts */
 #define RE_ANSI_HEX            64   /* ansi sequences (\n etc) and \xhh */
 #define RE_NO_GNU_EXTENSIONS   128   /* no gnu extensions */
+#define RE_NOTBOL              256   /* bol fails to match */
+#define RE_NOTEOL              512   /* eol fails to match */
 
 /* definitions for some common regexp styles */
 #define RE_SYNTAX_AWK  (RE_NO_BK_PARENS|RE_NO_BK_VBAR|RE_CONTEXT_INDEP_OPS)
@@ -74,22 +76,22 @@ SilcResult re_compile_pattern(char *regex, int regex_size, SilcRegex compiled);
    translation table, or NULL if it is not used. */
 
 int re_match(SilcRegex compiled, char *string, int size, int pos,
-            regexp_registers_t regs);
+            regexp_registers_t regs, unsigned int flags);
 /* This tries to match the regexp against the string.  This returns the
    length of the matched portion, or -1 if the pattern could not be
    matched and -2 if an error (such as failure stack overflow) is
    encountered. */
 
 int re_match_2(SilcRegex compiled, char *string1, int size1,
-             char *string2, int size2, int pos, regexp_registers_t regs,
-              int mstop);
+              char *string2, int size2, int pos, regexp_registers_t regs,
+              int mstop, unsigned int flags);
 /* This tries to match the regexp to the concatenation of string1 and
    string2.  This returns the length of the matched portion, or -1 if the
    pattern could not be matched and -2 if an error (such as failure stack
    overflow) is encountered. */
 
 int re_search(SilcRegex compiled, char *string, int size, int startpos,
-             int range, regexp_registers_t regs);
+             int range, regexp_registers_t regs, unsigned int flags);
 /* This rearches for a substring matching the regexp.  This returns the first
    index at which a match is found.  range specifies at how many positions to
    try matching; positive values indicate searching forwards, and negative
@@ -99,7 +101,7 @@ int re_search(SilcRegex compiled, char *string, int size, int startpos,
 
 int re_search_2(SilcRegex compiled, char *string1, int size1,
                char *string2, int size2, int startpos, int range,
-               regexp_registers_t regs, int mstop);
+               regexp_registers_t regs, int mstop, unsigned int flags);
 /* This is like re_search, but search from the concatenation of string1 and
    string2.  */
 
@@ -973,11 +975,12 @@ SilcRegex bufp;
 #define INITIAL_FAILURES  128  /* initial # failure points to allocate */
 #define MAX_FAILURES     4100  /* max # of failure points before failing */
 
-int re_match_2(bufp, string1, size1, string2, size2, pos, regs, mstop)
+int re_match_2(bufp, string1, size1, string2, size2, pos, regs, mstop, flags)
 SilcRegex bufp;
 char *string1, *string2;
 int size1, size2, pos, mstop;
 regexp_registers_t regs;
+unsigned int flags;
 {
   struct failure_point { char *text, *partend, *code; }
     *failure_stack_start, *failure_sp, *failure_stack_end,
@@ -1101,15 +1104,21 @@ regexp_registers_t regs;
            silc_free((char *)failure_stack_start);
          return match_end - pos;
        case Cbol:
-         if (text == string1 || text[-1] == '\n') /* text[-1] always valid */
+         if (text == string1 || text[-1] == '\n') { /* text[-1] always valid */
+           if (flags & RE_NOTBOL)
+             goto fail;
            break;
+         }
          goto fail;
        case Ceol:
          if (text == string2 + size2 ||
              (text == string1 + size1 ?
               (size2 == 0 || *string2 == '\n') :
-              *text == '\n'))
+              *text == '\n')) {
+           if (flags & RE_NOTEOL)
+             goto fail;
            break;
+         }
          goto fail;
        case Cset:
          NEXTCHAR(ch);
@@ -1436,21 +1445,24 @@ regexp_registers_t regs;
 #undef NEXTCHAR
 #undef PUSH_FAILURE
 
-int re_match(bufp, string, size, pos, regs)
+int re_match(bufp, string, size, pos, regs, flags)
 SilcRegex bufp;
 char *string;
 int size, pos;
 regexp_registers_t regs;
+unsigned int flags;
 {
-  return re_match_2(bufp, string, size, (char *)NULL, 0, pos, regs, size);
+  return re_match_2(bufp, string, size, (char *)NULL, 0, pos, regs, size,
+                   flags);
 }
 
 int re_search_2(bufp, string1, size1, string2, size2, pos, range, regs,
-               mstop)
+               mstop, flags)
 SilcRegex bufp;
 char *string1, *string2;
 int size1, size2, pos, range, mstop;
 regexp_registers_t regs;
+unsigned int flags;
 {
   char *fastmap, *translate, *text, *partstart, *partend;
   int dir, ret;
@@ -1550,7 +1562,8 @@ regexp_registers_t regs;
            continue;
        }
       assert(pos >= 0 && pos <= size1 + size2);
-      ret = re_match_2(bufp, string1, size1, string2, size2, pos, regs, mstop);
+      ret = re_match_2(bufp, string1, size1, string2, size2, pos, regs, mstop,
+                      flags);
       if (ret >= 0)
        return pos;
       if (ret == -2)
@@ -1559,14 +1572,15 @@ regexp_registers_t regs;
   return -1;
 }
 
-int re_search(bufp, string, size, startpos, range, regs)
+int re_search(bufp, string, size, startpos, range, regs, flags)
 SilcRegex bufp;
 char *string;
 int size, startpos, range;
 regexp_registers_t regs;
+unsigned int flags;
 {
   return re_search_2(bufp, string, size, (char *)NULL, 0,
-                    startpos, range, regs, size);
+                    startpos, range, regs, size, flags);
 }
 
 /****************************** SILC Regex API ******************************/
@@ -1601,11 +1615,12 @@ SilcBool silc_regex_compile(SilcRegex regexp, const char *regex,
 /* Match compiled regular expression */
 
 SilcBool silc_regex_match(SilcRegex regexp, const char *string,
-                         SilcUInt32 num_match, SilcRegexMatch match,
-                         SilcRegexFlags flags)
+                         SilcUInt32 string_len, SilcUInt32 num_match,
+                         SilcRegexMatch match, SilcRegexFlags flags)
 {
   struct re_registers regs;
-  int ret, i, len = strlen(string);
+  unsigned int f = 0;
+  int ret, i;
 
   if (!regexp || !string) {
     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
@@ -1621,9 +1636,15 @@ SilcBool silc_regex_match(SilcRegex regexp, const char *string,
   if (num_match > RE_NREGS)
     num_match = RE_NREGS;
 
+  /* Set flags */
+  if (flags & SILC_REGEX_NOTBOL)
+    f |= RE_NOTBOL;
+  if (flags & SILC_REGEX_NOTEOL)
+    f |= RE_NOTEOL;
+
   /* Search */
-  ret = re_search(regexp, (char *)string, len, 0, len,
-                 num_match ? &regs : NULL);
+  ret = re_search(regexp, (char *)string, string_len, 0, string_len,
+                 num_match ? &regs : NULL, f);
   if (ret < 0) {
     if (ret == -2)
       silc_set_errno(SILC_ERR);
@@ -1648,3 +1669,108 @@ void silc_regex_free(SilcRegex regexp)
 {
   silc_free(regexp->buffer);
 }
+
+/* Match string */
+
+SilcBool silc_regex_va(const char *string, SilcUInt32 string_len,
+                      const char *regex, SilcBuffer match, va_list va)
+{
+  SilcRegexStruct reg;
+  SilcRegexMatch m = NULL;
+  SilcBuffer buf, *rets = NULL;
+  int i, c = 0;
+
+  /* Compile */
+  if (!silc_regex_compile(&reg, regex, 0))
+    return FALSE;
+
+  /* Get match pointers */
+  if (match) {
+    rets = silc_malloc(sizeof(*rets));
+    if (!rets)
+      return FALSE;
+    rets[c++] = match;
+
+    while ((buf = va_arg(va, SilcBuffer))) {
+      rets = silc_realloc(rets, (c + 1) * sizeof(*rets));
+      if (!rets)
+       return FALSE;
+      rets[c++] = buf;
+    }
+
+    m = silc_malloc(c * sizeof(*m));
+    if (!m) {
+      silc_free(rets);
+      return FALSE;
+    }
+  }
+
+  /* Match */
+  if (!silc_regex_match(&reg, string, string_len, c, m, 0)) {
+    silc_free(m);
+    silc_free(rets);
+    return FALSE;
+  }
+
+  /* Return matches */
+  for (i = 0; i < c; i++) {
+    if (m[i].start == -1)
+      continue;
+    silc_buffer_set(rets[i], (unsigned char *)string + m[i].start,
+                   m[i].end - m[i].start);
+  }
+
+  silc_free(m);
+  silc_free(rets);
+
+  return TRUE;
+}
+
+/* Match string */
+
+SilcBool silc_regex(const char *string, const char *regex,
+                   SilcBuffer match, ...)
+{
+  SilcBool ret;
+  va_list va;
+
+  if (!string || !regex) {
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+    return FALSE;
+  }
+
+  if (match)
+    va_start(va, match);
+
+  ret = silc_regex_va(string, strlen(string), regex, match, va);
+
+  if (match)
+    va_end(va);
+
+  return ret;
+}
+
+/* Match string */
+
+SilcBool silc_regex_buffer(SilcBuffer buffer, const char *regex,
+                          SilcBuffer match, ...)
+{
+  SilcBool ret;
+  va_list va;
+
+  if (!buffer || !regex) {
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+    return FALSE;
+  }
+
+  if (match)
+    va_start(va, match);
+
+  ret = silc_regex_va((const char *)silc_buffer_data(buffer),
+                     silc_buffer_len(buffer), regex, match, va);
+
+  if (match)
+    va_end(va);
+
+  return ret;
+}