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

Oleh Nykyforchyn oleh.nyk at gmail.com
Sun Oct 30 05:03:55 PDT 2011


Small fixes:

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 +++++-
 message                        |   11 ++++++++++
 5 files changed, 93 insertions(+), 8 deletions(-)
 create mode 100644 message

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index d39ab89..88909ed 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 f4b080f..eba97f8 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') {
@@ -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, "%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;
 
diff --git a/message b/message
new file mode 100644
index 0000000..c31c11f
--- /dev/null
+++ b/message
@@ -0,0 +1,11 @@
+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-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.
+
-- 
1.7.4.4



-- 
Oleh Nykyforchyn <oleh.nyk at gmail.com>


More information about the xorg-devel mailing list