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>
This commit is contained in:
Dan Nicholson 2010-06-07 20:39:57 -07:00 • committed by Peter Hutterer
commit a71bdff47d
4 changed files with 179 additions and 109 deletions

View file

@ -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;
return FALSE;
for (cur = group->values; *cur; cur++)
if ((*compare)(attr, *cur) == 0) {
match = TRUE;
break;
}
if (!match)
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;
}