summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Nicholson <dbn.lists@gmail.com>2010-06-07 20:39:57 -0700
committerPeter Hutterer <peter.hutterer@who-t.net>2010-06-11 09:41:02 +1000
commita71bdff47d4cc80da6ceeb548db1dcc8e8b59702 (patch)
tree04c8481244bbfba1da2568af7626eed6f623f1da
parent842625928632ae767b0689fcdb5103c1779a4c91 (diff)
xfree86: Allow multiple InputClass Match* entries for && matching
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@gmail.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--hw/xfree86/common/xf86Xinput.c49
-rw-r--r--hw/xfree86/doc/man/xorg.conf.man.pre50
-rw-r--r--hw/xfree86/parser/InputClass.c167
-rw-r--r--hw/xfree86/parser/xf86Parser.h22
4 files changed, 179 insertions, 109 deletions
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 421803962..fa0ed8592 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 63dbb68b1..f6b90be2c 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 bdcfba486..f2b46bb1c 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 a86462f93..26d9a5b33 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;