[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