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 <[email protected]>
---
 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

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to