Commit 9b369f71 authored by Dan Nicholson's avatar Dan Nicholson Committed by Peter Hutterer

xfree86: Allow multiple arguments to InputClass matches

In order to keep the number of InputClass sections manageable, allow
matches to contain multiple arguments. The arguments will be separated
by the '|' character. This allows a policy to apply to multiple types of
devices. For example:

    Section "InputClass"
        Identifier "Inverted Mice"
        MatchProduct "Crazy Mouse|Silly Mouse"
        Option "InvertX" "yes"
    EndSection

This applies to the MatchProduct, MatchVendor and MatchDevicePath
entries. Currently there is no way to escape characters, so names or
patterns cannot contain '|'.
Signed-off-by: Dan Nicholson's avatarDan Nicholson <dbn.lists@gmail.com>
Reviewed-by: Peter Hutterer's avatarPeter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer's avatarPeter Hutterer <peter.hutterer@who-t.net>
parent a378e361
......@@ -502,20 +502,49 @@ AddOtherInputDevices(void)
static Bool
InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
{
if (iclass->match_product &&
(!attrs->product || !strstr(attrs->product, iclass->match_product)))
return FALSE;
if (iclass->match_vendor &&
(!attrs->vendor || !strstr(attrs->vendor, iclass->match_vendor)))
return FALSE;
if (iclass->match_device &&
char **cur;
Bool match;
if (iclass->match_product) {
if (!attrs->product)
return FALSE;
/* see if any of the values match */
for (cur = iclass->match_product, match = FALSE; *cur; cur++)
if (strstr(attrs->product, *cur)) {
match = TRUE;
break;
}
if (!match)
return FALSE;
}
if (iclass->match_vendor) {
if (!attrs->vendor)
return FALSE;
/* see if any of the values match */
for (cur = iclass->match_vendor, match = FALSE; *cur; cur++)
if (strstr(attrs->vendor, *cur)) {
match = TRUE;
break;
}
if (!match)
return FALSE;
}
if (iclass->match_device) {
if (!attrs->device)
return FALSE;
/* see if any of the values match */
for (cur = iclass->match_device, match = FALSE; *cur; cur++)
#ifdef HAVE_FNMATCH_H
(!attrs->device ||
fnmatch(iclass->match_device, attrs->device, 0) != 0))
if (fnmatch(*cur, attrs->device, 0) == 0) {
#else
(!attrs->device || !strstr(attrs->device, iclass->match_device)))
if (strstr(attrs->device, *cur)) {
#endif
return FALSE;
match = TRUE;
break;
}
if (!match)
return FALSE;
}
if (iclass->is_keyboard.set &&
iclass->is_keyboard.val != !!(attrs->flags & ATTR_KEYBOARD))
return FALSE;
......
......@@ -1039,17 +1039,20 @@ The allowed matching entries are shown below.
.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.
occurs in the device's product name. Multiple substrings can be matched by
separating arguments with a '|' character.
.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.
occurs in the device's vendor name. Multiple substrings can be matched by
separating arguments with a '|' character.
.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.
pathname pattern. Multiple patterns can be matched by separating arguments
with a '|' character.
.TP 7
.BI "MatchIsKeyboard \*q" bool \*q
.TP 7
......
......@@ -29,6 +29,8 @@
#include <xorg-config.h>
#endif
#include <string.h>
#include "os.h"
#include "xf86Parser.h"
#include "xf86tokens.h"
#include "Configint.h"
......@@ -56,6 +58,46 @@ xf86ConfigSymTabRec InputClassTab[] =
#define CLEANUP xf86freeInputClassList
#define TOKEN_SEP "|"
/*
* Tokenize a string into a NULL terminated array of strings. Always returns
* an allocated array unless an error occurs.
*/
static char **
tokenize(const char *str)
{
char **list, **nlist;
char *tok, *tmp;
unsigned num = 0, n;
list = calloc(1, sizeof(*list));
if (!list)
return NULL;
tmp = strdup(str);
if (!tmp)
goto error;
for (tok = strtok(tmp, TOKEN_SEP); tok; tok = strtok(NULL, TOKEN_SEP)) {
nlist = realloc(list, (num + 2) * sizeof(*list));
if (!nlist)
goto error;
list = nlist;
list[num] = strdup(tok);
if (!list[num])
goto error;
list[++num] = NULL;
}
free(tmp);
return list;
error:
TestFree(tmp);
for (n = 0; n < num; n++)
free(list[n]);
TestFree(list);
return NULL;
}
XF86ConfInputClassPtr
xf86parseInputClassSection(void)
{
......@@ -91,17 +133,17 @@ xf86parseInputClassSection(void)
case MATCH_PRODUCT:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchProduct");
ptr->match_product = val.str;
ptr->match_product = tokenize(val.str);
break;
case MATCH_VENDOR:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchVendor");
ptr->match_vendor = val.str;
ptr->match_vendor = tokenize(val.str);
break;
case MATCH_DEVICE_PATH:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchDevicePath");
ptr->match_device = val.str;
ptr->match_device = tokenize(val.str);
break;
case MATCH_IS_KEYBOARD:
if (xf86getSubToken(&(ptr->comment)) != STRING)
......@@ -173,6 +215,8 @@ xf86parseInputClassSection(void)
void
xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
{
char **list;
while (ptr) {
fprintf(cf, "Section \"InputClass\"\n");
if (ptr->comment)
......@@ -181,12 +225,30 @@ 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)
fprintf(cf, "\tMatchProduct \"%s\"\n", ptr->match_product);
if (ptr->match_vendor)
fprintf(cf, "\tMatchVendor \"%s\"\n", ptr->match_vendor);
if (ptr->match_device)
fprintf(cf, "\tMatchDevicePath \"%s\"\n", ptr->match_device);
if (ptr->match_product) {
fprintf(cf, "\tMatchProduct \"");
for (list = ptr->match_product; *list; list++)
fprintf(cf, "%s%s",
list == ptr->match_product ? "" : TOKEN_SEP,
*list);
fprintf(cf, "\"\n");
}
if (ptr->match_vendor) {
fprintf(cf, "\tMatchVendor \"");
for (list = ptr->match_vendor; *list; list++)
fprintf(cf, "%s%s",
list == ptr->match_vendor ? "" : TOKEN_SEP,
*list);
fprintf(cf, "\"\n");
}
if (ptr->match_device) {
fprintf(cf, "\tMatchDevicePath \"");
for (list = ptr->match_device; *list; list++)
fprintf(cf, "%s%s",
list == ptr->match_device ? "" : TOKEN_SEP,
*list);
fprintf(cf, "\"\n");
}
if (ptr->is_keyboard.set)
fprintf(cf, "\tIsKeyboard \"%s\"\n",
ptr->is_keyboard.val ? "yes" : "no");
......@@ -215,13 +277,26 @@ void
xf86freeInputClassList (XF86ConfInputClassPtr ptr)
{
XF86ConfInputClassPtr prev;
char **list;
while (ptr) {
TestFree(ptr->identifier);
TestFree(ptr->driver);
TestFree(ptr->match_product);
TestFree(ptr->match_vendor);
TestFree(ptr->match_device);
if (ptr->match_product) {
for (list = ptr->match_product; *list; list++)
free(*list);
free(ptr->match_product);
}
if (ptr->match_vendor) {
for (list = ptr->match_vendor; *list; list++)
free(*list);
free(ptr->match_vendor);
}
if (ptr->match_device) {
for (list = ptr->match_device; *list; list++)
free(*list);
free(ptr->match_device);
}
TestFree(ptr->comment);
xf86optionListFree(ptr->option_lst);
......
......@@ -343,9 +343,9 @@ typedef struct
GenericListRec list;
char *identifier;
char *driver;
char *match_product;
char *match_vendor;
char *match_device;
char **match_product;
char **match_vendor;
char **match_device;
xf86TriState is_keyboard;
xf86TriState is_pointer;
xf86TriState is_joystick;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment