[PATCH 2/2] xserver: Use extended regular expressions in Match entries

Oleh Nykyforchyn oleh.nyk at gmail.com
Wed Oct 26 03:06:40 PDT 2011


xserver: Use extended regular expressions in Match entries

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-9]$/"
is applied to a device only in layouts Seat0, Seat1, ..., Seat9. In particular,
this can allow 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 486a105..695f0b0 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -473,7 +473,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)
@@ -504,9 +506,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 5397713..b1132b8 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[n] != '\0') {
@@ -319,10 +346,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, "%c", 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

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001
Type: application/octet-stream
Size: 435 bytes
Desc: not available
URL: <http://lists.x.org/archives/xorg-devel/attachments/20111026/7c1025bb/attachment.obj>


More information about the xorg-devel mailing list