From 9b369f71273fb117c982e6ce16cd4462f206d365 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Wed, 10 Feb 2010 15:36:47 +1000 Subject: [PATCH] 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 Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- hw/xfree86/common/xf86Xinput.c | 51 ++++++++++---- hw/xfree86/doc/man/xorg.conf.man.pre | 9 ++- hw/xfree86/parser/InputClass.c | 99 ++++++++++++++++++++++++---- hw/xfree86/parser/xf86Parser.h | 6 +- 4 files changed, 136 insertions(+), 29 deletions(-) diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index b37dae62a..8ac9d268f 100644 --- a/hw/xfree86/common/xf86Xinput.c +++ b/hw/xfree86/common/xf86Xinput.c @@ -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; diff --git a/hw/xfree86/doc/man/xorg.conf.man.pre b/hw/xfree86/doc/man/xorg.conf.man.pre index ee91b9afe..69f475107 100644 --- a/hw/xfree86/doc/man/xorg.conf.man.pre +++ b/hw/xfree86/doc/man/xorg.conf.man.pre @@ -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 diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c index 1c9816012..8041740a8 100644 --- a/hw/xfree86/parser/InputClass.c +++ b/hw/xfree86/parser/InputClass.c @@ -29,6 +29,8 @@ #include #endif +#include +#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); diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h index 5e8351fc4..b6d40a1f3 100644 --- a/hw/xfree86/parser/xf86Parser.h +++ b/hw/xfree86/parser/xf86Parser.h @@ -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;