[PATCH v2 10/11] xfree86: Allow multiple InputClass Match* entries for && matching

Dan Nicholson dbn.lists at gmail.com
Mon Jun 7 20:39:57 PDT 2010


Currently when there multiple InputClass entries of the same type, only
the last entry is used and the previous ones are ignored. Instead,
multiple entries are used to create multiple matching conditions.

For instance, an InputClass with

	MatchProduct "foo"
	MatchProduct "bar"

will require that the device's product name contain both foo and bar.
This provides a complement to the || style matching when an entry is
split using the "|" token.

The xorg.conf man page has added an example to hopefully clarify the two
types of compound matches.

Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
---
 hw/xfree86/common/xf86Xinput.c       |   49 ++++++----
 hw/xfree86/doc/man/xorg.conf.man.pre |   50 +++++++----
 hw/xfree86/parser/InputClass.c       |  167 ++++++++++++++++++++-------------
 hw/xfree86/parser/xf86Parser.h       |   22 +++--
 4 files changed, 179 insertions(+), 109 deletions(-)

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 7981dbe..be1b8a5 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -551,29 +551,42 @@ match_path_pattern(const char *attr, const char *pattern)
 #endif
 
 /*
- * Match an attribute against a NULL terminated list of patterns. If any
- * pattern is matched, return TRUE.
+ * Match an attribute against a list of NULL terminated arrays of patterns.
+ * If a pattern in each list entry is matched, return TRUE.
  */
 static Bool
-MatchAttrToken(const char *attr, char **patterns,
+MatchAttrToken(const char *attr, struct list *patterns,
                int (*compare)(const char *attr, const char *pattern))
 {
-    char **cur;
+    const xf86MatchGroup *group;
 
     /* If there are no patterns, accept the match */
-    if (!patterns)
+    if (list_is_empty(patterns))
         return TRUE;
 
     /* If there are patterns but no attribute, reject the match */
     if (!attr)
         return FALSE;
 
-    /* Otherwise, iterate the patterns looking for a match */
-    for (cur = patterns; *cur; cur++)
-        if ((*compare)(attr, *cur) == 0)
-            return TRUE;
+    /*
+     * Otherwise, iterate the list of patterns 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;
+        Bool match = FALSE;
+
+        for (cur = group->values; *cur; cur++)
+            if ((*compare)(attr, *cur) == 0) {
+                match = TRUE;
+                break;
+            }
+        if (!match)
+            return FALSE;
+    }
 
-    return FALSE;
+    /* All the entries in the list matched the attribute */
+    return TRUE;
 }
 
 /*
@@ -585,41 +598,41 @@ InputClassMatches(const XF86ConfInputClassPtr iclass,
                   const InputAttributes *attrs)
 {
     /* MatchProduct substring */
-    if (!MatchAttrToken(attrs->product, iclass->match_product, match_substring))
+    if (!MatchAttrToken(attrs->product, &iclass->match_product, match_substring))
         return FALSE;
 
     /* MatchVendor substring */
-    if (!MatchAttrToken(attrs->vendor, iclass->match_vendor, match_substring))
+    if (!MatchAttrToken(attrs->vendor, &iclass->match_vendor, match_substring))
         return FALSE;
 
     /* MatchDevicePath pattern */
-    if (!MatchAttrToken(attrs->device, iclass->match_device, match_path_pattern))
+    if (!MatchAttrToken(attrs->device, &iclass->match_device, match_path_pattern))
         return FALSE;
 
     /* MatchOS case-insensitive string */
-    if (!MatchAttrToken(HostOS(), iclass->match_os, strcasecmp))
+    if (!MatchAttrToken(HostOS(), &iclass->match_os, strcasecmp))
         return FALSE;
 
     /* MatchPnPID pattern */
-    if (!MatchAttrToken(attrs->pnp_id, iclass->match_pnpid, match_pattern))
+    if (!MatchAttrToken(attrs->pnp_id, &iclass->match_pnpid, match_pattern))
         return FALSE;
 
     /* MatchUSBID pattern */
-    if (!MatchAttrToken(attrs->usb_id, iclass->match_usbid, match_pattern))
+    if (!MatchAttrToken(attrs->usb_id, &iclass->match_usbid, match_pattern))
         return FALSE;
 
     /*
      * MatchTag string
      * See if any of the device's tags match any of the MatchTag tokens.
      */
-    if (iclass->match_tag) {
+    if (!list_is_empty(&iclass->match_tag)) {
         char * const *tag;
         Bool match;
 
         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, strcmp)) {
                 match = TRUE;
                 break;
             }
diff --git a/hw/xfree86/doc/man/xorg.conf.man.pre b/hw/xfree86/doc/man/xorg.conf.man.pre
index 63dbb68..f6b90be 100644
--- a/hw/xfree86/doc/man/xorg.conf.man.pre
+++ b/hw/xfree86/doc/man/xorg.conf.man.pre
@@ -1065,26 +1065,42 @@ of the class. If none of the optional entries appear, the
 .B InputClass
 section is generic and will match any input device. If more than one of
 these entries appear, they all must match for the configuration to apply.
-The allowed matching entries are shown below.
 .PP
+There are two types of match entries used in
+.B InputClass
+sections. The first allows various tokens to be matched against attributes
+of the device. An entry can be constructed to match attributes from different
+devices by separating arguments with a '|' character. Multiple entries of the
+same type may be supplied to add multiple matching conditions on the same
+attribute. For example:
+.PP
+.RS 4
+.nf
+.B  "Section \*qInputClass\*q"
+.B  "    Identifier   \*qMy Class\*q"
+.B  "    # product string must contain example and
+.B  "    # either gizmo or gadget
+.B  "    MatchProduct \*qexample\*q
+.B  "    MatchProduct \*qgizmo|gadget\*q
+.I  "    ..."
+.B  "EndSection"
+.fi
+.RE
 .TP 7
 .BI "MatchProduct  \*q" matchproduct \*q
 This entry can be used to check if the substring
 .RI \*q matchproduct \*q
-occurs in the device's product name. Multiple substrings can be matched by
-separating arguments with a '|' character.
+occurs in the device's product name.
 .TP 7
 .BI "MatchVendor  \*q" matchvendor \*q
 This entry can be used to check if the substring
 .RI \*q matchvendor \*q
-occurs in the device's vendor name. Multiple substrings can be matched by
-separating arguments with a '|' character.
+occurs in the device's vendor name.
 .TP 7
 .BI "MatchDevicePath \*q" matchdevice \*q
 This entry can be used to check if the device file matches the
 .RI \*q matchdevice \*q
-pathname pattern. Multiple patterns can be matched by separating arguments
-with a '|' character.
+pathname pattern.
 .TP 7
 .BI "MatchOS \*q" matchos \*q
 This entry can be used to check if the operating system matches the
@@ -1092,14 +1108,12 @@ case-insensitive
 .RI \*q matchos \*q
 string. This entry is only supported on platforms providing the
 .BR uname (2)
-system call. Multiple operating systems can be matched by separating arguments
-with a '|' character.
+system call.
 .TP 7
 .BI "MatchPnPID \*q" matchpnp \*q
 The device's Plug and Play (PnP) ID can be checked against the
 .RI \*q matchpnp \*q
-shell wildcard pattern. Multiple IDs can be matched by separating arguments
-with a '|' character.
+shell wildcard pattern.
 .TP 7
 .BI "MatchUSBID \*q" matchusb \*q
 The device's USB ID can be checked against the
@@ -1107,17 +1121,20 @@ The device's USB ID can be checked against the
 shell wildcard pattern. The ID is constructed as lowercase hexadecimal numbers
 separated by a ':'. This is the same format as the
 .BR lsusb (8)
-program. Multiple IDs can be matched by separating arguments with a '|'
-character.
+program.
 .TP 7
 .BI "MatchTag \*q" matchtag \*q
 This entry can be used to check if tags assigned by the config backend
 matches the
 .RI \*q matchtag \*q
-pattern.  Multiple patterns can be matched by separating arguments
-with a '|' character. A match is found if at least one of the tags given in
+pattern. A match is found if at least one of the tags given in
 .RI \*q matchtag \*q
 matches at least one of the tags assigned by the backend.
+.PP
+The second type of entry is used to match device types. These entries take a
+boolean argument similar to
+.B Option
+entries.
 .TP 7
 .BI "MatchIsKeyboard     \*q" bool \*q
 .TP 7
@@ -1130,9 +1147,6 @@ matches at least one of the tags assigned by the backend.
 .BI "MatchIsTouchpad     \*q" bool \*q
 .TP 7
 .BI "MatchIsTouchscreen  \*q" bool \*q
-Match device types. These entries take a boolean argument similar to
-.B Option
-entries.
 .PP
 When an input device has been matched to the
 .B InputClass
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index bdcfba4..f2b46bb 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -64,6 +64,18 @@ xf86ConfigSymTabRec InputClassTab[] =
 
 #define TOKEN_SEP "|"
 
+static void
+add_group_entry(struct list *head, char **values)
+{
+    xf86MatchGroup *group;
+
+    group = malloc(sizeof(*group));
+    if (group) {
+        group->values = values;
+        list_add(&group->entry, head);
+    }
+}
+
 XF86ConfInputClassPtr
 xf86parseInputClassSection(void)
 {
@@ -72,6 +84,15 @@ xf86parseInputClassSection(void)
 
     parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
 
+    /* Initialize MatchGroup lists */
+    list_init(&ptr->match_product);
+    list_init(&ptr->match_vendor);
+    list_init(&ptr->match_device);
+    list_init(&ptr->match_os);
+    list_init(&ptr->match_pnpid);
+    list_init(&ptr->match_usbid);
+    list_init(&ptr->match_tag);
+
     while ((token = xf86getToken(InputClassTab)) != ENDSECTION) {
         switch (token) {
         case COMMENT:
@@ -99,37 +120,44 @@ xf86parseInputClassSection(void)
         case MATCH_PRODUCT:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchProduct");
-            ptr->match_product = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_product,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_VENDOR:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchVendor");
-            ptr->match_vendor = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_vendor,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_DEVICE_PATH:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchDevicePath");
-            ptr->match_device = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_device,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_OS:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchOS");
-            ptr->match_os = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_os,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_PNPID:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchPnPID");
-            ptr->match_pnpid = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_pnpid,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_USBID:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchUSBID");
-            ptr->match_usbid = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_usbid,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_TAG:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchTag");
-            ptr->match_tag = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_tag,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_IS_KEYBOARD:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
@@ -201,7 +229,8 @@ xf86parseInputClassSection(void)
 void
 xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
 {
-    char **list;
+    const xf86MatchGroup *group;
+    char * const *cur;
 
     while (ptr) {
         fprintf(cf, "Section \"InputClass\"\n");
@@ -211,62 +240,57 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
             fprintf(cf, "\tIdentifier      \"%s\"\n", ptr->identifier);
         if (ptr->driver)
             fprintf(cf, "\tDriver          \"%s\"\n", ptr->driver);
-        if (ptr->match_product) {
+
+        list_for_each_entry(group, &ptr->match_product, entry) {
             fprintf(cf, "\tMatchProduct    \"");
-            for (list = ptr->match_product; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_product ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_vendor) {
+        list_for_each_entry(group, &ptr->match_vendor, entry) {
             fprintf(cf, "\tMatchVendor     \"");
-            for (list = ptr->match_vendor; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_vendor ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_device) {
+        list_for_each_entry(group, &ptr->match_device, entry) {
             fprintf(cf, "\tMatchDevicePath \"");
-            for (list = ptr->match_device; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_device ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_os) {
+        list_for_each_entry(group, &ptr->match_os, entry) {
             fprintf(cf, "\tMatchOS         \"");
-            for (list = ptr->match_os; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_os ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_pnpid) {
+        list_for_each_entry(group, &ptr->match_pnpid, entry) {
             fprintf(cf, "\tMatchPnPID      \"");
-            for (list = ptr->match_pnpid; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_pnpid ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_usbid) {
+        list_for_each_entry(group, &ptr->match_usbid, entry) {
             fprintf(cf, "\tMatchUSBID      \"");
-            for (list = ptr->match_usbid; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_usbid ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_tag) {
-            fprintf(cf, "\tMatchTag \"");
-            for (list = ptr->match_tag; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_tag ? "" : TOKEN_SEP,
-                        *list);
+        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");
         }
+
         if (ptr->is_keyboard.set)
             fprintf(cf, "\tIsKeyboard      \"%s\"\n",
                     ptr->is_keyboard.val ? "yes" : "no");
@@ -295,46 +319,57 @@ void
 xf86freeInputClassList (XF86ConfInputClassPtr ptr)
 {
     XF86ConfInputClassPtr prev;
-    char **list;
 
     while (ptr) {
+        xf86MatchGroup *group, *next;
+        char **list;
+
         TestFree(ptr->identifier);
         TestFree(ptr->driver);
-        if (ptr->match_product) {
-            for (list = ptr->match_product; *list; list++)
+
+        list_for_each_entry_safe(group, next, &ptr->match_product, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_product);
+            free(group);
         }
-        if (ptr->match_vendor) {
-            for (list = ptr->match_vendor; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_vendor, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_vendor);
+            free(group);
         }
-        if (ptr->match_device) {
-            for (list = ptr->match_device; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_device, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_device);
+            free(group);
         }
-        if (ptr->match_os) {
-            for (list = ptr->match_os; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_os, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_os);
+            free(group);
         }
-        if (ptr->match_pnpid) {
-            for (list = ptr->match_pnpid; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_pnpid, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_pnpid);
+            free(group);
         }
-        if (ptr->match_usbid) {
-            for (list = ptr->match_usbid; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_usbid, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_usbid);
+            free(group);
         }
-        if (ptr->match_tag) {
-            for (list = ptr->match_tag; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_tag, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_tag);
+            free(group);
         }
+
         TestFree(ptr->comment);
         xf86optionListFree(ptr->option_lst);
 
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index a86462f..26d9a5b 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -66,6 +66,7 @@
 
 #include <X11/Xdefs.h>
 #include "xf86Optrec.h"
+#include "list.h"
 
 #define HAVE_PARSER_DECLS
 
@@ -340,16 +341,23 @@ xf86TriState;
 
 typedef struct
 {
+	struct list entry;
+	char **values;
+}
+xf86MatchGroup;
+
+typedef struct
+{
 	GenericListRec list;
 	char *identifier;
 	char *driver;
-	char **match_product;
-	char **match_vendor;
-	char **match_device;
-	char **match_os;
-	char **match_pnpid;
-	char **match_usbid;
-	char **match_tag;
+	struct list match_product;
+	struct list match_vendor;
+	struct list match_device;
+	struct list match_os;
+	struct list match_pnpid;
+	struct list match_usbid;
+	struct list match_tag;
 	xf86TriState is_keyboard;
 	xf86TriState is_pointer;
 	xf86TriState is_joystick;
-- 
1.6.6.1



More information about the xorg-devel mailing list