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

Peter Hutterer peter.hutterer at who-t.net
Sun Dec 5 21:29:00 PST 2010


On Thu, Dec 02, 2010 at 06:19:15AM -0800, Dan Nicholson wrote:
> 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.

I wonder if it is possible to support sed- or grep-like matching instead of
adding match types like this?

something like?
    MatchProduct "s/pattern/i"

Cheers,
  Peter

> 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