[PATCH 1/2] xserver: Use constants for matching modes and make xf86MatchGroup a list

Oleh Nykyforchyn oleh.nyk at gmail.com
Wed Oct 26 03:02:40 PDT 2011


xserver: Use constants for matching modes and make xf86MatchGroup a list

Make a match group a list of patterns instead of an array of string, to unify
with other structures in the parser, to prepare for introduction of regular
expression in Match* statements, and to keep a matching mode field in
a pattern together with a pattern string. This allows to join all match_*
functions in InputClass.c into one "multi-mode" function.

Signed-off-by: Oleh Nykyforchyn <oleh.nyk at gmail.com>
---
 hw/xfree86/common/xf86Xinput.c |  130 +++++++++++++------------
 hw/xfree86/parser/InputClass.c |  211 +++++++++++++++++++++++++---------------
 hw/xfree86/parser/xf86Parser.h |   22 ++++-
 3 files changed, 221 insertions(+), 142 deletions(-)

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index ea1f927..486a105 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -471,79 +471,76 @@ HostOS(void)
 #endif
 }
 
+/*
+ * Match an attribute against a pattern. Matching mode is
+ * determined by pattern->mode member.
+ */
 static int
-match_substring(const char *attr, const char *pattern)
+match_token(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;
+        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)");
+        default:
+        /* Impossible */
+            return 0;
     }
 }
 
 /*
- * 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;
-            }
-        if (!match)
-            return FALSE;
+        list_for_each_entry(pattern, &group->patterns, entry) {
+            match = match || match_token(attr, pattern);
+            if (match) break;
+        }
+        if (!match) return FALSE;
     }
 
     /* All the entries in the list matched the attribute */
@@ -558,32 +555,34 @@ static Bool
 InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
                   const InputAttributes *attrs)
 {
+    const char *layout;
+
     /* 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;
 
     /*
@@ -597,7 +596,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;
             }
@@ -606,12 +605,17 @@ InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
             return FALSE;
     }
 
-    /* MatchLayout string */
-    if (!list_is_empty(&iclass->match_layout)) {
-        if (!MatchAttrToken(xf86ConfigLayout.id,
-                            &iclass->match_layout, match_string_implicit))
+    /* MatchLayout string
+     *
+     * If no Layout section is found, xf86ServerLayout.id becomes "(implicit)"
+     * It is convenient that "" in patterns means "no explicit layout"
+     */
+    if (strcmp(xf86ConfigLayout.id,"(implicit)"))
+        layout = xf86ConfigLayout.id;
+    else
+        layout = "";
+    if (!MatchAttrToken(layout, &iclass->match_layout))
             return FALSE;
-    }
 
     /* MatchIs* booleans */
     if (iclass->is_keyboard.set &&
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index 3f80170..5397713 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -67,15 +67,55 @@ xf86ConfigSymTabRec InputClassTab[] =
 #define TOKEN_SEP "|"
 
 static void
-add_group_entry(struct list *head, char **values)
+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);
+        free(pattern);
+    }
+    free(group);
+}
+
+static
+xf86MatchGroup*
+create_group(const char *str,
+                   xf86MatchMode pref_mode)
+{
+    xf86MatchPattern *pattern;
     xf86MatchGroup *group;
+    unsigned n;
+
+    if (!str)
+        return NULL;
 
     group = malloc(sizeof(*group));
-    if (group) {
-        group->values = values;
-        list_add(&group->entry, head);
+    if (!group) return NULL;
+    list_init(&group->patterns);
+
+  again:
+    /* start new pattern */
+    if ((pattern = calloc(sizeof(*pattern),1)) == NULL) {
+        free_group(group);
+        return NULL;
     }
+    list_add(&pattern->entry, &group->patterns);
+
+    pattern->mode = pref_mode;
+
+    n = strcspn(str, TOKEN_SEP);
+
+    if ((pattern->str = strndup(str, n)) == NULL)
+        pattern->mode = MATCH_IS_INVALID;
+
+    if (str[n] != '\0') {
+        str += n+1;
+        goto again;
+    }
+
+    return group;
 }
 
 XF86ConfInputClassPtr
@@ -83,6 +123,7 @@ xf86parseInputClassSection(void)
 {
     int has_ident = FALSE;
     int token;
+    xf86MatchGroup *group;
 
     parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
 
@@ -126,56 +167,83 @@ xf86parseInputClassSection(void)
         case MATCH_PRODUCT:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchProduct");
-            add_group_entry(&ptr->match_product,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRSTR);
+            if (group)
+                list_add(&group->entry, &ptr->match_product);
+            else
+                Error(QUOTE_MSG, "MatchProduct");
             break;
         case MATCH_VENDOR:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchVendor");
-            add_group_entry(&ptr->match_vendor,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRSTR);
+            if (group)
+                list_add(&group->entry, &ptr->match_vendor);
+            else
+                Error(QUOTE_MSG, "MatchVendor");
             break;
         case MATCH_DEVICE_PATH:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchDevicePath");
-            add_group_entry(&ptr->match_device,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_PATHNAME);
+            if (group)
+                list_add(&group->entry, &ptr->match_device);
+            else
+                Error(QUOTE_MSG, "MatchDevicePath");
             break;
         case MATCH_OS:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchOS");
-            add_group_entry(&ptr->match_os,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRCASECMP);
+            if (group)
+                list_add(&group->entry, &ptr->match_os);
+            else
+                Error(QUOTE_MSG, "MatchOS");
             break;
         case MATCH_PNPID:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchPnPID");
-            add_group_entry(&ptr->match_pnpid,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_FILENAME);
+            if (group)
+                list_add(&group->entry, &ptr->match_pnpid);
+            else
+                Error(QUOTE_MSG, "MatchPnPID");
             break;
         case MATCH_USBID:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchUSBID");
-            add_group_entry(&ptr->match_usbid,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_FILENAME);
+            if (group)
+                list_add(&group->entry, &ptr->match_usbid);
+            else
+                Error(QUOTE_MSG, "MatchUSBID");
             break;
         case MATCH_DRIVER:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchDriver");
-            add_group_entry(&ptr->match_driver,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRCMP);
+            if (group)
+                list_add(&group->entry, &ptr->match_driver);
+            else
+                Error(QUOTE_MSG, "MatchDriver");
             break;
         case MATCH_TAG:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchTag");
-            add_group_entry(&ptr->match_tag,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRCMP);
+            if (group)
+                list_add(&group->entry, &ptr->match_tag);
+            else
+                Error(QUOTE_MSG, "MatchTag");
             break;
         case MATCH_LAYOUT:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchLayout");
-            add_group_entry(&ptr->match_layout,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRCMP);
+            if (group)
+                list_add(&group->entry, &ptr->match_layout);
+            else
+                Error(QUOTE_MSG, "MatchLayout");
             break;
         case MATCH_IS_KEYBOARD:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
@@ -244,11 +312,26 @@ xf86parseInputClassSection(void)
     return ptr;
 }
 
+static void
+print_pattern(FILE * cf, const xf86MatchPattern *pattern)
+{
+    if (!pattern) return;
+
+    if (pattern->mode == MATCH_IS_INVALID)
+        fprintf(cf, "invalid:");
+    if (pattern->str)
+        fprintf(cf, "%s", pattern->str);
+    else
+        fprintf(cf, "(none)");
+    if (pattern->entry.next)
+        fprintf(cf, "%c", TOKEN_SEP);
+}
+
 void
 xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
 {
     const xf86MatchGroup *group;
-    char * const *cur;
+    const xf86MatchPattern *pattern;
 
     while (ptr) {
         fprintf(cf, "Section \"InputClass\"\n");
@@ -261,65 +344,56 @@ 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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                print_pattern(cf, pattern);
             fprintf(cf, "\"\n");
         }
 
@@ -354,64 +428,45 @@ xf86freeInputClassList (XF86ConfInputClassPtr ptr)
 
     while (ptr) {
         xf86MatchGroup *group, *next;
-        char **list;
 
         TestFree(ptr->identifier);
         TestFree(ptr->driver);
 
         list_for_each_entry_safe(group, next, &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_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_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_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_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_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_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_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_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..b02923f 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -341,10 +341,30 @@ xf86TriState;
 typedef struct
 {
 	struct list entry;
-	char **values;
+	struct list patterns;
 }
 xf86MatchGroup;
 
+typedef enum
+{
+	MATCH_IS_INVALID,
+	MATCH_IS_STRCMP,
+	MATCH_IS_STRCASECMP,
+	MATCH_IS_STRSTR,
+	MATCH_IS_STRCASESTR,
+	MATCH_IS_FILENAME,
+	MATCH_IS_PATHNAME
+}
+xf86MatchMode;
+
+typedef struct
+{
+	struct list entry;
+	xf86MatchMode mode;
+	char *str;
+}
+xf86MatchPattern;
+
 typedef struct
 {
 	GenericListRec list;
-- 
1.7.4.4



Signed-off-by: Oleh Nykyforchyn <oleh.nyk at gmail.com>
---
 hw/xfree86/common/xf86Xinput.c |  140 ++++++++++++----------
 hw/xfree86/parser/InputClass.c |  247 +++++++++++++++++++++++++--------------
 hw/xfree86/parser/xf86Parser.h |   23 ++++-
 3 files changed, 256 insertions(+), 154 deletions(-)

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 26051ad..e065876 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -443,79 +443,84 @@ HostOS(void)
 #endif
 }
 
+/*
+ * Match an attribute against a pattern. Matching mode is
+ * determined by pattern->mode member.
+ */
 static int
-match_substring(const char *attr, const char *pattern)
+match_token(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;
+        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)");
+        default:
+        /* Impossible */
+            return 0;
     }
 }
 
 /*
- * 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;
-        Bool match = FALSE;
-
-        for (cur = group->values; *cur; cur++)
-            if ((*compare)(attr, *cur) == 0) {
-                match = TRUE;
-                break;
+    list_for_each_entry(group, groups, entry) {
+        Bool match = TRUE;
+
+        list_for_each_entry(pattern, &group->patterns, entry) {
+            match = match && match_token(attr, pattern);
+            if (pattern->is_last) {
+            /* last pattern in a conjunction, i.e. &-separated sequence */
+                if (match)
+                    goto new_group;
+                else
+                    match = TRUE;
             }
-        if (!match)
-            return FALSE;
+        }
+        return FALSE;
+      new_group:
+        continue;
     }
 
     /* All the entries in the list matched the attribute */
@@ -530,32 +535,34 @@ static Bool
 InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
                   const InputAttributes *attrs)
 {
+    const char *layout;
+
     /* 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 +576,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;
             }
@@ -578,12 +585,17 @@ InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
             return FALSE;
     }
 
-    /* MatchLayout string */
-    if (!list_is_empty(&iclass->match_layout)) {
-        if (!MatchAttrToken(xf86ConfigLayout.id,
-                            &iclass->match_layout, match_string_implicit))
+    /* MatchLayout string
+     *
+     * If no Layout section is found, xf86ServerLayout.id becomes "(implicit)"
+     * It is convenient that "" in patterns means "no explicit layout"
+     */
+    if (strcmp(xf86ConfigLayout.id,"(implicit)"))
+        layout = xf86ConfigLayout.id;
+    else
+        layout = "";
+    if (!MatchAttrToken(layout, &iclass->match_layout))
             return FALSE;
-    }
 
     /* MatchIs* booleans */
     if (iclass->is_keyboard.set &&
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index 3f80170..5794327 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -64,18 +64,67 @@ xf86ConfigSymTabRec InputClassTab[] =
 
 #define CLEANUP xf86freeInputClassList
 
-#define TOKEN_SEP "|"
+#define LOG_OR '|'
+#define LOG_AND '&'
+
 
 static void
-add_group_entry(struct list *head, char **values)
+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);
+}
+
+static
+xf86MatchGroup*
+create_group(const char *str,
+                   xf86MatchMode pref_mode)
 {
+    xf86MatchPattern *pattern;
     xf86MatchGroup *group;
+    unsigned n;
+    static const char sep[3] = { LOG_OR, LOG_AND, '\0' };
+
+    if (!str)
+        return NULL;
 
     group = malloc(sizeof(*group));
-    if (group) {
-        group->values = values;
-        list_add(&group->entry, head);
+    if (!group) return NULL;
+    list_init(&group->patterns);
+
+  again:
+    /* start new pattern */
+    if ((pattern = calloc(sizeof(*pattern),1)) == NULL) {
+        free_group(group);
+        return NULL;
+    }
+    list_add(&pattern->entry, &group->patterns);
+
+    pattern->mode = pref_mode;
+
+    n = strcspn(str, sep);
+
+    pattern->is_last = (str[n] != LOG_AND);
+
+    if ((pattern->str = strndup(str, n)) == NULL)
+        pattern->mode = MATCH_IS_INVALID;
+
+    if (str[n] != '\0') {
+        str += n+1;
+        goto again;
     }
+
+    return group;
 }
 
 XF86ConfInputClassPtr
@@ -83,6 +132,7 @@ xf86parseInputClassSection(void)
 {
     int has_ident = FALSE;
     int token;
+    xf86MatchGroup *group;
 
     parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
 
@@ -98,6 +148,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);
@@ -126,56 +177,83 @@ xf86parseInputClassSection(void)
         case MATCH_PRODUCT:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchProduct");
-            add_group_entry(&ptr->match_product,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRSTR);
+            if (group)
+                list_add(&group->entry, &ptr->match_product);
+            else
+                Error(QUOTE_MSG, "MatchProduct");
             break;
         case MATCH_VENDOR:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchVendor");
-            add_group_entry(&ptr->match_vendor,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRSTR);
+            if (group)
+                list_add(&group->entry, &ptr->match_vendor);
+            else
+                Error(QUOTE_MSG, "MatchVendor");
             break;
         case MATCH_DEVICE_PATH:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchDevicePath");
-            add_group_entry(&ptr->match_device,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRSTR);
+            if (group)
+                list_add(&group->entry, &ptr->match_device);
+            else
+                Error(QUOTE_MSG, "MatchDevicePath");
             break;
         case MATCH_OS:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchOS");
-            add_group_entry(&ptr->match_os,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRCASECMP);
+            if (group)
+                list_add(&group->entry, &ptr->match_os);
+            else
+                Error(QUOTE_MSG, "MatchOS");
             break;
         case MATCH_PNPID:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchPnPID");
-            add_group_entry(&ptr->match_pnpid,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_FILENAME);
+            if (group)
+                list_add(&group->entry, &ptr->match_pnpid);
+            else
+                Error(QUOTE_MSG, "MatchPnPID");
             break;
         case MATCH_USBID:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchUSBID");
-            add_group_entry(&ptr->match_usbid,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_FILENAME);
+            if (group)
+                list_add(&group->entry, &ptr->match_usbid);
+            else
+                Error(QUOTE_MSG, "MatchISBID");
             break;
         case MATCH_DRIVER:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchDriver");
-            add_group_entry(&ptr->match_driver,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRCMP);
+            if (group)
+                list_add(&group->entry, &ptr->match_driver);
+            else
+                Error(QUOTE_MSG, "MatchDriver");
             break;
         case MATCH_TAG:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchTag");
-            add_group_entry(&ptr->match_tag,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRCMP);
+            if (group)
+                list_add(&group->entry, &ptr->match_tag);
+            else
+                Error(QUOTE_MSG, "MatchTag");
             break;
         case MATCH_LAYOUT:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchLayout");
-            add_group_entry(&ptr->match_layout,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            group = create_group(val.str, MATCH_IS_STRCMP);
+            if (group)
+                list_add(&group->entry, &ptr->match_layout);
+            else
+                Error(QUOTE_MSG, "MatchLayout");
             break;
         case MATCH_IS_KEYBOARD:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
@@ -244,11 +322,30 @@ xf86parseInputClassSection(void)
     return ptr;
 }
 
+static void
+print_pattern(FILE * cf, const xf86MatchPattern *pattern)
+{
+    if (!pattern) return;
+
+    if (pattern->mode == MATCH_IS_INVALID)
+        fprintf(cf, "invalid:");
+    if (pattern->str)
+        fprintf(cf, "%s", pattern->str);
+    else
+        fprintf(cf, "(none)");
+    if (pattern->entry.next) {
+        if (pattern->is_last)
+            fprintf(cf, "%c", LOG_OR);
+        else
+            fprintf(cf, "%c", LOG_AND);
+    }
+}
+
 void
 xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
 {
     const xf86MatchGroup *group;
-    char * const *cur;
+    const xf86MatchPattern *pattern;
 
     while (ptr) {
         fprintf(cf, "Section \"InputClass\"\n");
@@ -261,65 +358,56 @@ 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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                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);
+            list_for_each_entry(pattern, &group->patterns, entry)
+                print_pattern(cf, pattern);
             fprintf(cf, "\"\n");
         }
 
@@ -353,65 +441,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..d10d421 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -341,10 +341,31 @@ xf86TriState;
 typedef struct
 {
 	struct list entry;
-	char **values;
+	struct list patterns;
 }
 xf86MatchGroup;
 
+typedef enum
+{
+	MATCH_IS_INVALID,
+	MATCH_IS_STRCMP,
+	MATCH_IS_STRCASECMP,
+	MATCH_IS_STRSTR,
+	MATCH_IS_STRCASESTR,
+	MATCH_IS_FILENAME,
+	MATCH_IS_PATHNAME
+}
+xf86MatchMode;
+
+typedef struct
+{
+	struct list entry;
+	Bool is_last;
+	xf86MatchMode mode;
+	char *str;
+}
+xf86MatchPattern;
+
 typedef struct
 {
 	GenericListRec list;
-- 
1.7.4.4
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001
Type: application/octet-stream
Size: 435 bytes
Desc: not available
URL: <http://lists.x.org/archives/xorg-devel/attachments/20111026/9ca84d38/attachment-0001.obj>


More information about the xorg-devel mailing list