Imported Upstream version 2.6.1
[debian/amanda] / common-src / match.c
index 6f94ab4d967a452fabb3d1b8685723126a3b323b..d8c83bcc7657ec16014ade4c0f35587bc4e20826 100644 (file)
  * file named AUTHORS, in the root directory of this distribution.
  */
 /*
- * $Id: match.c,v 1.10.4.1.4.1.2.4 2002/11/12 18:01:19 martinea Exp $
+ * $Id: match.c,v 1.23 2006/05/25 01:47:12 johnfranks Exp $
  *
  * functions for checking and matching regular expressions
  */
 
 #include "amanda.h"
-#include "regex.h"
+#include <regex.h>
 
-char *validate_regexp(regex)
-char *regex;
+static int match_word(const char *glob, const char *word, const char separator);
+
+char *
+validate_regexp(
+    const char *       regex)
 {
     regex_t regc;
     int result;
@@ -41,7 +44,7 @@ char *regex;
 
     if ((result = regcomp(&regc, regex,
                          REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
-      regerror(result, &regc, errmsg, sizeof(errmsg));
+      regerror(result, &regc, errmsg, SIZEOF(errmsg));
       return errmsg;
     }
 
@@ -50,8 +53,9 @@ char *regex;
     return NULL;
 }
 
-char *clean_regex(regex)
-char *regex;
+char *
+clean_regex(
+    const char *       regex)
 {
     char *result;
     int j;
@@ -63,12 +67,14 @@ char *regex;
            result[j++]='\\';
        result[j++]=regex[i];
     }
-    result[j++] = '\0';
+    result[j] = '\0';
     return result;
 }
 
-int match(regex, str)
-char *regex, *str;
+int
+match(
+    const char *       regex,
+    const char *       str)
 {
     regex_t regc;
     int result;
@@ -76,14 +82,16 @@ char *regex, *str;
 
     if((result = regcomp(&regc, regex,
                         REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
-        regerror(result, &regc, errmsg, sizeof(errmsg));
-       error("regex \"%s\": %s", regex, errmsg);
+        regerror(result, &regc, errmsg, SIZEOF(errmsg));
+       error(_("regex \"%s\": %s"), regex, errmsg);
+       /*NOTREACHED*/
     }
 
     if((result = regexec(&regc, str, 0, 0, 0)) != 0
        && result != REG_NOMATCH) {
-        regerror(result, &regc, errmsg, sizeof(errmsg));
-       error("regex \"%s\": %s", regex, errmsg);
+        regerror(result, &regc, errmsg, SIZEOF(errmsg));
+       error(_("regex \"%s\": %s"), regex, errmsg);
+       /*NOTREACHED*/
     }
 
     regfree(&regc);
@@ -91,10 +99,39 @@ char *regex, *str;
     return result == 0;
 }
 
-char *validate_glob(glob)
-char *glob;
+int
+match_no_newline(
+    const char *       regex,
+    const char *       str)
 {
-    char *regex = NULL;
+    regex_t regc;
+    int result;
+    char errmsg[STR_SIZE];
+
+    if((result = regcomp(&regc, regex,
+                        REG_EXTENDED|REG_NOSUB)) != 0) {
+        regerror(result, &regc, errmsg, SIZEOF(errmsg));
+       error(_("regex \"%s\": %s"), regex, errmsg);
+       /*NOTREACHED*/
+    }
+
+    if((result = regexec(&regc, str, 0, 0, 0)) != 0
+       && result != REG_NOMATCH) {
+        regerror(result, &regc, errmsg, SIZEOF(errmsg));
+       error(_("regex \"%s\": %s"), regex, errmsg);
+       /*NOTREACHED*/
+    }
+
+    regfree(&regc);
+
+    return result == 0;
+}
+
+char *
+validate_glob(
+    const char *       glob)
+{
+    char *regex;
     regex_t regc;
     int result;
     static char errmsg[STR_SIZE];
@@ -102,7 +139,7 @@ char *glob;
     regex = glob_to_regex(glob);
     if ((result = regcomp(&regc, regex,
                          REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
-      regerror(result, &regc, errmsg, sizeof(errmsg));
+      regerror(result, &regc, errmsg, SIZEOF(errmsg));
       amfree(regex);
       return errmsg;
     }
@@ -113,10 +150,12 @@ char *glob;
     return NULL;
 }
 
-int match_glob(glob, str)
-char *glob, *str;
+int
+match_glob(
+    const char *       glob,
+    const char *       str)
 {
-    char *regex = NULL;
+    char *regex;
     regex_t regc;
     int result;
     char errmsg[STR_SIZE];
@@ -124,16 +163,16 @@ char *glob, *str;
     regex = glob_to_regex(glob);
     if((result = regcomp(&regc, regex,
                         REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
-        regerror(result, &regc, errmsg, sizeof(errmsg));
-       amfree(regex);
-       error("glob \"%s\" -> regex \"%s\": %s", glob, regex, errmsg);
+        regerror(result, &regc, errmsg, SIZEOF(errmsg));
+       error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
+       /*NOTREACHED*/
     }
 
     if((result = regexec(&regc, str, 0, 0, 0)) != 0
        && result != REG_NOMATCH) {
-        regerror(result, &regc, errmsg, sizeof(errmsg));
-       amfree(regex);
-       error("glob \"%s\" -> regex \"%s\": %s", glob, regex, errmsg);
+        regerror(result, &regc, errmsg, SIZEOF(errmsg));
+       error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
+       /*NOTREACHED*/
     }
 
     regfree(&regc);
@@ -142,8 +181,9 @@ char *glob, *str;
     return result == 0;
 }
 
-char *glob_to_regex(glob)
-char *glob;
+char *
+glob_to_regex(
+    const char *       glob)
 {
     char *regex;
     char *r;
@@ -180,12 +220,12 @@ char *glob;
     last_ch = '\0';
     for (ch = *glob++; ch != '\0'; last_ch = ch, ch = *glob++) {
        if (last_ch == '\\') {
-           *r++ = ch;
+           *r++ = (char)ch;
            ch = '\0';                  /* so last_ch != '\\' next time */
        } else if (last_ch == '[' && ch == '!') {
            *r++ = '^';
        } else if (ch == '\\') {
-           *r++ = ch;
+           *r++ = (char)ch;
        } else if (ch == '*' || ch == '?') {
            *r++ = '[';
            *r++ = '^';
@@ -204,9 +244,9 @@ char *glob;
                   || ch == '$'
                   || ch == '|') {
            *r++ = '\\';
-           *r++ = ch;
+           *r++ = (char)ch;
        } else {
-           *r++ = ch;
+           *r++ = (char)ch;
        }
     }
     if (last_ch != '\\') {
@@ -218,9 +258,119 @@ char *glob;
 }
 
 
-int match_word(glob, word, separator)
-char *glob, *word;
-char separator;
+int
+match_tar(
+    const char *       glob,
+    const char *       str)
+{
+    char *regex;
+    regex_t regc;
+    int result;
+    char errmsg[STR_SIZE];
+
+    regex = tar_to_regex(glob);
+    if((result = regcomp(&regc, regex,
+                        REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
+        regerror(result, &regc, errmsg, SIZEOF(errmsg));
+       error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
+       /*NOTREACHED*/
+    }
+
+    if((result = regexec(&regc, str, 0, 0, 0)) != 0
+       && result != REG_NOMATCH) {
+        regerror(result, &regc, errmsg, SIZEOF(errmsg));
+       error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
+       /*NOTREACHED*/
+    }
+
+    regfree(&regc);
+    amfree(regex);
+
+    return result == 0;
+}
+
+char *
+tar_to_regex(
+    const char *       glob)
+{
+    char *regex;
+    char *r;
+    size_t len;
+    int ch;
+    int last_ch;
+
+    /*
+     * Allocate an area to convert into.  The worst case is a five to
+     * one expansion.
+     */
+    len = strlen(glob);
+    regex = alloc(1 + len * 5 + 1 + 1);
+
+    /*
+     * Do the conversion:
+     *
+     *  ?      -> [^/]
+     *  *      -> .*
+     *  [!...] -> [^...]
+     *
+     * The following are given a leading backslash to protect them
+     * unless they already have a backslash:
+     *
+     *   ( ) { } + . ^ $ |
+     *
+     * Put a leading ^ and trailing $ around the result.  If the last
+     * non-escaped character is \ leave the $ off to cause a syntax
+     * error when the regex is compiled.
+     */
+
+    r = regex;
+    *r++ = '^';
+    last_ch = '\0';
+    for (ch = *glob++; ch != '\0'; last_ch = ch, ch = *glob++) {
+       if (last_ch == '\\') {
+           *r++ = (char)ch;
+           ch = '\0';                  /* so last_ch != '\\' next time */
+       } else if (last_ch == '[' && ch == '!') {
+           *r++ = '^';
+       } else if (ch == '\\') {
+           *r++ = (char)ch;
+       } else if (ch == '*') {
+           *r++ = '.';
+           *r++ = '*';
+       } else if (ch == '?') {
+           *r++ = '[';
+           *r++ = '^';
+           *r++ = '/';
+           *r++ = ']';
+       } else if (ch == '('
+                  || ch == ')'
+                  || ch == '{'
+                  || ch == '}'
+                  || ch == '+'
+                  || ch == '.'
+                  || ch == '^'
+                  || ch == '$'
+                  || ch == '|') {
+           *r++ = '\\';
+           *r++ = (char)ch;
+       } else {
+           *r++ = (char)ch;
+       }
+    }
+    if (last_ch != '\\') {
+       *r++ = '$';
+    }
+    *r = '\0';
+
+    return regex;
+}
+
+
+static int
+match_word(
+    const char *       glob,
+    const char *       word,
+    const char         separator)
 {
     char *regex;
     char *r;
@@ -231,7 +381,8 @@ char separator;
     size_t  lenword;
     char *nword;
     char *nglob;
-    char *g, *w;
+    char *g; 
+    const char *w;
     int  i;
 
     lenword = strlen(word);
@@ -309,12 +460,12 @@ char separator;
        for (ch = *g++; ch != '\0'; last_ch = ch, ch = *g++) {
            next_ch = *g;
            if (last_ch == '\\') {
-               *r++ = ch;
+               *r++ = (char)ch;
                ch = '\0';              /* so last_ch != '\\' next time */
            } else if (last_ch == '[' && ch == '!') {
                *r++ = '^';
            } else if (ch == '\\') {
-               *r++ = ch;
+               *r++ = (char)ch;
            } else if (ch == '*' || ch == '?') {
                if(ch == '*' && next_ch == '*') {
                    *r++ = '.';
@@ -335,7 +486,7 @@ char separator;
                    *r++ = '\\';
                    *r++ = separator;
                }
-               *r++ = ch;
+               *r++ = (char)ch;
            } else if (   ch == '('
                       || ch == ')'
                       || ch == '{'
@@ -346,9 +497,9 @@ char separator;
                       || ch == '$'
                       || ch == '|') {
                *r++ = '\\';
-               *r++ = ch;
+               *r++ = (char)ch;
            } else {
-               *r++ = ch;
+               *r++ = (char)ch;
            }
        }
        if(last_ch != '\\') {
@@ -369,93 +520,118 @@ char separator;
 }
 
 
-int match_host(glob, host)
-char *glob, *host;
+int
+match_host(
+    const char *       glob,
+    const char *       host)
 {
     char *lglob, *lhost;
-    char *c, *d;
+    char *c;
+    const char *d;
     int i;
 
     
     lglob = (char *)alloc(strlen(glob)+1);
     c = lglob, d=glob;
     while( *d != '\0')
-       *c++ = tolower(*d++);
+       *c++ = (char)tolower(*d++);
     *c = *d;
 
     lhost = (char *)alloc(strlen(host)+1);
     c = lhost, d=host;
     while( *d != '\0')
-       *c++ = tolower(*d++);
+       *c++ = (char)tolower(*d++);
     *c = *d;
 
-    i = match_word(lglob, lhost, '.');
+    i = match_word(lglob, lhost, (int)'.');
     amfree(lglob);
     amfree(lhost);
     return i;
 }
 
 
-int match_disk(glob, disk)
-char *glob, *disk;
+int
+match_disk(
+    const char *       glob,
+    const char *       disk)
 {
-    int i;
-    i = match_word(glob, disk, '/');
-    return i;
+    return match_word(glob, disk, '/');
 }
 
-int match_datestamp(dateexp, datestamp)
-char *dateexp, *datestamp;
+static int
+alldigits(
+    const char *str)
+{
+    while (*str) {
+       if (!isdigit((int)*(str++)))
+           return 0;
+    }
+    return 1;
+}
+
+int
+match_datestamp(
+    const char *       dateexp,
+    const char *       datestamp)
 {
     char *dash;
     size_t len, len_suffix;
-    int len_prefix;
+    size_t len_prefix;
     char firstdate[100], lastdate[100];
     char mydateexp[100];
     int match_exact;
 
     if(strlen(dateexp) >= 100 || strlen(dateexp) < 1) {
-       error("Illegal datestamp expression %s",dateexp);
+       goto illegal;
     }
    
+    /* strip and ignore an initial "^" */
     if(dateexp[0] == '^') {
-       strncpy(mydateexp, dateexp+1, strlen(dateexp)-1); 
-       mydateexp[strlen(dateexp)-1] = '\0';
+       strncpy(mydateexp, dateexp+1, sizeof(mydateexp)-1);
+       mydateexp[sizeof(mydateexp)-1] = '\0';
     }
     else {
-       strncpy(mydateexp, dateexp, strlen(dateexp));
-       mydateexp[strlen(dateexp)] = '\0';
+       strncpy(mydateexp, dateexp, sizeof(mydateexp)-1);
+       mydateexp[sizeof(mydateexp)-1] = '\0';
     }
 
-    if(mydateexp[strlen(mydateexp)] == '$') {
+    if(mydateexp[strlen(mydateexp)-1] == '$') {
        match_exact = 1;
-       mydateexp[strlen(mydateexp)] = '\0';
+       mydateexp[strlen(mydateexp)-1] = '\0';  /* strip the trailing $ */
     }
     else
        match_exact = 0;
 
+    /* a single dash represents a date range */
     if((dash = strchr(mydateexp,'-'))) {
-       if(match_exact == 1) {
-           error("Illegal datestamp expression %s",dateexp);
+       if(match_exact == 1 || strchr(dash+1, '-')) {
+           goto illegal;
        }
-       len = dash - mydateexp;
-       len_suffix = strlen(dash) - 1;
-       len_prefix = len - len_suffix;
 
-       if(len_prefix < 0) {
-           error("Illegal datestamp expression %s",dateexp);
-       }
+       /* format: XXXYYYY-ZZZZ, indicating dates XXXYYYY to XXXZZZZ */
+
+       len = (size_t)(dash - mydateexp);   /* length of XXXYYYY */
+       len_suffix = strlen(dash) - 1;  /* length of ZZZZ */
+       if (len_suffix > len) goto illegal;
+       len_prefix = len - len_suffix; /* length of XXX */
 
        dash++;
+
        strncpy(firstdate, mydateexp, len);
        firstdate[len] = '\0';
        strncpy(lastdate, mydateexp, len_prefix);
        strncpy(&(lastdate[len_prefix]), dash, len_suffix);
        lastdate[len] = '\0';
+       if (!alldigits(firstdate) || !alldigits(lastdate))
+           goto illegal;
+       if (strncmp(firstdate, lastdate, strlen(firstdate)) > 0)
+           goto illegal;
        return ((strncmp(datestamp, firstdate, strlen(firstdate)) >= 0) &&
                (strncmp(datestamp, lastdate , strlen(lastdate))  <= 0));
     }
     else {
+       if (!alldigits(mydateexp))
+           goto illegal;
        if(match_exact == 1) {
            return (strcmp(datestamp, mydateexp) == 0);
        }
@@ -463,4 +639,69 @@ char *dateexp, *datestamp;
            return (strncmp(datestamp, mydateexp, strlen(mydateexp)) == 0);
        }
     }
+illegal:
+       error(_("Illegal datestamp expression %s"),dateexp);
+       /*NOTREACHED*/
+}
+
+
+int
+match_level(
+    const char *       levelexp,
+    const char *       level)
+{
+    char *dash;
+    size_t len, len_suffix;
+    size_t len_prefix;
+    char lowend[100], highend[100];
+    char mylevelexp[100];
+    int match_exact;
+
+    if(strlen(levelexp) >= 100 || strlen(levelexp) < 1) {
+       error(_("Illegal level expression %s"),levelexp);
+       /*NOTREACHED*/
+    }
+   
+    if(levelexp[0] == '^') {
+       strncpy(mylevelexp, levelexp+1, strlen(levelexp)-1); 
+       mylevelexp[strlen(levelexp)-1] = '\0';
+    }
+    else {
+       strncpy(mylevelexp, levelexp, strlen(levelexp));
+       mylevelexp[strlen(levelexp)] = '\0';
+    }
+
+    if(mylevelexp[strlen(mylevelexp)] == '$') {
+       match_exact = 1;
+       mylevelexp[strlen(mylevelexp)] = '\0';
+    }
+    else
+       match_exact = 0;
+
+    if((dash = strchr(mylevelexp,'-'))) {
+       if(match_exact == 1) {
+           error(_("Illegal level expression %s"),levelexp);
+           /*NOTREACHED*/
+       }
+       len = (size_t)(dash - mylevelexp);
+       len_suffix = strlen(dash) - 1;
+       len_prefix = len - len_suffix;
+
+       dash++;
+       strncpy(lowend, mylevelexp, len);
+       lowend[len] = '\0';
+       strncpy(highend, mylevelexp, len_prefix);
+       strncpy(&(highend[len_prefix]), dash, len_suffix);
+       highend[len] = '\0';
+       return ((strncmp(level, lowend, strlen(lowend)) >= 0) &&
+               (strncmp(level, highend , strlen(highend))  <= 0));
+    }
+    else {
+       if(match_exact == 1) {
+           return (strcmp(level, mylevelexp) == 0);
+       }
+       else {
+           return (strncmp(level, mylevelexp, strlen(mylevelexp)) == 0);
+       }
+    }
 }