Eric Pouech : dbghelp: Rewrote a simple regular expression matcher, and use for implementing SymMatchString[AW].
Alexandre Julliard
julliard at winehq.org
Mon Jan 23 13:01:11 CST 2012
Module: wine
Branch: master
Commit: be9a7b9b97b5e3a9223be232dfd52ce49c0ec26c
URL: http://source.winehq.org/git/wine.git/?a=commit;h=be9a7b9b97b5e3a9223be232dfd52ce49c0ec26c
Author: Eric Pouech <eric.pouech at orange.fr>
Date: Sun Jan 22 12:57:53 2012 +0100
dbghelp: Rewrote a simple regular expression matcher, and use for implementing SymMatchString[AW].
---
dlls/dbghelp/symbol.c | 176 ++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 152 insertions(+), 24 deletions(-)
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c
index ac1824b..ed2ce01 100644
--- a/dlls/dbghelp/symbol.c
+++ b/dlls/dbghelp/symbol.c
@@ -1873,50 +1873,178 @@ DWORD WINAPI UnDecorateSymbolName(PCSTR DecoratedName, PSTR UnDecoratedName,
return strlen(UnDecoratedName);
}
+#define WILDCHAR(x) (-(x))
+
+static int re_fetch_char(const WCHAR** re)
+{
+ switch (**re)
+ {
+ case '\\': (*re)++; return *(*re)++;
+ case '*': case '[': case '?': case '+': case '#': case ']': return WILDCHAR(*(*re)++);
+ default: return *(*re)++;
+ }
+}
+
+static inline int re_match_char(WCHAR ch1, WCHAR ch2, BOOL _case)
+{
+ return _case ? ch1 - ch2 : toupperW(ch1) - toupperW(ch2);
+}
+
+static const WCHAR* re_match_one(const WCHAR* string, const WCHAR* elt, BOOL _case)
+{
+ int ch1, prev = 0;
+ unsigned state = 0;
+
+ switch (ch1 = re_fetch_char(&elt))
+ {
+ default:
+ return (ch1 >= 0 && re_match_char(*string, ch1, _case) == 0) ? ++string : NULL;
+ case WILDCHAR('?'): return *string ? ++string : NULL;
+ case WILDCHAR('*'): assert(0);
+ case WILDCHAR('['): break;
+ }
+
+ for (;;)
+ {
+ ch1 = re_fetch_char(&elt);
+ if (ch1 == WILDCHAR(']')) return NULL;
+ if (state == 1 && ch1 == '-') state = 2;
+ else
+ {
+ if (re_match_char(*string, ch1, _case) == 0) return ++string;
+ switch (state)
+ {
+ case 0:
+ state = 1;
+ prev = ch1;
+ break;
+ case 1:
+ state = 0;
+ break;
+ case 2:
+ if (prev >= 0 && ch1 >= 0 && re_match_char(prev, *string, _case) <= 0 &&
+ re_match_char(*string, ch1, _case) <= 0)
+ return ++string;
+ state = 0;
+ break;
+ }
+ }
+ }
+}
+
+/******************************************************************
+ * re_match_multi
+ *
+ * match a substring of *pstring according to *pre regular expression
+ * pstring and pre are only updated in case of successful match
+ */
+static BOOL re_match_multi(const WCHAR** pstring, const WCHAR** pre, BOOL _case)
+{
+ const WCHAR* re_end = *pre;
+ const WCHAR* string_end = *pstring;
+ const WCHAR* re_beg;
+ const WCHAR* string_beg;
+ const WCHAR* next;
+ int ch;
+
+ while (*re_end && *string_end)
+ {
+ string_beg = string_end;
+ re_beg = re_end;
+ switch (ch = re_fetch_char(&re_end))
+ {
+ case WILDCHAR(']'): case WILDCHAR('+'): case WILDCHAR('#'): return FALSE;
+ case WILDCHAR('*'):
+ /* transform '*' into '?#' */
+ {static const WCHAR qmW[] = {'?',0}; re_beg = qmW;}
+ goto closure;
+ case WILDCHAR('['):
+ do
+ {
+ if (!(ch = re_fetch_char(&re_end))) return FALSE;
+ } while (ch != WILDCHAR(']'));
+ /* fall through */
+ case WILDCHAR('?'):
+ default:
+ break;
+ }
+
+ switch (*re_end)
+ {
+ case '+':
+ if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
+ string_beg++;
+ /* fall through */
+ case '#':
+ re_end++;
+ closure:
+ while ((next = re_match_one(string_end, re_beg, _case))) string_end = next;
+ for ( ; string_end >= string_beg; string_end--)
+ {
+ if (re_match_multi(&string_end, &re_end, _case)) goto found;
+ }
+ return FALSE;
+ default:
+ if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
+ string_end = next;
+ }
+ re_beg = re_end;
+ }
+
+ if (*re_end || *string_end) return FALSE;
+
+found:
+ *pre = re_end;
+ *pstring = string_end;
+ return TRUE;
+}
+
/******************************************************************
* SymMatchStringA (DBGHELP.@)
*
*/
BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case)
{
- regex_t preg;
- BOOL ret;
+ WCHAR* strW;
+ WCHAR* reW;
+ BOOL ret = FALSE;
+ DWORD sz;
+ if (!string || !re)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N');
- compile_regex(re, -1, &preg, _case);
- ret = match_regexp(&preg, string);
- regfree(&preg);
+ sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0);
+ if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
+ MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz);
+ sz = MultiByteToWideChar(CP_ACP, 0, re, -1, NULL, 0);
+ if ((reW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
+ MultiByteToWideChar(CP_ACP, 0, re, -1, reW, sz);
+
+ if (strW && reW)
+ ret = SymMatchStringW(strW, reW, _case);
+ HeapFree(GetProcessHeap(), 0, strW);
+ HeapFree(GetProcessHeap(), 0, reW);
return ret;
}
/******************************************************************
* SymMatchStringW (DBGHELP.@)
*
- * FIXME: SymMatchStringA should convert and pass the strings to SymMatchStringW,
- * but that needs a unicode RE library.
*/
BOOL WINAPI SymMatchStringW(PCWSTR string, PCWSTR re, BOOL _case)
{
- BOOL ret;
- LPSTR s, r;
- DWORD len;
-
TRACE("%s %s %c\n", debugstr_w(string), debugstr_w(re), _case ? 'Y' : 'N');
- len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL );
- s = HeapAlloc( GetProcessHeap(), 0, len );
- WideCharToMultiByte( CP_ACP, 0, string, -1, s, len, NULL, NULL );
-
- len = WideCharToMultiByte( CP_ACP, 0, re, -1, NULL, 0, NULL, NULL );
- r = HeapAlloc( GetProcessHeap(), 0, len );
- WideCharToMultiByte( CP_ACP, 0, re, -1, r, len, NULL, NULL );
-
- ret = SymMatchStringA(s, r, _case);
-
- HeapFree( GetProcessHeap(), 0, r );
- HeapFree( GetProcessHeap(), 0, s );
- return ret;
+ if (!string || !re)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ return re_match_multi(&string, &re, _case);
}
/******************************************************************
More information about the wine-cvs
mailing list