[RFC] regular expression support in config files (try 2)

Oleh Nykyforchyn oleh.nyk at gmail.com
Tue May 31 11:05:58 PDT 2011


Finally seems to work. Hence:
-------------------------------

Add extended regexes support to InputClass Match* statements (try 2)
 
Any number of patterns can be written in one line either as
      MatchProduct "foo|!bar" "something|re:^else$" "you" "!regex:n..d"
or as
      MatchProduct "foo" "!bar|something" "regex:~else$" "you|!re:n..d"
etc. A regex ends at the end of the respective "piece", irrespective of '|'s.

Negated conditions prefixed by "!", regexes by "regex:" of "re:", can
be combined. All other modes can also be prefixed if someone misses them badly.
Place left for useful and useless enhancements.

Tested (not so heavy, but no obvious errors found). Comments, please.

Signed-off-by: Oleh Nykyforchyn <oleh.nyk at gmail.com>
---
 hw/xfree86/common/xf86Xinput.c |  131 +++++++------
 hw/xfree86/parser/InputClass.c |  418 +++++++++++++++++++++++++++++-----------
 hw/xfree86/parser/xf86Parser.h |   30 +++-
 3 files changed, 410 insertions(+), 169 deletions(-)

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 26051ad..09ae3d3 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -444,76 +444,95 @@ HostOS(void)
 }
 
 static int
-match_substring(const char *attr, const char *pattern)
+multi_match(const char *attr, xf86MatchPattern *pattern)
 {
-    return (strstr(attr, pattern)) ? 0 : -1;
-}
-
-#ifdef HAVE_FNMATCH_H
-static int
-match_pattern(const char *attr, const char *pattern)
-{
-    return fnmatch(pattern, attr, 0);
-}
-#else
-#define match_pattern match_substring
-#endif
+    if (!pattern) return 0;
 
+    switch (pattern->mode)
+    {
+        case MATCH_IS_INVALID:
+            return 0;
+        case MATCH_IS_STRCMP:
+            return (strcmp(attr, pattern->str)) ? 0 : -1;
+        case MATCH_IS_STRCASECMP:
+            return (strcasecmp(attr, pattern->str)) ? 0 : -1;
+        /*
+         * If no Layout section is found, xf86ServerLayout.id becomes "(implicit)"
+         * It is convenient that "" in patterns means "no explicit layout"
+         */
+        case MATCH_IS_STRIMPLICIT:
+            if (*(pattern->str))
+                return (strcmp(attr, pattern->str)) ? 0 : -1;
+            else
+                return (strcmp(attr, "(implicit)")) ? 0 : -1;
+        case MATCH_IS_STRSTR:
+            return (strstr(attr, pattern->str)) ? 0 : -1;
+        case MATCH_IS_STRCASESTR:
+            return (strcasestr(attr, pattern->str)) ? 0 : -1;
 #ifdef HAVE_FNMATCH_H
-static int
-match_path_pattern(const char *attr, const char *pattern)
-{
-    return fnmatch(pattern, attr, FNM_PATHNAME);
-}
+        case MATCH_IS_FILENAME:
+            return (fnmatch(attr, pattern->str, 0)) ? 0 : -1;
+        case MATCH_IS_PATHNAME:
+            return (fnmatch(attr, pattern->str, FNM_PATHNAME)) ? 0 : -1;
 #else
-#define match_path_pattern match_substring
+        case MATCH_IS_FILENAME:
+            return (strstr(attr, pattern->str)) ? 0 : -1;
+        case MATCH_IS_PATHNAME:
+            return (strstr(attr, pattern->str)) ? 0 : -1;
 #endif
-
-/*
- * If no Layout section is found, xf86ServerLayout.id becomes "(implicit)"
- * It is convenient that "" in patterns means "no explicit layout"
- */
-static int
-match_string_implicit(const char *attr, const char *pattern)
-{
-    if (strlen(pattern)) {
-        return strcmp(attr, pattern);
-    } else {
-        return strcmp(attr,"(implicit)");
+        case MATCH_IS_REGEX:
+        default:
+            if (pattern->regex == NULL) {
+                int r;
+                if ((pattern->regex = malloc(sizeof(regex_t))) == NULL) {
+                    pattern->mode = MATCH_IS_INVALID;
+                    return 0;
+                }
+                r = regcomp(pattern->regex, pattern->str, REG_EXTENDED | REG_NOSUB);
+                if (r) { /* Wrong regex */
+                    regfree(pattern->regex);
+                    xf86Msg(X_ERROR, "Wrong regex: \"%s\"\n", pattern->str);
+                    pattern->mode = MATCH_IS_INVALID;
+                    return 0;
+                }
+            }
+            return (regexec(pattern->regex, attr,0, NULL, 0)) ? 0 : -1;
     }
 }
 
 /*
- * Match an attribute against a list of NULL terminated arrays of patterns.
+ * Match an attribute against a list of xf86MatchGroup's
  * If a pattern in each list entry is matched, return TRUE.
  */
 static Bool
-MatchAttrToken(const char *attr, struct list *patterns,
-               int (*compare)(const char *attr, const char *pattern))
+MatchAttrToken(const char *attr, struct list *groups)
 {
-    const xf86MatchGroup *group;
-
-    /* If there are no patterns, accept the match */
-    if (list_is_empty(patterns))
+    xf86MatchGroup *group;
+    xf86MatchPattern *pattern;
+    
+    /* If there are no groups, accept the match */
+    if (list_is_empty(groups))
         return TRUE;
 
-    /* If there are patterns but no attribute, reject the match */
+    /* If there are groups but no attribute, reject the match */
     if (!attr)
         return FALSE;
 
     /*
-     * Otherwise, iterate the list of patterns ensuring each entry has a
+     * Otherwise, iterate the list of groups ensuring each entry has a
      * match. Each list entry is a separate Match line of the same type.
      */
-    list_for_each_entry(group, patterns, entry) {
-        char * const *cur;
+    list_for_each_entry(group, groups, entry) {
         Bool match = FALSE;
 
-        for (cur = group->values; *cur; cur++)
-            if ((*compare)(attr, *cur) == 0) {
-                match = TRUE;
-                break;
+        list_for_each_entry(pattern, &group->patterns, entry) {
+            if (multi_match(attr, pattern)) {
+                if (pattern->is_negated) return FALSE;
+                else return TRUE;
             }
+            else if (pattern->is_negated)
+                match = TRUE;
+        }
         if (!match)
             return FALSE;
     }
@@ -531,31 +550,31 @@ InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
                   const InputAttributes *attrs)
 {
     /* MatchProduct substring */
-    if (!MatchAttrToken(attrs->product, &iclass->match_product, match_substring))
+    if (!MatchAttrToken(attrs->product, &iclass->match_product))
         return FALSE;
 
     /* MatchVendor substring */
-    if (!MatchAttrToken(attrs->vendor, &iclass->match_vendor, match_substring))
+    if (!MatchAttrToken(attrs->vendor, &iclass->match_vendor))
         return FALSE;
 
     /* MatchDevicePath pattern */
-    if (!MatchAttrToken(attrs->device, &iclass->match_device, match_path_pattern))
+    if (!MatchAttrToken(attrs->device, &iclass->match_device))
         return FALSE;
 
     /* MatchOS case-insensitive string */
-    if (!MatchAttrToken(HostOS(), &iclass->match_os, strcasecmp))
+    if (!MatchAttrToken(HostOS(), &iclass->match_os))
         return FALSE;
 
     /* MatchPnPID pattern */
-    if (!MatchAttrToken(attrs->pnp_id, &iclass->match_pnpid, match_pattern))
+    if (!MatchAttrToken(attrs->pnp_id, &iclass->match_pnpid))
         return FALSE;
 
     /* MatchUSBID pattern */
-    if (!MatchAttrToken(attrs->usb_id, &iclass->match_usbid, match_pattern))
+    if (!MatchAttrToken(attrs->usb_id, &iclass->match_usbid))
         return FALSE;
 
     /* MatchDriver string */
-    if (!MatchAttrToken(idev->driver, &iclass->match_driver, strcmp))
+    if (!MatchAttrToken(idev->driver, &iclass->match_driver))
         return FALSE;
 
     /*
@@ -569,7 +588,7 @@ InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
         if (!attrs->tags)
             return FALSE;
         for (tag = attrs->tags, match = FALSE; *tag; tag++) {
-            if (MatchAttrToken(*tag, &iclass->match_tag, strcmp)) {
+            if (MatchAttrToken(*tag, &iclass->match_tag)) {
                 match = TRUE;
                 break;
             }
@@ -579,9 +598,7 @@ InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
     }
 
     /* MatchLayout string */
-    if (!list_is_empty(&iclass->match_layout)) {
-        if (!MatchAttrToken(xf86ConfigLayout.id,
-                            &iclass->match_layout, match_string_implicit))
+    if (!MatchAttrToken(xf86ConfigLayout.id, &iclass->match_layout))
             return FALSE;
     }
 
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index 3f80170..6124989 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -64,17 +64,73 @@ xf86ConfigSymTabRec InputClassTab[] =
 
 #define CLEANUP xf86freeInputClassList
 
-#define TOKEN_SEP "|"
+#define TOKEN_SEP '|'
+
+#define NEG_FLAG '!'
+
+static struct
+{
+    const char *prefix;
+    xf86MatchMode mode;
+}
+mode_prefixes[] = {
+    { "regex:",   MATCH_IS_REGEX },
+    { "re:",      MATCH_IS_REGEX },
+    { NULL,       MATCH_IS_INVALID }
+};
 
 static void
-add_group_entry(struct list *head, char **values)
+add_to_group_entry(xf86MatchGroup **group, const char *str,
+                   xf86MatchMode pref_mode)
 {
-    xf86MatchGroup *group;
+    xf86MatchPattern *pattern;
+    unsigned n;
+    char *next;
+
+    if (!str) return;
+
+    if (!*group) {
+        *group = malloc(sizeof(**group));
+        if (!*group) return;
+        list_init(&(*group)->patterns);
+    }
+
+  again:
+    /* not negated, MATCH_IS_AUTO */
+    if ((pattern = calloc(sizeof(*pattern),1)) == NULL)
+        return;
+    list_add(&pattern->entry, &(*group)->patterns);
+
+    if (*str == NEG_FLAG) {
+        pattern->is_negated = TRUE;
+        str++;
+    }
 
-    group = malloc(sizeof(*group));
-    if (group) {
-        group->values = values;
-        list_add(&group->entry, head);
+    for (n=0; mode_prefixes[n].prefix; n++) {
+        if (!strncmp(str, mode_prefixes[n].prefix,
+                     strlen(mode_prefixes[n].prefix))) {
+            pattern->mode = mode_prefixes[n].mode;
+            str += strlen(mode_prefixes[n].prefix);
+            break;
+        }
+    }
+
+
+    if (pattern->mode == MATCH_IS_AUTO)
+        pattern->mode = pref_mode;
+
+    if ((next = index(str, TOKEN_SEP)))
+        n = next-str;
+    else
+        n = strlen(str);
+
+    if ((pattern->str = strndup(str, n)) == NULL) {
+        pattern->mode = MATCH_IS_INVALID;
+    }
+
+    if (next) {
+        str = next+1;
+        goto again;
     }
 }
 
@@ -83,6 +139,7 @@ xf86parseInputClassSection(void)
 {
     int has_ident = FALSE;
     int token;
+    xf86MatchGroup *group;
 
     parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
 
@@ -98,6 +155,7 @@ xf86parseInputClassSection(void)
     list_init(&ptr->match_layout);
 
     while ((token = xf86getToken(InputClassTab)) != ENDSECTION) {
+        group = NULL;
         switch (token) {
         case COMMENT:
             ptr->comment = xf86addComment(ptr->comment, val.str);
@@ -124,59 +182,95 @@ xf86parseInputClassSection(void)
             ptr->option_lst = xf86parseOption(ptr->option_lst);
             break;
         case MATCH_PRODUCT:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
-                Error(QUOTE_MSG, "MatchProduct");
-            add_group_entry(&ptr->match_product,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+                add_to_group_entry(&group, val.str, MATCH_IS_STRSTR);
+            }
+            xf86unGetToken(token);
+            if (group)
+                list_add(&group->entry, &ptr->match_product);
+            else
+                Error(QUOTE_MSG, "MatchVendor");
+            continue;
         case MATCH_VENDOR:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
+            while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+                add_to_group_entry(&group, val.str, MATCH_IS_STRSTR);
+            }
+            xf86unGetToken(token);
+            if (group)
+                list_add(&group->entry, &ptr->match_vendor);
+            else
                 Error(QUOTE_MSG, "MatchVendor");
-            add_group_entry(&ptr->match_vendor,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            continue;
         case MATCH_DEVICE_PATH:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
-                Error(QUOTE_MSG, "MatchDevicePath");
-            add_group_entry(&ptr->match_device,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+                add_to_group_entry(&group, val.str, MATCH_IS_PATHNAME);
+            }
+            xf86unGetToken(token);
+            if (group)
+                list_add(&group->entry, &ptr->match_device);
+            else
+                Error(QUOTE_MSG, "MatchDevice");
+            continue;
         case MATCH_OS:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
+            while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+                add_to_group_entry(&group, val.str, MATCH_IS_STRCASECMP);
+            }
+            xf86unGetToken(token);
+            if (group)
+                list_add(&group->entry, &ptr->match_os);
+            else
                 Error(QUOTE_MSG, "MatchOS");
-            add_group_entry(&ptr->match_os,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            continue;
         case MATCH_PNPID:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
+            while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+                add_to_group_entry(&group, val.str, MATCH_IS_FILENAME);
+            }
+            xf86unGetToken(token);
+            if (group)
+                list_add(&group->entry, &ptr->match_pnpid);
+            else
                 Error(QUOTE_MSG, "MatchPnPID");
-            add_group_entry(&ptr->match_pnpid,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            continue;
         case MATCH_USBID:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
+            while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+                add_to_group_entry(&group, val.str, MATCH_IS_FILENAME);
+            }
+            xf86unGetToken(token);
+            if (group)
+                list_add(&group->entry, &ptr->match_usbid);
+            else
                 Error(QUOTE_MSG, "MatchUSBID");
-            add_group_entry(&ptr->match_usbid,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            continue;
         case MATCH_DRIVER:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
+            while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+                add_to_group_entry(&group, val.str, MATCH_IS_STRCMP);
+            }
+            xf86unGetToken(token);
+            if (group)
+                list_add(&group->entry, &ptr->match_driver);
+            else
                 Error(QUOTE_MSG, "MatchDriver");
-            add_group_entry(&ptr->match_driver,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            continue;
         case MATCH_TAG:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
+            while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+                add_to_group_entry(&group, val.str, MATCH_IS_STRCMP);
+            }
+            xf86unGetToken(token);
+            if (group)
+                list_add(&group->entry, &ptr->match_tag);
+            else
                 Error(QUOTE_MSG, "MatchTag");
-            add_group_entry(&ptr->match_tag,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            continue;
         case MATCH_LAYOUT:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
+            while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+                add_to_group_entry(&group, val.str, MATCH_IS_STRIMPLICIT);
+            }
+            xf86unGetToken(token);
+            if (group)
+                list_add(&group->entry, &ptr->match_layout);
+            else
                 Error(QUOTE_MSG, "MatchLayout");
-            add_group_entry(&ptr->match_layout,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            continue;
         case MATCH_IS_KEYBOARD:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchIsKeyboard");
@@ -244,11 +338,32 @@ xf86parseInputClassSection(void)
     return ptr;
 }
 
+static
+void
+xf86printMatchPattern(FILE * cf, const xf86MatchPattern *pattern)
+{
+    if (!pattern) return;
+
+    if (pattern->is_negated) fprintf(cf, "%c", NEG_FLAG);
+    if (pattern->mode == MATCH_IS_INVALID)
+        fprintf(cf, "invalid:");
+    else {
+        unsigned n;
+        for (n=0; mode_prefixes[n].prefix; n++) {
+            if (mode_prefixes[n].mode == pattern->mode) {
+                fprintf(cf, "%s", mode_prefixes[n].prefix);
+                break;
+            }
+        }
+    }
+    fprintf(cf, "%s", pattern->str);
+}
+
 void
 xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
 {
     const xf86MatchGroup *group;
-    char * const *cur;
+    const xf86MatchPattern *pattern;
 
     while (ptr) {
         fprintf(cf, "Section \"InputClass\"\n");
@@ -261,66 +376,84 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
 
         list_for_each_entry(group, &ptr->match_product, entry) {
             fprintf(cf, "\tMatchProduct    \"");
-            for (cur = group->values; *cur; cur++)
-                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
-                        *cur);
-            fprintf(cf, "\"\n");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " \"");
+                xf86printMatchPattern(cf, pattern);
+                fprintf(cf, "\"");
+            }
+            fprintf(cf, "\n");
         }
         list_for_each_entry(group, &ptr->match_vendor, entry) {
             fprintf(cf, "\tMatchVendor     \"");
-            for (cur = group->values; *cur; cur++)
-                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
-                        *cur);
-            fprintf(cf, "\"\n");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " \"");
+                xf86printMatchPattern(cf, pattern);
+                fprintf(cf, "\"");
+            }
+            fprintf(cf, "\n");
         }
         list_for_each_entry(group, &ptr->match_device, entry) {
             fprintf(cf, "\tMatchDevicePath \"");
-            for (cur = group->values; *cur; cur++)
-                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
-                        *cur);
-            fprintf(cf, "\"\n");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " \"");
+                xf86printMatchPattern(cf, pattern);
+                fprintf(cf, "\"");
+            }
+            fprintf(cf, "\n");
         }
         list_for_each_entry(group, &ptr->match_os, entry) {
             fprintf(cf, "\tMatchOS         \"");
-            for (cur = group->values; *cur; cur++)
-                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
-                        *cur);
-            fprintf(cf, "\"\n");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " \"");
+                xf86printMatchPattern(cf, pattern);
+                fprintf(cf, "\"");
+            }
+            fprintf(cf, "\n");
         }
         list_for_each_entry(group, &ptr->match_pnpid, entry) {
             fprintf(cf, "\tMatchPnPID      \"");
-            for (cur = group->values; *cur; cur++)
-                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
-                        *cur);
-            fprintf(cf, "\"\n");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " \"");
+                xf86printMatchPattern(cf, pattern);
+                fprintf(cf, "\"");
+            }
+            fprintf(cf, "\n");
         }
         list_for_each_entry(group, &ptr->match_usbid, entry) {
             fprintf(cf, "\tMatchUSBID      \"");
-            for (cur = group->values; *cur; cur++)
-                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
-                        *cur);
-            fprintf(cf, "\"\n");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " \"");
+                xf86printMatchPattern(cf, pattern);
+                fprintf(cf, "\"");
+            }
+            fprintf(cf, "\n");
         }
         list_for_each_entry(group, &ptr->match_driver, entry) {
             fprintf(cf, "\tMatchDriver     \"");
-            for (cur = group->values; *cur; cur++)
-                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
-                        *cur);
-            fprintf(cf, "\"\n");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " \"");
+                xf86printMatchPattern(cf, pattern);
+                fprintf(cf, "\"");
+            }
+            fprintf(cf, "\n");
         }
         list_for_each_entry(group, &ptr->match_tag, entry) {
             fprintf(cf, "\tMatchTag        \"");
-            for (cur = group->values; *cur; cur++)
-                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
-                        *cur);
-            fprintf(cf, "\"\n");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " \"");
+                xf86printMatchPattern(cf, pattern);
+                fprintf(cf, "\"");
+            }
+            fprintf(cf, "\n");
         }
         list_for_each_entry(group, &ptr->match_layout, entry) {
             fprintf(cf, "\tMatchLayout     \"");
-            for (cur = group->values; *cur; cur++)
-                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
-                        *cur);
-            fprintf(cf, "\"\n");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " \"");
+                xf86printMatchPattern(cf, pattern);
+                fprintf(cf, "\"");
+            }
+            fprintf(cf, "\n");
         }
 
         if (ptr->is_keyboard.set)
@@ -353,64 +486,127 @@ xf86freeInputClassList (XF86ConfInputClassPtr ptr)
     XF86ConfInputClassPtr prev;
 
     while (ptr) {
-        xf86MatchGroup *group, *next;
-        char **list;
+        xf86MatchGroup *group, *next_group;
+        xf86MatchPattern *pattern, *next_pattern;
 
         TestFree(ptr->identifier);
         TestFree(ptr->driver);
 
-        list_for_each_entry_safe(group, next, &ptr->match_product, entry) {
+        list_for_each_entry_safe(group, next_group, &ptr->match_product, entry) {
             list_del(&group->entry);
-            for (list = group->values; *list; list++)
-                free(*list);
+            list_for_each_entry_safe(pattern, next_pattern, &group->patterns, entry) {
+                list_del(&pattern->entry);
+                if (pattern->str) free(pattern->str);
+                if ((pattern->mode == MATCH_IS_REGEX) && pattern->regex) {
+                    regfree(pattern->regex);
+                    free(pattern->regex);
+                }
+                free(pattern);
+            }
             free(group);
         }
-        list_for_each_entry_safe(group, next, &ptr->match_vendor, entry) {
+        list_for_each_entry_safe(group, next_group, &ptr->match_vendor, entry) {
             list_del(&group->entry);
-            for (list = group->values; *list; list++)
-                free(*list);
+            list_for_each_entry_safe(pattern, next_pattern, &group->patterns, entry) {
+                list_del(&pattern->entry);
+                if (pattern->str) free(pattern->str);
+                if ((pattern->mode == MATCH_IS_REGEX) && pattern->regex) {
+                    regfree(pattern->regex);
+                    free(pattern->regex);
+                }
+                free(pattern);
+            }
             free(group);
         }
-        list_for_each_entry_safe(group, next, &ptr->match_device, entry) {
+        list_for_each_entry_safe(group, next_group, &ptr->match_device, entry) {
             list_del(&group->entry);
-            for (list = group->values; *list; list++)
-                free(*list);
+            list_for_each_entry_safe(pattern, next_pattern, &group->patterns, entry) {
+                list_del(&pattern->entry);
+                if (pattern->str) free(pattern->str);
+                if ((pattern->mode == MATCH_IS_REGEX) && pattern->regex) {
+                    regfree(pattern->regex);
+                    free(pattern->regex);
+                }
+                free(pattern);
+            }
             free(group);
         }
-        list_for_each_entry_safe(group, next, &ptr->match_os, entry) {
+        list_for_each_entry_safe(group, next_group, &ptr->match_os, entry) {
             list_del(&group->entry);
-            for (list = group->values; *list; list++)
-                free(*list);
+            list_for_each_entry_safe(pattern, next_pattern, &group->patterns, entry) {
+                list_del(&pattern->entry);
+                if (pattern->str) free(pattern->str);
+                if ((pattern->mode == MATCH_IS_REGEX) && pattern->regex) {
+                    regfree(pattern->regex);
+                    free(pattern->regex);
+                }
+                free(pattern);
+            }
             free(group);
         }
-        list_for_each_entry_safe(group, next, &ptr->match_pnpid, entry) {
+        list_for_each_entry_safe(group, next_group, &ptr->match_pnpid, entry) {
             list_del(&group->entry);
-            for (list = group->values; *list; list++)
-                free(*list);
+            list_for_each_entry_safe(pattern, next_pattern, &group->patterns, entry) {
+                list_del(&pattern->entry);
+                if (pattern->str) free(pattern->str);
+                if ((pattern->mode == MATCH_IS_REGEX) && pattern->regex) {
+                    regfree(pattern->regex);
+                    free(pattern->regex);
+                }
+                free(pattern);
+            }
             free(group);
         }
-        list_for_each_entry_safe(group, next, &ptr->match_usbid, entry) {
+        list_for_each_entry_safe(group, next_group, &ptr->match_usbid, entry) {
             list_del(&group->entry);
-            for (list = group->values; *list; list++)
-                free(*list);
+            list_for_each_entry_safe(pattern, next_pattern, &group->patterns, entry) {
+                list_del(&pattern->entry);
+                if (pattern->str) free(pattern->str);
+                if ((pattern->mode == MATCH_IS_REGEX) && pattern->regex) {
+                    regfree(pattern->regex);
+                    free(pattern->regex);
+                }
+                free(pattern);
+            }
             free(group);
         }
-        list_for_each_entry_safe(group, next, &ptr->match_driver, entry) {
+        list_for_each_entry_safe(group, next_group, &ptr->match_driver, entry) {
             list_del(&group->entry);
-            for (list = group->values; *list; list++)
-                free(*list);
+            list_for_each_entry_safe(pattern, next_pattern, &group->patterns, entry) {
+                list_del(&pattern->entry);
+                if (pattern->str) free(pattern->str);
+                if ((pattern->mode == MATCH_IS_REGEX) && pattern->regex) {
+                    regfree(pattern->regex);
+                    free(pattern->regex);
+                }
+                free(pattern);
+            }
             free(group);
         }
-        list_for_each_entry_safe(group, next, &ptr->match_tag, entry) {
+        list_for_each_entry_safe(group, next_group, &ptr->match_tag, entry) {
             list_del(&group->entry);
-            for (list = group->values; *list; list++)
-                free(*list);
+            list_for_each_entry_safe(pattern, next_pattern, &group->patterns, entry) {
+                list_del(&pattern->entry);
+                if (pattern->str) free(pattern->str);
+                if ((pattern->mode == MATCH_IS_REGEX) && pattern->regex) {
+                    regfree(pattern->regex);
+                    free(pattern->regex);
+                }
+                free(pattern);
+            }
             free(group);
         }
-        list_for_each_entry_safe(group, next, &ptr->match_layout, entry) {
+        list_for_each_entry_safe(group, next_group, &ptr->match_layout, entry) {
             list_del(&group->entry);
-            for (list = group->values; *list; list++)
-                free(*list);
+            list_for_each_entry_safe(pattern, next_pattern, &group->patterns, entry) {
+                list_del(&pattern->entry);
+                if (pattern->str) free(pattern->str);
+                if ((pattern->mode == MATCH_IS_REGEX) && pattern->regex) {
+                    regfree(pattern->regex);
+                    free(pattern->regex);
+                }
+                free(pattern);
+            }
             free(group);
         }
 
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index a8785c5..0fea7c4 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -68,6 +68,9 @@
 #include "xf86Optrec.h"
 #include "list.h"
 
+#include <sys/types.h>
+#include <regex.h>
+
 #define HAVE_PARSER_DECLS
 
 typedef struct
@@ -341,10 +344,35 @@ xf86TriState;
 typedef struct
 {
 	struct list entry;
-	char **values;
+	struct list patterns;
 }
 xf86MatchGroup;
 
+typedef enum
+{
+	MATCH_IS_INVALID = -1,
+	MATCH_IS_AUTO = 0,
+	MATCH_IS_STRCMP,
+	MATCH_IS_STRCASECMP,
+	MATCH_IS_STRIMPLICIT,
+	MATCH_IS_STRSTR,
+	MATCH_IS_STRCASESTR,
+	MATCH_IS_FILENAME,
+	MATCH_IS_PATHNAME,
+	MATCH_IS_REGEX
+}
+xf86MatchMode;
+
+typedef struct
+{
+	struct list entry;
+	Bool is_negated;
+	xf86MatchMode mode;
+	char *str;
+	regex_t *regex;
+}
+xf86MatchPattern;
+
 typedef struct
 {
 	GenericListRec list;
-- 
1.6.4


Best regards,
Oleh



More information about the xorg-devel mailing list