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

Oleh Nykyforchyn oleh.nyk at gmail.com
Mon Jun 20 00:09:59 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,
    MatchProduct "!regex:/^USB/&regex:%Optical Mouse$%"
matches non-USB optical mice. Regex patterns can be arbitarily mixed with
"simple" ones.

Signed-off-by: Oleh Nykyforchyn <oleh.nyk at gmail.com>
---
 hw/xfree86/common/xf86Xinput.c |   23 +++++++++++++++++++--
 hw/xfree86/parser/InputClass.c |   42 ++++++++++++++++++++++++++++++++-------
 hw/xfree86/parser/xf86Parser.h |    7 +++++-
 3 files changed, 60 insertions(+), 12 deletions(-)

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 3a16dc0..f617a96 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -445,7 +445,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)
@@ -476,9 +478,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/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index 2d78f05..a360f78 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -69,6 +69,8 @@ xf86ConfigSymTabRec InputClassTab[] =
 
 #define NEG_FLAG '!'
 
+#define REGEX_PREFIX "regex:"
+
 
 static void
 free_group(xf86MatchGroup *group)
@@ -118,17 +120,38 @@ create_group(const char *str,
         str++;
     }
 
-    pattern->mode = pref_mode;
-
-    n = strcspn(str, sep);
-
-    pattern->is_last = (str[n] != LOG_AND);
+    /* 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, 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') {
-        str += n+1;
+    pattern->is_last = (*str != LOG_AND);
+
+    if (*str) {
+        str++;
         goto again;
     }
 
@@ -339,6 +362,9 @@ print_pattern(FILE * cf, const xf86MatchPattern *pattern)
         fprintf(cf, "%c", NEG_FLAG);
     if (pattern->mode == MATCH_IS_INVALID)
         fprintf(cf, "invalid:");
+    else
+    if (pattern->mode == MATCH_IS_REGEX)
+        fprintf(cf, "regex:");
     if (pattern->str)
         fprintf(cf, "%s", pattern->str);
     else
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index 6a42161..16e215a 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;
 
@@ -364,6 +368,7 @@ typedef struct
 	Bool is_negated;
 	xf86MatchMode mode;
 	char *str;
+	regex_t *regex;
 }
 xf86MatchPattern;
 
-- 
1.7.4.4



More information about the xorg-devel mailing list