[PATCH xserver] Multiple matching modes (incl. regex) selection support in Match* statements

Oleh Nykyforchyn oleh.nyk at gmail.com
Thu Jun 2 07:53:14 PDT 2011


Please consider a final version of the patch.

-------------------------------

Multiple matching modes selection (incl. regex) support in Match* statements

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.

Regexes are prefixed by "regex:" of "re:", prefixes are also added for all
other matching modes in two versions each: short and real name of the used
function. Negated conditions are prefixed by "!", which can be combined with
each other prefix. Different modes, as well as usual and negated patterns,
can be mixed in one line.

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

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 26051ad..3152064 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -443,79 +443,108 @@ HostOS(void)
 #endif
 }
 
+/*
+ * Match an attribute against a pattern. Matching mode is
+ * determined by pattern->mode member. If the mode is REGEX,
+ * then regex_t is allocated and compiled only during
+ * the first call, to save time and memory.
+ */
 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)) ? -1 : 0;
+        case MATCH_IS_STRCASESTR:
+            return (strcasestr(attr, pattern->str)) ? -1 : 0;
 #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(pattern->str, attr, 0)) ? 0 : -1;
+        case MATCH_IS_PATHNAME:
+            return (fnmatch(pattern->str, attr, FNM_PATHNAME)) ? 0 : -1;
 #else
-#define match_path_pattern match_substring
+        case MATCH_IS_FILENAME:
+            return (strstr(attr, pattern->str)) ? -1 : 0;
+        case MATCH_IS_PATHNAME:
+            return (strstr(attr, pattern->str)) ? -1 : 0;
 #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);
+                    free(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.
- * If a pattern in each list entry is matched, return TRUE.
+ * Match an attribute against a list of xf86MatchGroup's.
+ * Return TRUE only if each list entry is successful.
  */
 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;
+    xf86MatchGroup *group;
+    xf86MatchPattern *pattern;
 
-    /* If there are no patterns, accept the match */
-    if (list_is_empty(patterns))
+    /* 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
-     * match. Each list entry is a separate Match line of the same type.
+     * Otherwise, iterate the list of groups ensuring each entry has a
+     * match. Each list entry is a list of patterns obtained from
+     * a separate Match line.
      */
-    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)  /* negated pattern matched */
+                    return FALSE;         /* failure */
+                else                      /* appropriate pattern reached */
+                    return TRUE;          /* success */
             }
-        if (!match)
-            return FALSE;
+            else if (pattern->is_negated) /* at least negated pattern not */
+                match = TRUE;             /* matched - partial success */
+        }
+        if (!match)          /* nothing successful is this Match line */
+            return FALSE;    /* failure */
     }
 
     /* All the entries in the list matched the attribute */
@@ -531,31 +560,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 +598,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 +608,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..b8500a8 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -64,25 +64,113 @@ 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 },       /* regular expression */
+    { "re:",          MATCH_IS_REGEX },
+    { "str:",         MATCH_IS_STRCMP },      /* strings coincide */
+    { "strcmp:",      MATCH_IS_STRCMP },
+    { "cistr:",       MATCH_IS_STRCASECMP },  /* the same, but case insensitive */
+    { "strcasecmp:",  MATCH_IS_STRCASECMP },
+    { "stri:",        MATCH_IS_STRIMPLICIT }, /* "" matches "(implicit)" layout */
+    { "strcmpimpl:",  MATCH_IS_STRIMPLICIT },
+    { "sub:",         MATCH_IS_STRSTR },      /* contains a substring */
+    { "strstr:",      MATCH_IS_STRSTR },
+    { "cisub:",       MATCH_IS_STRCASESTR },  /* the same, but case insensitive */
+    { "strcasestr:",  MATCH_IS_STRCASESTR },
+    { "file:",        MATCH_IS_FILENAME },    /* match a shell wildcard pattern */
+    { "fnmatch:",     MATCH_IS_FILENAME },
+    { "path:",        MATCH_IS_PATHNAME },    /* the same, but '/' treated separately */
+    { "pnmatch:",     MATCH_IS_PATHNAME },
+    {  NULL,          MATCH_IS_INVALID }      /* sentinel */
+};
 
 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:
+    /* start new pattern: not negated, MATCH_IS_AUTO */
+    if ((pattern = calloc(sizeof(*pattern),1)) == NULL)
+        return;
+    list_add(&pattern->entry, &(*group)->patterns);
+
+    /* Pattern starting with '!' should NOT be matched */
+    if (*str == NEG_FLAG) {
+        pattern->is_negated = TRUE;
+        str++;
+    }
+
+    /* Check if there is a mode prefix */
+    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;
+    }
 
-    group = malloc(sizeof(*group));
-    if (group) {
-        group->values = values;
-        list_add(&group->entry, head);
+    if (next) {
+        str = next+1;
+        goto again;
     }
 }
 
+static void
+free_group(xf86MatchGroup *group)
+{
+    xf86MatchPattern *pattern, *next_pattern;
+    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);
+}
+
 XF86ConfInputClassPtr
 xf86parseInputClassSection(void)
 {
     int has_ident = FALSE;
     int token;
+    xf86MatchGroup *group;
 
     parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
 
@@ -98,6 +186,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);
@@ -123,60 +212,110 @@ xf86parseInputClassSection(void)
         case OPTION:
             ptr->option_lst = xf86parseOption(ptr->option_lst);
             break;
+        /*
+         * Argument of each Match{Product,..,Layout} statement
+         * can be a sequence of >=1 \"-quoted and space separated
+         * strings, which in turn are divided further by '|' chars
+         * to make a final list of patterns, unless a regular
+         * expression lasts until the closing \" of the current
+         * string, irrespective of '|'s. Hence
+         *     MatchProduct "foo" "bar" "regex:^Yes|No$" "$100"
+         *     MatchProduct "foo" "bar|regex:^Yes|No$" "$100"
+         * and
+         *     MatchProduct "foo|bar" "regex:^Yes|No$" "$100"
+         * are equivalent, but not
+         *     MatchProduct "foo" "bar" "regex:^Yes|No$|$100"
+         */
         case MATCH_PRODUCT:
-            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_product);
+            else
                 Error(QUOTE_MSG, "MatchProduct");
-            add_group_entry(&ptr->match_product,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            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)
+            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, "MatchDevicePath");
-            add_group_entry(&ptr->match_device,
-                            xstrtokenize(val.str, TOKEN_SEP));
-            break;
+            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 +383,35 @@ xf86parseInputClassSection(void)
     return ptr;
 }
 
+static void
+print_pattern(FILE * cf, const xf86MatchPattern *pattern)
+{
+    if (!pattern) return;
+
+    fprintf(cf, "\"");
+    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;
+            }
+        }
+    }
+    if (pattern->str)
+        fprintf(cf, "%s\"", pattern->str);
+    else
+        fprintf(cf, "(none)\"");
+}
+
 void
 xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
 {
     const xf86MatchGroup *group;
-    char * const *cur;
+    const xf86MatchPattern *pattern;
 
     while (ptr) {
         fprintf(cf, "Section \"InputClass\"\n");
@@ -260,67 +423,76 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
             fprintf(cf, "\tDriver          \"%s\"\n", ptr->driver);
 
         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");
+            fprintf(cf, "\tMatchProduct    ");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " ");
+                print_pattern(cf, pattern);
+            }
+            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");
+            fprintf(cf, "\tMatchVendor     ");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " ");
+                print_pattern(cf, pattern);
+            }
+            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");
+            fprintf(cf, "\tMatchDevicePath ");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " ");
+                print_pattern(cf, pattern);
+            }
+            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");
+            fprintf(cf, "\tMatchOS         ");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " ");
+                print_pattern(cf, pattern);
+            }
+            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");
+            fprintf(cf, "\tMatchPnPID      ");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " ");
+                print_pattern(cf, pattern);
+            }
+            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");
+            fprintf(cf, "\tMatchUSBID      ");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " ");
+                print_pattern(cf, pattern);
+            }
+            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");
+            fprintf(cf, "\tMatchDriver     ");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " ");
+                print_pattern(cf, pattern);
+            }
+            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");
+            fprintf(cf, "\tMatchTag        ");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " ");
+                print_pattern(cf, pattern);
+            }
+            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");
+            fprintf(cf, "\tMatchLayout     ");
+            list_for_each_entry(pattern, &group->patterns, entry) {
+                fprintf(cf, " ");
+                print_pattern(cf, pattern);
+            }
+            fprintf(cf, "\n");
         }
 
         if (ptr->is_keyboard.set)
@@ -353,65 +525,46 @@ xf86freeInputClassList (XF86ConfInputClassPtr ptr)
     XF86ConfInputClassPtr prev;
 
     while (ptr) {
-        xf86MatchGroup *group, *next;
-        char **list;
+        xf86MatchGroup *group, *next_group;
 
         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);
-            free(group);
+            free_group(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);
-            free(group);
+            free_group(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);
-            free(group);
+            free_group(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);
-            free(group);
+            free_group(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);
-            free(group);
+            free_group(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);
-            free(group);
+            free_group(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);
-            free(group);
+            free_group(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);
-            free(group);
+            free_group(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);
-            free(group);
+            free_group(group);
         }
 
         TestFree(ptr->comment);
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.7.0.1


Best regards,
Oleh


More information about the xorg-devel mailing list