[PATCH 3/3] xserver: Use lists and constants for matching modes in Match entries

Oleh Nykyforchyn oleh.nyk at gmail.com
Thu Jun 9 07:58:14 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/man/xorg.conf.man   |   17 +++++++++++++++--
 hw/xfree86/parser/InputClass.c |   17 ++++++++++++++++-
 hw/xfree86/parser/xf86Parser.h |    7 ++++++-
 4 files changed, 57 insertions(+), 7 deletions(-)

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 42ab747..4fe44ee 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/man/xorg.conf.man b/hw/xfree86/man/xorg.conf.man
index d88db61..c4324f2 100644
--- a/hw/xfree86/man/xorg.conf.man
+++ b/hw/xfree86/man/xorg.conf.man
@@ -1162,12 +1162,25 @@ if no named
 .B ServerLayout
 sections have been found.
 .PP
-Finally, it is allowed to join via '|' any adjacent patterns, so a match
+To apply a more specific condition, e.g. to select devices with product
+names that start with "Advanced" and end with "Gadget", extended regular
+expressions (see
+.BR regex (7)
+), prefixed by "regex:", can be used as patterns:
+.PP
+.RS 4
+.nf
+.B  "    MatchProduct \*qregex:^Advanced.*Gadget$\*q"
+.fi
+.RE
+.PP
+Finally, it is allowed to join via '|' any adjacent patterns, except
+regular expressions, in which '|' has a special meaning, so a match
 entry can look like
 .PP
 .RS 4
 .nf
-.B  "    MatchProduct \*q!USB|Optical Mouse|Touchpad\*q"
+.B  "    MatchProduct \*q!regex:^USB\*q \*qOptical Mouse|Touchpad\*q"
 .fi
 .RE
 .PP
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index 3475de2..72e3d1e 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -68,6 +68,8 @@ xf86ConfigSymTabRec InputClassTab[] =
 
 #define NEG_FLAG '!'
 
+#define REGEX_PREFIX "regex:"
+
 
 static void
 add_to_group(xf86MatchGroup **group, const char *str,
@@ -98,7 +100,13 @@ add_to_group(xf86MatchGroup **group, const char *str,
         str++;
     }
 
-    pattern->mode = pref_mode;
+    /* Check if there is a mode prefix */
+    if (!strncmp(str,REGEX_PREFIX,strlen(REGEX_PREFIX))) {
+        pattern->mode = MATCH_IS_REGEX;
+        str += strlen(REGEX_PREFIX);
+    }
+    else
+        pattern->mode = pref_mode;
 
     if ((next = index(str, TOKEN_SEP)))
         n = next-str;
@@ -122,6 +130,10 @@ free_group(xf86MatchGroup *group)
     list_for_each_entry_safe(pattern, next_pattern, &group->patterns, entry) {
         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);
@@ -341,6 +353,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 faf5ab8..2d98992 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;
 
@@ -363,6 +367,7 @@ typedef struct
 	Bool is_negated;
 	xf86MatchMode mode;
 	char *str;
+	regex_t *regex;
 }
 xf86MatchPattern;
 
-- 
1.6.4



More information about the xorg-devel mailing list