[augeas-devel] [PATCH 3/8] Add fa_expand_nocase to libfa

lutter at redhat.com lutter at redhat.com
Wed Jan 13 18:40:40 UTC 2010


From: David Lutterkort <lutter at redhat.com>

---
 src/fa.c           |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/fa.h           |   13 +++++++
 src/fa_sym.version |    1 +
 tests/fatest.c     |   22 +++++++++++++
 4 files changed, 126 insertions(+), 0 deletions(-)

diff --git a/src/fa.c b/src/fa.c
index 11e70a1..6d2f8ca 100644
--- a/src/fa.c
+++ b/src/fa.c
@@ -4110,6 +4110,96 @@ int fa_expand_char_ranges(const char *regexp, size_t regexp_len,
     return result;
 }
 
+/* Expand regexp so that it is case-insensitive in a case-sensitive match.
+ *
+ * Return 1 when a change was made, -1 when an allocation failed, and 0
+ * when no change was made.
+ */
+static int re_case_expand(struct re *re) {
+    int result = 0, r1, r2;
+
+    switch(re->type) {
+    case UNION:
+    case CONCAT:
+        r1 = re_case_expand(re->exp1);
+        r2 = re_case_expand(re->exp2);
+        result = (r1 != 0) ? r1 : r2;
+        break;
+    case CSET:
+        for (int c = 'A'; c <= 'Z'; c++)
+            if (bitset_get(re->cset, c)) {
+                result = 1;
+                bitset_set(re->cset, tolower(c));
+            }
+        for (int c = 'a'; c <= 'z'; c++)
+            if (bitset_get(re->cset, c)) {
+                result = 1;
+                bitset_set(re->cset, toupper(c));
+            }
+        break;
+    case CHAR:
+        if (isalpha(re->c)) {
+            int c = re->c;
+            re->type = CSET;
+            re->negate = false;
+            re->no_ranges = 0;
+            re->cset = bitset_init(UCHAR_NUM);
+            if (re->cset == NULL)
+                return -1;
+            bitset_set(re->cset, tolower(c));
+            bitset_set(re->cset, toupper(c));
+            result = 1;
+        }
+        break;
+    case ITER:
+        result = re_case_expand(re->exp);
+        break;
+    case EPSILON:
+        break;
+    default:
+        assert(0);
+        abort();
+        break;
+    }
+    return result;
+}
+
+int fa_expand_nocase(const char *regexp, size_t regexp_len,
+                     char **newregexp, size_t *newregexp_len) {
+    int result, r;
+    struct re *re = NULL;
+    struct re_parse parse;
+    struct re_str str;
+
+    *newregexp = NULL;
+    MEMZERO(&parse, 1);
+    parse.rx = regexp;
+    parse.rend = regexp + regexp_len;
+    parse.error = REG_NOERROR;
+    re = parse_regexp(&parse);
+    if (parse.error != REG_NOERROR)
+        return parse.error;
+
+    r = re_case_expand(re);
+    if (r < 0) {
+        re_unref(re);
+        return REG_ESPACE;
+    }
+
+    if (r == 1) {
+        MEMZERO(&str, 1);
+        result = re_as_string(re, &str);
+        *newregexp = str.rx;
+        *newregexp_len = str.len;
+    } else {
+        *newregexp = strndup(regexp, regexp_len);
+        *newregexp_len = regexp_len;
+        result = (*newregexp == NULL) ? REG_ESPACE : REG_NOERROR;
+    }
+    re_unref(re);
+    return result;
+}
+
 static void print_char(FILE *out, uchar c) {
     /* We escape '/' as '\\/' since dot chokes on bare slashes in labels;
        Also, a space ' ' is shown as '\s' */
diff --git a/src/fa.h b/src/fa.h
index b9e08cf..e3c3a7b 100644
--- a/src/fa.h
+++ b/src/fa.h
@@ -241,6 +241,19 @@ int fa_nocase(struct fa *fa);
 
 /* Return 1 if FA matches ignoring case, 0 if matches are case sensitive */
 int fa_is_nocase(struct fa *fa);
+
+/* Assume REGEXP is a case-insensitive regular expression, and convert it
+ * to one that matches the same strings when used case sensitively. All
+ * occurrences of individual letters c in the regular expression will be
+ * replaced by character sets [cC], and lower/upper case characters are
+ * added to character sets as needed.
+ *
+ * Return a positive value if REGEXP is not syntactically valid; the value
+ * returned is one of the REG_ERRCODE_T POSIX error codes. Return 0 on
+ * success and -1 if an allocation fails.
+ */
+int fa_expand_nocase(const char *regexp, size_t regexp_len,
+                     char **newregexp, size_t *newregexp_len);
 #endif
 
 
diff --git a/src/fa_sym.version b/src/fa_sym.version
index 9101bdf..5d513e9 100644
--- a/src/fa_sym.version
+++ b/src/fa_sym.version
@@ -27,4 +27,5 @@ FA_1.0.0 {
 FA_1.2.0 {
       fa_nocase;
       fa_is_nocase;
+      fa_expand_nocase;
 } FA_1.0.0;
diff --git a/tests/fatest.c b/tests/fatest.c
index e4ece92..28e33b0 100644
--- a/tests/fatest.c
+++ b/tests/fatest.c
@@ -541,6 +541,27 @@ static void testNoCase(CuTest *tc) {
     CuAssertIntEquals(tc, 1, r);
 }
 
+static void testExpandNoCase(CuTest *tc) {
+    const char *p1 = "aB";
+    const char *p2 = "[a-cUV]";
+    const char *p3 = "[^a-z]";
+    char *s;
+    size_t len;
+    int r;
+
+    r = fa_expand_nocase(p1, strlen(p1), &s, &len);
+    CuAssertStrEquals(tc, "[Aa][Bb]", s);
+    free(s);
+
+    r = fa_expand_nocase(p2, strlen(p2), &s, &len);
+    CuAssertStrEquals(tc, "[A-CUVa-cuv]", s);
+    free(s);
+
+    r = fa_expand_nocase(p3, strlen(p3), &s, &len);
+    CuAssertStrEquals(tc, "[^A-Za-z]", s);
+    free(s);
+}
+
 int main(int argc, char **argv) {
     if (argc == 1) {
         char *output = NULL;
@@ -564,6 +585,7 @@ int main(int argc, char **argv) {
         SUITE_ADD_TEST(suite, testRestrictAlphabet);
         SUITE_ADD_TEST(suite, testExpandCharRanges);
         SUITE_ADD_TEST(suite, testNoCase);
+        SUITE_ADD_TEST(suite, testExpandNoCase);
 
         CuSuiteRun(suite);
         CuSuiteSummary(suite, &output);
-- 
1.6.5.2




More information about the augeas-devel mailing list