[PATCH] xfree86: Allow InputClass entries to specify match type

Dan Nicholson dbn.lists at gmail.com
Thu Dec 2 06:19:15 PST 2010


The InputClass Match* entries are currently hardwired to offer a certain
variant of comparison for matching. For example, the MatchProduct entry
uses substring match. Add a second optional argument to the entry to
allow the match type to be specified.

	MatchProduct "foo*" "pattern"

The available match types are "string", "istring", "substring",
"isubstring", "path" and "pattern". See xorg.conf(5) for more details.
If no type is supplied, the previous default is used.

Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
---
 Sorry, I know this is late, but I've been sitting on this for months
 and forgot to send it. A rebased it to current HEAD, but it's been a
 while since I actually tested it. I can't see anything that's changed
 in the affected areas that would break it, though. Too late for 1.10?

 hw/xfree86/common/xf86Xinput.c       |   51 ++++++++++++---
 hw/xfree86/doc/man/xorg.conf.man.pre |   88 ++++++++++++++++++++------
 hw/xfree86/parser/InputClass.c       |  115 +++++++++++++++++++++++-----------
 hw/xfree86/parser/xf86Parser.h       |   12 ++++
 4 files changed, 199 insertions(+), 67 deletions(-)

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 81bb707..ac87119 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -450,6 +450,12 @@ match_substring(const char *attr, const char *pattern)
     return (strstr(attr, pattern)) ? 0 : -1;
 }
 
+static int
+match_isubstring(const char *attr, const char *pattern)
+{
+    return (strcasestr(attr, pattern)) ? 0 : -1;
+}
+
 #ifdef HAVE_FNMATCH_H
 static int
 match_pattern(const char *attr, const char *pattern)
@@ -475,8 +481,7 @@ match_path_pattern(const char *attr, const char *pattern)
  * If a pattern in each list entry is matched, return TRUE.
  */
 static Bool
-MatchAttrToken(const char *attr, struct list *patterns,
-               int (*compare)(const char *attr, const char *pattern))
+MatchAttrToken(const char *attr, struct list *patterns)
 {
     const xf86MatchGroup *group;
 
@@ -495,6 +500,32 @@ MatchAttrToken(const char *attr, struct list *patterns,
     list_for_each_entry(group, patterns, entry) {
         char * const *cur;
         Bool match = FALSE;
+        int (*compare)(const char *attr, const char *pattern);
+
+        switch (group->type) {
+        case MATCH_STRING:
+            compare = strcmp;
+            break;
+        case MATCH_ISTRING:
+            compare = strcasecmp;
+            break;
+        case MATCH_SUBSTRING:
+            compare = match_substring;
+            break;
+        case MATCH_ISUBSTRING:
+            compare = match_isubstring;
+            break;
+        case MATCH_PATH:
+            compare = match_path_pattern;
+            break;
+        case MATCH_PATTERN:
+            compare = match_pattern;
+            break;
+        default:
+            /* this shouldn't happen */
+            xf86Msg(X_ERROR, "Unrecognized match type %d\n", group->type);
+            return FALSE;
+        }
 
         for (cur = group->values; *cur; cur++)
             if ((*compare)(attr, *cur) == 0) {
@@ -518,31 +549,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;
 
     /*
@@ -556,7 +587,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;
             }
diff --git a/hw/xfree86/doc/man/xorg.conf.man.pre b/hw/xfree86/doc/man/xorg.conf.man.pre
index ba876c0..db9a955 100644
--- a/hw/xfree86/doc/man/xorg.conf.man.pre
+++ b/hw/xfree86/doc/man/xorg.conf.man.pre
@@ -1068,59 +1068,109 @@ attribute. For example:
 .B  "EndSection"
 .fi
 .RE
+.PP
+An optional second argument to the entry specifies the type of matching
+used. The recognized match types are:
+.RS 4
+.TP 16
+.B \*qstring\*q
+case-sensitive string
+.TP 16
+.B \*qistring\*q
+case-insensitive string
+.TP 16
+.B \*qsubstring\*q
+case-sensitive substring
+.TP 16
+.B \*qisubstring\*q
+case-insensitive substring
+.TP 16
+.B \*qpath\*q
+shell path pattern on systems providing
+.BR fnmatch (3)
+or
+.B \*qsubstring\*q
+matching otherwise
+.TP 16
+.B \*qpattern\*q
+shell wildcard pattern on systems providing
+.BR fnmatch (3)
+or
+.B \*qsubstring\*q
+matching otherwise
+.RE
+.PP
+Here is an example showing the optional nature of the match type:
+.PP
+.RS 4
+.nf
+.B "MatchVendor \*qfoo*\*q \*qpattern\*q # use the pattern match"
+.B "MatchVendor \*qfoo\*q            # use the default substring match"
+.fi
+.RE
+.PP
+The available match entries of this type are:
 .TP 7
 .BI "MatchProduct  \*q" matchproduct \*q
-This entry can be used to check if the substring
+This entry can be used to check
 .RI \*q matchproduct \*q
-occurs in the device's product name.
+against the device's product name. The default match type is
+.BR \*qsubstring\*q .
 .TP 7
 .BI "MatchVendor  \*q" matchvendor \*q
-This entry can be used to check if the substring
+This entry can be used to check
 .RI \*q matchvendor \*q
-occurs in the device's vendor name.
+against the device's vendor name. The default match type is
+.BR \*qsubstring\*q .
 .TP 7
 .BI "MatchDevicePath \*q" matchdevice \*q
-This entry can be used to check if the device file matches the
+This entry can be used to check if
 .RI \*q matchdevice \*q
-pathname pattern.
+matches the device file. The default match type is
+.BR \*qpath\*q .
 .TP 7
 .BI "MatchOS \*q" matchos \*q
-This entry can be used to check if the operating system matches the
-case-insensitive
+This entry can be used to check if the operating system matches
 .RI \*q matchos \*q
 string. This entry is only supported on platforms providing the
 .BR uname (2)
-system call.
+system call. The default match type is
+.BR \*qistring\*q .
 .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.
+string. The default match type is
+.BR \*qpattern\*q .
 .TP 7
 .BI "MatchUSBID \*q" matchusb \*q
 The device's USB ID can be checked against the
 .RI \*q matchusb \*q
-shell wildcard pattern. The ID is constructed as lowercase hexadecimal numbers
-separated by a ':'. This is the same format as the
+string. The ID is constructed as lowercase hexadecimal numbers separated by a
+':'. This is the same format as the
 .BR lsusb (8)
-program.
+program. The default match type is
+.BR \*qpattern\*q .
 .TP 7
 .BI "MatchDriver \*q" matchdriver \*q
-Check the case-sensitive string
+Check the string
 .RI \*q matchdriver \*q
 against the currently configured driver of the device. Ordering of sections
 using this entry is important since it will not match unless the driver has
 been set by the config backend or a previous
 .B InputClass
-section.
+section. The default match type is
+.BR \*qstring\*q .
 .TP 7
 .BI "MatchTag \*q" matchtag \*q
-This entry can be used to check if tags assigned by the config backend
-matches the
+This entry can be used to check if any of the tags assigned by the config
+backend match the
 .RI \*q matchtag \*q
-pattern. A match is found if at least one of the tags given in
+string. 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.
+matches at least one of the tags assigned by the backend. The default match
+type is
+.BR \*qstring\*q .
 .PP
 The second type of entry is used to match device types. These entries take a
 boolean argument similar to
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index 9f88e7e..8cd9613 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -65,16 +65,47 @@ xf86ConfigSymTabRec InputClassTab[] =
 
 #define TOKEN_SEP "|"
 
-static void
-add_group_entry(struct list *head, char **values)
+static Bool
+parse_match_entry(struct list *head, xf86MatchType def_type, const char *str)
 {
     xf86MatchGroup *group;
+    int token;
+
+    if (xf86getToken(NULL) != STRING) {
+        xf86parseError(QUOTE_MSG, str);
+        return FALSE;
+    }
+
+    group = XNFalloc(sizeof(*group));
+    group->values = xstrtokenize(val.str, TOKEN_SEP);
+    group->type = def_type;
+    list_add(&group->entry, head);
+
+    /* See if an alternate match type is specified */
+    if ((token = xf86getToken(NULL)) != STRING) {
+        xf86unGetToken(token);
+        return TRUE;
+    }
 
-    group = malloc(sizeof(*group));
-    if (group) {
-        group->values = values;
-        list_add(&group->entry, head);
+    /* Check the specified match type */
+    if (strcasecmp(val.str, "string"))
+        group->type = MATCH_STRING;
+    else if (strcasecmp(val.str, "istring"))
+        group->type = MATCH_ISTRING;
+    else if (strcasecmp(val.str, "substring"))
+        group->type = MATCH_SUBSTRING;
+    else if (strcasecmp(val.str, "isubstring"))
+        group->type = MATCH_ISUBSTRING;
+    else if (strcasecmp(val.str, "path"))
+        group->type = MATCH_PATH;
+    else if (strcasecmp(val.str, "pattern"))
+        group->type = MATCH_PATTERN;
+    else {
+        xf86parseError("Match type \"%s\" is not valid.", val.str);
+        return FALSE;
     }
+
+    return TRUE;
 }
 
 XF86ConfInputClassPtr
@@ -122,52 +153,60 @@ xf86parseInputClassSection(void)
             ptr->option_lst = xf86parseOption(ptr->option_lst);
             break;
         case MATCH_PRODUCT:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
-                Error(QUOTE_MSG, "MatchProduct");
-            add_group_entry(&ptr->match_product,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            if (!parse_match_entry(&ptr->match_product, MATCH_SUBSTRING,
+                                   "MatchProduct")) {
+                xf86freeInputClassList(ptr);
+                return NULL;
+            }
             break;
         case MATCH_VENDOR:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
-                Error(QUOTE_MSG, "MatchVendor");
-            add_group_entry(&ptr->match_vendor,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            if (!parse_match_entry(&ptr->match_vendor, MATCH_SUBSTRING,
+                                   "MatchVendor")) {
+                xf86freeInputClassList(ptr);
+                return NULL;
+            }
             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));
+            if (!parse_match_entry(&ptr->match_device, MATCH_PATH,
+                                   "MatchDevicePath")) {
+                xf86freeInputClassList(ptr);
+                return NULL;
+            }
             break;
         case MATCH_OS:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
-                Error(QUOTE_MSG, "MatchOS");
-            add_group_entry(&ptr->match_os,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            if (!parse_match_entry(&ptr->match_os, MATCH_ISTRING,
+                                   "MatchOS")) {
+                xf86freeInputClassList(ptr);
+                return NULL;
+            }
             break;
         case MATCH_PNPID:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
-                Error(QUOTE_MSG, "MatchPnPID");
-            add_group_entry(&ptr->match_pnpid,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            if (!parse_match_entry(&ptr->match_pnpid, MATCH_PATTERN,
+                                   "MatchPnPID")) {
+                xf86freeInputClassList(ptr);
+                return NULL;
+            }
             break;
         case MATCH_USBID:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
-                Error(QUOTE_MSG, "MatchUSBID");
-            add_group_entry(&ptr->match_usbid,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            if (!parse_match_entry(&ptr->match_usbid, MATCH_PATTERN,
+                                   "MatchUSBID")) {
+                xf86freeInputClassList(ptr);
+                return NULL;
+            }
             break;
         case MATCH_DRIVER:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
-                Error(QUOTE_MSG, "MatchDriver");
-            add_group_entry(&ptr->match_driver,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            if (!parse_match_entry(&ptr->match_driver, MATCH_STRING,
+                                   "MatchDriver")) {
+                xf86freeInputClassList(ptr);
+                return NULL;
+            }
             break;
         case MATCH_TAG:
-            if (xf86getSubToken(&(ptr->comment)) != STRING)
-                Error(QUOTE_MSG, "MatchTag");
-            add_group_entry(&ptr->match_tag,
-                            xstrtokenize(val.str, TOKEN_SEP));
+            if (!parse_match_entry(&ptr->match_tag, MATCH_STRING,
+                                   "MatchTag")) {
+                xf86freeInputClassList(ptr);
+                return NULL;
+            }
             break;
         case MATCH_IS_KEYBOARD:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index 4f279f1..2082ea3 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -338,9 +338,21 @@ typedef struct
 }
 xf86TriState;
 
+typedef enum
+{
+	MATCH_STRING,
+	MATCH_ISTRING,
+	MATCH_SUBSTRING,
+	MATCH_ISUBSTRING,
+	MATCH_PATH,
+	MATCH_PATTERN,
+}
+xf86MatchType;
+
 typedef struct
 {
 	struct list entry;
+	xf86MatchType type;
 	char **values;
 }
 xf86MatchGroup;
-- 
1.7.2.3



More information about the xorg-devel mailing list