[PATCH 2/2 v3] xserver: Use extended regular expressions in Match entries
Oleh R. Nykyforchyn
oleh.nyk at gmail.com
Sat Nov 12 07:25:09 PST 2011
Together with "simple" matching modes (via strcmp() or fnmatch() etc), which
are natural for different types on input device attributes, it will be allowed
to match against extended regular expressions (cf. man 7 regex). For example,
an InputClass with
MatchLayout "regex:/^Seat[0-5]$/"
is applied to a device only in layouts Seat0, Seat1, ..., Seat5. In particular,
this can allow for path matching on systems without fnmatch(). A regular
expression is compiled only before its first use.
Signed-off-by: Oleh Nykyforchyn <oleh.nyk at gmail.com>
---
hw/xfree86/common/xf86Xinput.c | 23 +++++++++++++++++++--
hw/xfree86/man/xorg.conf.man | 19 ++++++++++++++++++
hw/xfree86/parser/InputClass.c | 41 ++++++++++++++++++++++++++++++++++++---
hw/xfree86/parser/xf86Parser.h | 7 +++++-
4 files changed, 82 insertions(+), 8 deletions(-)
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index fa63550..136924f 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -474,7 +474,9 @@ HostOS(void)
/*
* Match an attribute against a pattern. Matching mode is
- * determined by pattern->mode member.
+ * determined by pattern->mode member. If the mode is REGEX,
+ * then regex_t is allocated and compiled only during
+ * the first call, to save time and memory.
*/
static int
match_token(const char *attr, xf86MatchPattern *pattern)
@@ -505,9 +507,24 @@ match_token(const char *attr, xf86MatchPattern *pattern)
case MATCH_IS_PATHNAME:
return (strstr(attr, pattern->str)) ? -1 : 0;
#endif
+ case MATCH_IS_REGEX:
default:
- /* Impossible */
- return 0;
+ if (pattern->regex == NULL) {
+ int r;
+ if ((pattern->regex = malloc(sizeof(regex_t))) == NULL) {
+ pattern->mode = MATCH_IS_INVALID;
+ return 0;
+ }
+ r = regcomp(pattern->regex, pattern->str, REG_EXTENDED | REG_NOSUB);
+ if (r) { /* Wrong regex */
+ regfree(pattern->regex);
+ free(pattern->regex);
+ xf86Msg(X_ERROR, "Wrong regex: \"%s\"\n", pattern->str);
+ pattern->mode = MATCH_IS_INVALID;
+ return 0;
+ }
+ }
+ return (regexec(pattern->regex, attr,0, NULL, 0)) ? 0 : -1;
}
}
diff --git a/hw/xfree86/man/xorg.conf.man b/hw/xfree86/man/xorg.conf.man
index 996798f..31b4cfc 100644
--- a/hw/xfree86/man/xorg.conf.man
+++ b/hw/xfree86/man/xorg.conf.man
@@ -1146,6 +1146,25 @@ if no named
.B ServerLayout
sections have been found.
.PP
+To apply more sophicticated conditions, an entire attribute can be matched
+against an extended regular expression (see
+.BR regex (7)
+):
+.PP
+.RS 4
+.nf
+.B " # product string must start with Experimental
+.B " # and end with Device
+.B " MatchProduct \*qregex:_^Experimental.*Device$_\*q"
+.fi
+.RE
+.PP
+Such a pattern is prefixed with "regex:", and the next character, which
+may be arbitrary, is used as a two-side delimiter, i.e. the regular
+expression starts after it and lasts until its next occurrence, or to
+the end of the argument, if the delimiting character has not been found
+again.
+.PP
The second type of entry is used to match device types. These entries take a
boolean argument similar to
.B Option
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index 0ce44cd..4e2c7a6 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -66,6 +66,8 @@ xf86ConfigSymTabRec InputClassTab[] =
#define TOKEN_SEP "|"
+#define REGEX_PREFIX "regex:"
+
static void
free_group(xf86MatchGroup *group)
{
@@ -74,6 +76,10 @@ free_group(xf86MatchGroup *group)
list_del(&pattern->entry);
if (pattern->str)
free(pattern->str);
+ if ((pattern->mode == MATCH_IS_REGEX) && pattern->regex) {
+ regfree(pattern->regex);
+ free(pattern->regex);
+ }
free(pattern);
}
free(group);
@@ -103,11 +109,32 @@ create_group(const char *str,
}
list_add(&pattern->entry, &group->patterns);
- pattern->mode = pref_mode;
-
- n = strcspn(str, TOKEN_SEP);
+ /* Check if there is a mode prefix */
+ if (!strncmp(str,REGEX_PREFIX,strlen(REGEX_PREFIX))) {
+ pattern->mode = MATCH_IS_REGEX;
+ str += strlen(REGEX_PREFIX);
+ if (*str) {
+ char *last;
+ last = strchr(str+1, *str);
+ if (last)
+ n = (last-str)-1;
+ else
+ n = strlen(str+1);
+ pattern->str = strndup(str+1, n);
+ str += n+1;
+ if (*str) str++;
+ }
+ else
+ pattern->str = NULL;
+ }
+ else {
+ pattern->mode = pref_mode;
+ n = strcspn(str, TOKEN_SEP);
+ pattern->str = strndup(str, n);
+ str += n;
+ }
- if ((pattern->str = strndup(str, n)) == NULL)
+ if (pattern->str == NULL)
pattern->mode = MATCH_IS_INVALID;
if (*str != '\0') {
@@ -346,10 +373,16 @@ print_pattern(FILE * cf, const xf86MatchPattern *pattern)
if (pattern->mode == MATCH_IS_INVALID)
fprintf(cf, "invalid:");
+ else
+ if (pattern->mode == MATCH_IS_REGEX)
+ /* FIXME: Hope there is no '_' in the pattern */
+ fprintf(cf, REGEX_PREFIX "_");
if (pattern->str)
fprintf(cf, "%s", pattern->str);
else
fprintf(cf, "(none)");
+ if (pattern->mode == MATCH_IS_REGEX)
+ fprintf(cf, "_");
if (pattern->entry.next)
fprintf(cf, "%s", TOKEN_SEP);
}
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index b02923f..294ae30 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -68,6 +68,9 @@
#include "xf86Optrec.h"
#include "list.h"
+#include <sys/types.h>
+#include <regex.h>
+
#define HAVE_PARSER_DECLS
typedef struct
@@ -353,7 +356,8 @@ typedef enum
MATCH_IS_STRSTR,
MATCH_IS_STRCASESTR,
MATCH_IS_FILENAME,
- MATCH_IS_PATHNAME
+ MATCH_IS_PATHNAME,
+ MATCH_IS_REGEX
}
xf86MatchMode;
@@ -362,6 +366,7 @@ typedef struct
struct list entry;
xf86MatchMode mode;
char *str;
+ regex_t *regex;
}
xf86MatchPattern;
--
1.7.4.4
More information about the xorg-devel
mailing list