[RFC] regular expression support in config files (try 2)
Oleh Nykyforchyn
oleh.nyk at gmail.com
Wed Jun 1 13:59:15 PDT 2011
Polished, simplified and more commented version. Hope that
I have taken into account previous comments. User can now
choose manually any matching modes for different patterns
in one line. I can't imagine that someone may want something
more in Match* statements.
-------------------------------
Add extended regexes support to InputClass Match* statements (try 2)
Any number of patterns can be written in one line either as
MatchProduct "foo|!bar" "something|re:^else$" "you" "!regex:n..d"
or as
MatchProduct "foo" "!bar|something" "regex:~else$" "you|!re:n..d"
etc. A regex ends at the end of the respective "piece", irrespective of '|'s.
Negated conditions prefixed by "!", regexes by "regex:" of "re:", can
be combined. Added also prefixes for all other matching modes in two versions
each: short and real name of the used function. Different modes, as well
as usual and negated patterns can be mixed in one line.
Signed-off-by: Oleh Nykyforchyn <oleh.nyk at gmail.com>
---
hw/xfree86/common/xf86Xinput.c | 147 +++++++++------
hw/xfree86/parser/InputClass.c | 407 +++++++++++++++++++++++++++-------------
hw/xfree86/parser/xf86Parser.h | 30 +++-
3 files changed, 396 insertions(+), 188 deletions(-)
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 26051ad..3152064 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -443,79 +443,108 @@ HostOS(void)
#endif
}
+/*
+ * Match an attribute against a pattern. Matching mode is
+ * 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_substring(const char *attr, const char *pattern)
+multi_match(const char *attr, xf86MatchPattern *pattern)
{
- return (strstr(attr, pattern)) ? 0 : -1;
-}
-
-#ifdef HAVE_FNMATCH_H
-static int
-match_pattern(const char *attr, const char *pattern)
-{
- return fnmatch(pattern, attr, 0);
-}
-#else
-#define match_pattern match_substring
-#endif
+ if (!pattern) return 0;
+ switch (pattern->mode)
+ {
+ case MATCH_IS_INVALID:
+ return 0;
+ case MATCH_IS_STRCMP:
+ return (strcmp(attr, pattern->str)) ? 0 : -1;
+ case MATCH_IS_STRCASECMP:
+ return (strcasecmp(attr, pattern->str)) ? 0 : -1;
+ /*
+ * If no Layout section is found, xf86ServerLayout.id becomes "(implicit)"
+ * It is convenient that "" in patterns means "no explicit layout"
+ */
+ case MATCH_IS_STRIMPLICIT:
+ if (*(pattern->str))
+ return (strcmp(attr, pattern->str)) ? 0 : -1;
+ else
+ return (strcmp(attr, "(implicit)")) ? 0 : -1;
+ case MATCH_IS_STRSTR:
+ return (strstr(attr, pattern->str)) ? 0 : -1;
+ case MATCH_IS_STRCASESTR:
+ return (strcasestr(attr, pattern->str)) ? 0 : -1;
#ifdef HAVE_FNMATCH_H
-static int
-match_path_pattern(const char *attr, const char *pattern)
-{
- return fnmatch(pattern, attr, FNM_PATHNAME);
-}
+ case MATCH_IS_FILENAME:
+ return (fnmatch(attr, pattern->str, 0)) ? 0 : -1;
+ case MATCH_IS_PATHNAME:
+ return (fnmatch(attr, pattern->str, FNM_PATHNAME)) ? 0 : -1;
#else
-#define match_path_pattern match_substring
+ case MATCH_IS_FILENAME:
+ return (strstr(attr, pattern->str)) ? 0 : -1;
+ case MATCH_IS_PATHNAME:
+ return (strstr(attr, pattern->str)) ? 0 : -1;
#endif
-
-/*
- * If no Layout section is found, xf86ServerLayout.id becomes "(implicit)"
- * It is convenient that "" in patterns means "no explicit layout"
- */
-static int
-match_string_implicit(const char *attr, const char *pattern)
-{
- if (strlen(pattern)) {
- return strcmp(attr, pattern);
- } else {
- return strcmp(attr,"(implicit)");
+ case MATCH_IS_REGEX:
+ default:
+ 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;
}
}
/*
- * Match an attribute against a list of NULL terminated arrays of patterns.
- * If a pattern in each list entry is matched, return TRUE.
+ * Match an attribute against a list of xf86MatchGroup's.
+ * Return TRUE only if each list entry is successful.
*/
static Bool
-MatchAttrToken(const char *attr, struct list *patterns,
- int (*compare)(const char *attr, const char *pattern))
+MatchAttrToken(const char *attr, struct list *groups)
{
- const xf86MatchGroup *group;
+ xf86MatchGroup *group;
+ xf86MatchPattern *pattern;
- /* If there are no patterns, accept the match */
- if (list_is_empty(patterns))
+ /* If there are no groups, accept the match */
+ if (list_is_empty(groups))
return TRUE;
- /* If there are patterns but no attribute, reject the match */
+ /* If there are groups but no attribute, reject the match */
if (!attr)
return FALSE;
/*
- * Otherwise, iterate the list of patterns ensuring each entry has a
- * match. Each list entry is a separate Match line of the same type.
+ * Otherwise, iterate the list of groups ensuring each entry has a
+ * match. Each list entry is a list of patterns obtained from
+ * a separate Match line.
*/
- list_for_each_entry(group, patterns, entry) {
- char * const *cur;
+ list_for_each_entry(group, groups, entry) {
Bool match = FALSE;
- for (cur = group->values; *cur; cur++)
- if ((*compare)(attr, *cur) == 0) {
- match = TRUE;
- break;
+ list_for_each_entry(pattern, &group->patterns, entry) {
+ if (multi_match(attr, pattern)) {
+ if (pattern->is_negated) /* negated pattern matched */
+ return FALSE; /* failure */
+ else /* appropriate pattern reached */
+ return TRUE; /* success */
}
- if (!match)
- return FALSE;
+ else if (pattern->is_negated) /* at least negated pattern not */
+ match = TRUE; /* matched - partial success */
+ }
+ if (!match) /* nothing successful is this Match line */
+ return FALSE; /* failure */
}
/* All the entries in the list matched the attribute */
@@ -531,31 +560,31 @@ InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
const InputAttributes *attrs)
{
/* MatchProduct substring */
- if (!MatchAttrToken(attrs->product, &iclass->match_product, match_substring))
+ if (!MatchAttrToken(attrs->product, &iclass->match_product))
return FALSE;
/* MatchVendor substring */
- if (!MatchAttrToken(attrs->vendor, &iclass->match_vendor, match_substring))
+ if (!MatchAttrToken(attrs->vendor, &iclass->match_vendor))
return FALSE;
/* MatchDevicePath pattern */
- if (!MatchAttrToken(attrs->device, &iclass->match_device, match_path_pattern))
+ if (!MatchAttrToken(attrs->device, &iclass->match_device))
return FALSE;
/* MatchOS case-insensitive string */
- if (!MatchAttrToken(HostOS(), &iclass->match_os, strcasecmp))
+ if (!MatchAttrToken(HostOS(), &iclass->match_os))
return FALSE;
/* MatchPnPID pattern */
- if (!MatchAttrToken(attrs->pnp_id, &iclass->match_pnpid, match_pattern))
+ if (!MatchAttrToken(attrs->pnp_id, &iclass->match_pnpid))
return FALSE;
/* MatchUSBID pattern */
- if (!MatchAttrToken(attrs->usb_id, &iclass->match_usbid, match_pattern))
+ if (!MatchAttrToken(attrs->usb_id, &iclass->match_usbid))
return FALSE;
/* MatchDriver string */
- if (!MatchAttrToken(idev->driver, &iclass->match_driver, strcmp))
+ if (!MatchAttrToken(idev->driver, &iclass->match_driver))
return FALSE;
/*
@@ -569,7 +598,7 @@ InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
if (!attrs->tags)
return FALSE;
for (tag = attrs->tags, match = FALSE; *tag; tag++) {
- if (MatchAttrToken(*tag, &iclass->match_tag, strcmp)) {
+ if (MatchAttrToken(*tag, &iclass->match_tag)) {
match = TRUE;
break;
}
@@ -579,9 +608,7 @@ InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
}
/* MatchLayout string */
- if (!list_is_empty(&iclass->match_layout)) {
- if (!MatchAttrToken(xf86ConfigLayout.id,
- &iclass->match_layout, match_string_implicit))
+ if (!MatchAttrToken(xf86ConfigLayout.id, &iclass->match_layout))
return FALSE;
}
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index 3f80170..b8500a8 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -64,25 +64,113 @@ xf86ConfigSymTabRec InputClassTab[] =
#define CLEANUP xf86freeInputClassList
-#define TOKEN_SEP "|"
+#define TOKEN_SEP '|'
+
+#define NEG_FLAG '!'
+
+static struct
+{
+ const char *prefix;
+ xf86MatchMode mode;
+}
+mode_prefixes[] = {
+ { "regex:", MATCH_IS_REGEX }, /* regular expression */
+ { "re:", MATCH_IS_REGEX },
+ { "str:", MATCH_IS_STRCMP }, /* strings coincide */
+ { "strcmp:", MATCH_IS_STRCMP },
+ { "cistr:", MATCH_IS_STRCASECMP }, /* the same, but case insensitive */
+ { "strcasecmp:", MATCH_IS_STRCASECMP },
+ { "stri:", MATCH_IS_STRIMPLICIT }, /* "" matches "(implicit)" layout */
+ { "strcmpimpl:", MATCH_IS_STRIMPLICIT },
+ { "sub:", MATCH_IS_STRSTR }, /* contains a substring */
+ { "strstr:", MATCH_IS_STRSTR },
+ { "cisub:", MATCH_IS_STRCASESTR }, /* the same, but case insensitive */
+ { "strcasestr:", MATCH_IS_STRCASESTR },
+ { "file:", MATCH_IS_FILENAME }, /* match a shell wildcard pattern */
+ { "fnmatch:", MATCH_IS_FILENAME },
+ { "path:", MATCH_IS_PATHNAME }, /* the same, but '/' treated separately */
+ { "pnmatch:", MATCH_IS_PATHNAME },
+ { NULL, MATCH_IS_INVALID } /* sentinel */
+};
static void
-add_group_entry(struct list *head, char **values)
+add_to_group_entry(xf86MatchGroup **group, const char *str,
+ xf86MatchMode pref_mode)
{
- xf86MatchGroup *group;
+ xf86MatchPattern *pattern;
+ unsigned n;
+ char *next;
+
+ if (!str) return;
+
+ if (!*group) {
+ *group = malloc(sizeof(**group));
+ if (!*group) return;
+ list_init(&(*group)->patterns);
+ }
+
+ again:
+ /* start new pattern: not negated, MATCH_IS_AUTO */
+ if ((pattern = calloc(sizeof(*pattern),1)) == NULL)
+ return;
+ list_add(&pattern->entry, &(*group)->patterns);
+
+ /* Pattern starting with '!' should NOT be matched */
+ if (*str == NEG_FLAG) {
+ pattern->is_negated = TRUE;
+ str++;
+ }
+
+ /* Check if there is a mode prefix */
+ for (n=0; mode_prefixes[n].prefix; n++) {
+ if (!strncmp(str, mode_prefixes[n].prefix,
+ strlen(mode_prefixes[n].prefix))) {
+ pattern->mode = mode_prefixes[n].mode;
+ str += strlen(mode_prefixes[n].prefix);
+ break;
+ }
+ }
+
+ if (pattern->mode == MATCH_IS_AUTO)
+ pattern->mode = pref_mode;
+
+ if ((next = index(str, TOKEN_SEP)))
+ n = next-str;
+ else
+ n = strlen(str);
+
+ if ((pattern->str = strndup(str, n)) == NULL) {
+ pattern->mode = MATCH_IS_INVALID;
+ }
- group = malloc(sizeof(*group));
- if (group) {
- group->values = values;
- list_add(&group->entry, head);
+ if (next) {
+ str = next+1;
+ goto again;
}
}
+static void
+free_group(xf86MatchGroup *group)
+{
+ xf86MatchPattern *pattern, *next_pattern;
+ 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);
+}
+
XF86ConfInputClassPtr
xf86parseInputClassSection(void)
{
int has_ident = FALSE;
int token;
+ xf86MatchGroup *group;
parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
@@ -98,6 +186,7 @@ xf86parseInputClassSection(void)
list_init(&ptr->match_layout);
while ((token = xf86getToken(InputClassTab)) != ENDSECTION) {
+ group = NULL;
switch (token) {
case COMMENT:
ptr->comment = xf86addComment(ptr->comment, val.str);
@@ -123,60 +212,110 @@ xf86parseInputClassSection(void)
case OPTION:
ptr->option_lst = xf86parseOption(ptr->option_lst);
break;
+ /*
+ * Argument of each Match{Product,..,Layout} statement
+ * can be a sequence of >=1 \"-quoted and space separated
+ * strings, which in turn are divided further by '|' chars
+ * to make a final list of patterns, unless a regular
+ * expression lasts until the closing \" of the current
+ * string, irrespective of '|'s. Hence
+ * MatchProduct "foo" "bar" "regex:^Yes|No$" "$100"
+ * MatchProduct "foo" "bar|regex:^Yes|No$" "$100"
+ * and
+ * MatchProduct "foo|bar" "regex:^Yes|No$" "$100"
+ * are equivalent, but not
+ * MatchProduct "foo" "bar" "regex:^Yes|No$|$100"
+ */
case MATCH_PRODUCT:
- if (xf86getSubToken(&(ptr->comment)) != STRING)
+ while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+ add_to_group_entry(&group, val.str, MATCH_IS_STRSTR);
+ }
+ xf86unGetToken(token);
+ if (group)
+ list_add(&group->entry, &ptr->match_product);
+ else
Error(QUOTE_MSG, "MatchProduct");
- add_group_entry(&ptr->match_product,
- xstrtokenize(val.str, TOKEN_SEP));
- break;
+ continue;
case MATCH_VENDOR:
- if (xf86getSubToken(&(ptr->comment)) != STRING)
+ while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+ add_to_group_entry(&group, val.str, MATCH_IS_STRSTR);
+ }
+ xf86unGetToken(token);
+ if (group)
+ list_add(&group->entry, &ptr->match_vendor);
+ else
Error(QUOTE_MSG, "MatchVendor");
- add_group_entry(&ptr->match_vendor,
- xstrtokenize(val.str, TOKEN_SEP));
- break;
+ continue;
case MATCH_DEVICE_PATH:
- if (xf86getSubToken(&(ptr->comment)) != STRING)
+ while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+ add_to_group_entry(&group, val.str, MATCH_IS_PATHNAME);
+ }
+ xf86unGetToken(token);
+ if (group)
+ list_add(&group->entry, &ptr->match_device);
+ else
Error(QUOTE_MSG, "MatchDevicePath");
- add_group_entry(&ptr->match_device,
- xstrtokenize(val.str, TOKEN_SEP));
- break;
+ continue;
case MATCH_OS:
- if (xf86getSubToken(&(ptr->comment)) != STRING)
+ while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+ add_to_group_entry(&group, val.str, MATCH_IS_STRCASECMP);
+ }
+ xf86unGetToken(token);
+ if (group)
+ list_add(&group->entry, &ptr->match_os);
+ else
Error(QUOTE_MSG, "MatchOS");
- add_group_entry(&ptr->match_os,
- xstrtokenize(val.str, TOKEN_SEP));
- break;
+ continue;
case MATCH_PNPID:
- if (xf86getSubToken(&(ptr->comment)) != STRING)
+ while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+ add_to_group_entry(&group, val.str, MATCH_IS_FILENAME);
+ }
+ xf86unGetToken(token);
+ if (group)
+ list_add(&group->entry, &ptr->match_pnpid);
+ else
Error(QUOTE_MSG, "MatchPnPID");
- add_group_entry(&ptr->match_pnpid,
- xstrtokenize(val.str, TOKEN_SEP));
- break;
+ continue;
case MATCH_USBID:
- if (xf86getSubToken(&(ptr->comment)) != STRING)
+ while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+ add_to_group_entry(&group, val.str, MATCH_IS_FILENAME);
+ }
+ xf86unGetToken(token);
+ if (group)
+ list_add(&group->entry, &ptr->match_usbid);
+ else
Error(QUOTE_MSG, "MatchUSBID");
- add_group_entry(&ptr->match_usbid,
- xstrtokenize(val.str, TOKEN_SEP));
- break;
+ continue;
case MATCH_DRIVER:
- if (xf86getSubToken(&(ptr->comment)) != STRING)
+ while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+ add_to_group_entry(&group, val.str, MATCH_IS_STRCMP);
+ }
+ xf86unGetToken(token);
+ if (group)
+ list_add(&group->entry, &ptr->match_driver);
+ else
Error(QUOTE_MSG, "MatchDriver");
- add_group_entry(&ptr->match_driver,
- xstrtokenize(val.str, TOKEN_SEP));
- break;
+ continue;
case MATCH_TAG:
- if (xf86getSubToken(&(ptr->comment)) != STRING)
+ while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+ add_to_group_entry(&group, val.str, MATCH_IS_STRCMP);
+ }
+ xf86unGetToken(token);
+ if (group)
+ list_add(&group->entry, &ptr->match_tag);
+ else
Error(QUOTE_MSG, "MatchTag");
- add_group_entry(&ptr->match_tag,
- xstrtokenize(val.str, TOKEN_SEP));
- break;
+ continue;
case MATCH_LAYOUT:
- if (xf86getSubToken(&(ptr->comment)) != STRING)
+ while ((token=xf86getSubTokenWithTab(&(ptr->comment),InputClassTab)) == STRING) {
+ add_to_group_entry(&group, val.str, MATCH_IS_STRIMPLICIT);
+ }
+ xf86unGetToken(token);
+ if (group)
+ list_add(&group->entry, &ptr->match_layout);
+ else
Error(QUOTE_MSG, "MatchLayout");
- add_group_entry(&ptr->match_layout,
- xstrtokenize(val.str, TOKEN_SEP));
- break;
+ continue;
case MATCH_IS_KEYBOARD:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchIsKeyboard");
@@ -244,11 +383,35 @@ xf86parseInputClassSection(void)
return ptr;
}
+static void
+print_pattern(FILE * cf, const xf86MatchPattern *pattern)
+{
+ if (!pattern) return;
+
+ fprintf(cf, "\"");
+ if (pattern->is_negated) fprintf(cf, "%c", NEG_FLAG);
+ if (pattern->mode == MATCH_IS_INVALID)
+ fprintf(cf, "invalid:");
+ else {
+ unsigned n;
+ for (n=0; mode_prefixes[n].prefix; n++) {
+ if (mode_prefixes[n].mode == pattern->mode) {
+ fprintf(cf, "%s", mode_prefixes[n].prefix);
+ break;
+ }
+ }
+ }
+ if (pattern->str)
+ fprintf(cf, "%s\"", pattern->str);
+ else
+ fprintf(cf, "(none)\"");
+}
+
void
xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
{
const xf86MatchGroup *group;
- char * const *cur;
+ const xf86MatchPattern *pattern;
while (ptr) {
fprintf(cf, "Section \"InputClass\"\n");
@@ -260,67 +423,76 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
fprintf(cf, "\tDriver \"%s\"\n", ptr->driver);
list_for_each_entry(group, &ptr->match_product, entry) {
- fprintf(cf, "\tMatchProduct \"");
- for (cur = group->values; *cur; cur++)
- fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
- *cur);
- fprintf(cf, "\"\n");
+ fprintf(cf, "\tMatchProduct ");
+ list_for_each_entry(pattern, &group->patterns, entry) {
+ fprintf(cf, " ");
+ print_pattern(cf, pattern);
+ }
+ fprintf(cf, "\n");
}
list_for_each_entry(group, &ptr->match_vendor, entry) {
- fprintf(cf, "\tMatchVendor \"");
- for (cur = group->values; *cur; cur++)
- fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
- *cur);
- fprintf(cf, "\"\n");
+ fprintf(cf, "\tMatchVendor ");
+ list_for_each_entry(pattern, &group->patterns, entry) {
+ fprintf(cf, " ");
+ print_pattern(cf, pattern);
+ }
+ fprintf(cf, "\n");
}
list_for_each_entry(group, &ptr->match_device, entry) {
- fprintf(cf, "\tMatchDevicePath \"");
- for (cur = group->values; *cur; cur++)
- fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
- *cur);
- fprintf(cf, "\"\n");
+ fprintf(cf, "\tMatchDevicePath ");
+ list_for_each_entry(pattern, &group->patterns, entry) {
+ fprintf(cf, " ");
+ print_pattern(cf, pattern);
+ }
+ fprintf(cf, "\n");
}
list_for_each_entry(group, &ptr->match_os, entry) {
- fprintf(cf, "\tMatchOS \"");
- for (cur = group->values; *cur; cur++)
- fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
- *cur);
- fprintf(cf, "\"\n");
+ fprintf(cf, "\tMatchOS ");
+ list_for_each_entry(pattern, &group->patterns, entry) {
+ fprintf(cf, " ");
+ print_pattern(cf, pattern);
+ }
+ fprintf(cf, "\n");
}
list_for_each_entry(group, &ptr->match_pnpid, entry) {
- fprintf(cf, "\tMatchPnPID \"");
- for (cur = group->values; *cur; cur++)
- fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
- *cur);
- fprintf(cf, "\"\n");
+ fprintf(cf, "\tMatchPnPID ");
+ list_for_each_entry(pattern, &group->patterns, entry) {
+ fprintf(cf, " ");
+ print_pattern(cf, pattern);
+ }
+ fprintf(cf, "\n");
}
list_for_each_entry(group, &ptr->match_usbid, entry) {
- fprintf(cf, "\tMatchUSBID \"");
- for (cur = group->values; *cur; cur++)
- fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
- *cur);
- fprintf(cf, "\"\n");
+ fprintf(cf, "\tMatchUSBID ");
+ list_for_each_entry(pattern, &group->patterns, entry) {
+ fprintf(cf, " ");
+ print_pattern(cf, pattern);
+ }
+ fprintf(cf, "\n");
}
list_for_each_entry(group, &ptr->match_driver, entry) {
- fprintf(cf, "\tMatchDriver \"");
- for (cur = group->values; *cur; cur++)
- fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
- *cur);
- fprintf(cf, "\"\n");
+ fprintf(cf, "\tMatchDriver ");
+ list_for_each_entry(pattern, &group->patterns, entry) {
+ fprintf(cf, " ");
+ print_pattern(cf, pattern);
+ }
+ fprintf(cf, "\n");
}
list_for_each_entry(group, &ptr->match_tag, entry) {
- fprintf(cf, "\tMatchTag \"");
- for (cur = group->values; *cur; cur++)
- fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
- *cur);
- fprintf(cf, "\"\n");
+ fprintf(cf, "\tMatchTag ");
+ list_for_each_entry(pattern, &group->patterns, entry) {
+ fprintf(cf, " ");
+ print_pattern(cf, pattern);
+ }
+ fprintf(cf, "\n");
}
list_for_each_entry(group, &ptr->match_layout, entry) {
- fprintf(cf, "\tMatchLayout \"");
- for (cur = group->values; *cur; cur++)
- fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
- *cur);
- fprintf(cf, "\"\n");
+ fprintf(cf, "\tMatchLayout ");
+ list_for_each_entry(pattern, &group->patterns, entry) {
+ fprintf(cf, " ");
+ print_pattern(cf, pattern);
+ }
+ fprintf(cf, "\n");
}
if (ptr->is_keyboard.set)
@@ -353,65 +525,46 @@ xf86freeInputClassList (XF86ConfInputClassPtr ptr)
XF86ConfInputClassPtr prev;
while (ptr) {
- xf86MatchGroup *group, *next;
- char **list;
+ xf86MatchGroup *group, *next_group;
TestFree(ptr->identifier);
TestFree(ptr->driver);
- list_for_each_entry_safe(group, next, &ptr->match_product, entry) {
+ list_for_each_entry_safe(group, next_group, &ptr->match_product, entry) {
list_del(&group->entry);
- for (list = group->values; *list; list++)
- free(*list);
- free(group);
+ free_group(group);
}
- list_for_each_entry_safe(group, next, &ptr->match_vendor, entry) {
+ list_for_each_entry_safe(group, next_group, &ptr->match_vendor, entry) {
list_del(&group->entry);
- for (list = group->values; *list; list++)
- free(*list);
- free(group);
+ free_group(group);
}
- list_for_each_entry_safe(group, next, &ptr->match_device, entry) {
+ list_for_each_entry_safe(group, next_group, &ptr->match_device, entry) {
list_del(&group->entry);
- for (list = group->values; *list; list++)
- free(*list);
- free(group);
+ free_group(group);
}
- list_for_each_entry_safe(group, next, &ptr->match_os, entry) {
+ list_for_each_entry_safe(group, next_group, &ptr->match_os, entry) {
list_del(&group->entry);
- for (list = group->values; *list; list++)
- free(*list);
- free(group);
+ free_group(group);
}
- list_for_each_entry_safe(group, next, &ptr->match_pnpid, entry) {
+ list_for_each_entry_safe(group, next_group, &ptr->match_pnpid, entry) {
list_del(&group->entry);
- for (list = group->values; *list; list++)
- free(*list);
- free(group);
+ free_group(group);
}
- list_for_each_entry_safe(group, next, &ptr->match_usbid, entry) {
+ list_for_each_entry_safe(group, next_group, &ptr->match_usbid, entry) {
list_del(&group->entry);
- for (list = group->values; *list; list++)
- free(*list);
- free(group);
+ free_group(group);
}
- list_for_each_entry_safe(group, next, &ptr->match_driver, entry) {
+ list_for_each_entry_safe(group, next_group, &ptr->match_driver, entry) {
list_del(&group->entry);
- for (list = group->values; *list; list++)
- free(*list);
- free(group);
+ free_group(group);
}
- list_for_each_entry_safe(group, next, &ptr->match_tag, entry) {
+ list_for_each_entry_safe(group, next_group, &ptr->match_tag, entry) {
list_del(&group->entry);
- for (list = group->values; *list; list++)
- free(*list);
- free(group);
+ free_group(group);
}
- list_for_each_entry_safe(group, next, &ptr->match_layout, entry) {
+ list_for_each_entry_safe(group, next_group, &ptr->match_layout, entry) {
list_del(&group->entry);
- for (list = group->values; *list; list++)
- free(*list);
- free(group);
+ free_group(group);
}
TestFree(ptr->comment);
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index a8785c5..0fea7c4 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
@@ -341,10 +344,35 @@ xf86TriState;
typedef struct
{
struct list entry;
- char **values;
+ struct list patterns;
}
xf86MatchGroup;
+typedef enum
+{
+ MATCH_IS_INVALID = -1,
+ MATCH_IS_AUTO = 0,
+ MATCH_IS_STRCMP,
+ MATCH_IS_STRCASECMP,
+ MATCH_IS_STRIMPLICIT,
+ MATCH_IS_STRSTR,
+ MATCH_IS_STRCASESTR,
+ MATCH_IS_FILENAME,
+ MATCH_IS_PATHNAME,
+ MATCH_IS_REGEX
+}
+xf86MatchMode;
+
+typedef struct
+{
+ struct list entry;
+ Bool is_negated;
+ xf86MatchMode mode;
+ char *str;
+ regex_t *regex;
+}
+xf86MatchPattern;
+
typedef struct
{
GenericListRec list;
--
1.7.0.1
Oleh
--
Oleh Nykyforchyn <oleh.nyk at gmail.com>
More information about the xorg-devel
mailing list