add g_regex_escape_nul

The function can be used to let regex compile non-NUL-terminated
strings without redesigning the way the pattern is stored in GRegex
objects and retrieved with g_regex_get_pattern.

https://bugzilla.gnome.org/show_bug.cgi?id=615895
This commit is contained in:
Paolo Bonzini 2010-04-15 08:23:00 +02:00 committed by Matthias Clasen
parent 653c2f701a
commit 5eee90fbbc
5 changed files with 114 additions and 0 deletions

View File

@ -981,6 +981,7 @@ g_regex_get_string_number
g_regex_get_compile_flags
g_regex_get_match_flags
g_regex_escape_string
g_regex_escape_nul
g_regex_match_simple
g_regex_match
g_regex_match_full

View File

@ -1352,6 +1352,7 @@ g_regex_get_string_number
g_regex_get_compile_flags
g_regex_get_match_flags
g_regex_escape_string
g_regex_escape_nul
g_regex_match_simple
g_regex_match
g_regex_match_full

View File

@ -2832,6 +2832,74 @@ g_regex_check_replacement (const gchar *replacement,
return TRUE;
}
/**
* g_regex_escape_nul:
* @string: the string to escape
* @length: the length of @string
*
* Escapes the nul characters in @string to "\x00". It can be used
* to compile a regex with embedded nul characters.
*
* For completeness, @length can be -1 for a nul-terminated string.
* In this case the output string will be of course equal to @string.
*
* Returns: a newly-allocated escaped string
*
* Since: 2.30
*/
gchar *
g_regex_escape_nul (const gchar *string,
gint length)
{
GString *escaped;
const gchar *p, *piece_start, *end;
gint backslashes;
g_return_val_if_fail (string != NULL, NULL);
if (length < 0)
return g_strdup (string);
end = string + length;
p = piece_start = string;
escaped = g_string_sized_new (length + 1);
backslashes = 0;
while (p < end)
{
switch (*p)
{
case '\0':
if (p != piece_start)
{
/* copy the previous piece. */
g_string_append_len (escaped, piece_start, p - piece_start);
}
if ((backslashes & 1) == 0)
g_string_append_c (escaped, '\\');
g_string_append_c (escaped, 'x');
g_string_append_c (escaped, '0');
g_string_append_c (escaped, '0');
piece_start = ++p;
backslashes = 0;
break;
case '\\':
backslashes++;
++p;
break;
default:
backslashes = 0;
p = g_utf8_next_char (p);
break;
}
}
if (piece_start < end)
g_string_append_len (escaped, piece_start, end - piece_start);
return g_string_free (escaped, FALSE);
}
/**
* g_regex_escape_string:
* @string: (array length=length): the string to escape

View File

@ -364,6 +364,8 @@ gint g_regex_get_string_number (const GRegex *regex,
const gchar *name);
gchar *g_regex_escape_string (const gchar *string,
gint length);
gchar *g_regex_escape_nul (const gchar *string,
gint length);
GRegexCompileFlags g_regex_get_compile_flags (const GRegex *regex);
GRegexMatchFlags g_regex_get_match_flags (const GRegex *regex);

View File

@ -1129,6 +1129,31 @@ test_escape (gconstpointer d)
g_free (path); \
}
static void
test_escape_nul (gconstpointer d)
{
const TestEscapeData *data = d;
gchar *escaped;
escaped = g_regex_escape_nul (data->string, data->length);
g_assert_cmpstr (escaped, ==, data->expected);
g_free (escaped);
}
#define TEST_ESCAPE_NUL(_string, _length, _expected) { \
TestEscapeData *data; \
gchar *path; \
data = g_new0 (TestEscapeData, 1); \
data->string = _string; \
data->length = _length; \
data->expected = _expected; \
path = g_strdup_printf ("/regex/escape_nul/%d", ++total); \
g_test_add_data_func (path, data, test_escape_nul); \
g_free (path); \
}
typedef struct {
const gchar *pattern;
const gchar *string;
@ -2574,6 +2599,23 @@ main (int argc, char *argv[])
TEST_GET_STRING_NUMBER("(?:a)(?P<A>.)", "A", 1);
TEST_GET_STRING_NUMBER("(?:a)(?P<A>.)", "B", -1);
/* TEST_ESCAPE_NUL(string, length, expected) */
TEST_ESCAPE_NUL("hello world", -1, "hello world");
TEST_ESCAPE_NUL("hello\0world", -1, "hello");
TEST_ESCAPE_NUL("\0world", -1, "");
TEST_ESCAPE_NUL("hello world", 5, "hello");
TEST_ESCAPE_NUL("hello.world", 11, "hello.world");
TEST_ESCAPE_NUL("a(b\\b.$", 7, "a(b\\b.$");
TEST_ESCAPE_NUL("hello\0", 6, "hello\\x00");
TEST_ESCAPE_NUL("\0world", 6, "\\x00world");
TEST_ESCAPE_NUL("\0\0", 2, "\\x00\\x00");
TEST_ESCAPE_NUL("hello\0world", 11, "hello\\x00world");
TEST_ESCAPE_NUL("hello\0world\0", 12, "hello\\x00world\\x00");
TEST_ESCAPE_NUL("hello\\\0world", 12, "hello\\x00world");
TEST_ESCAPE_NUL("hello\\\\\0world", 13, "hello\\\\\\x00world");
TEST_ESCAPE_NUL("|()[]{}^$*+?.", 13, "|()[]{}^$*+?.");
TEST_ESCAPE_NUL("|()[]{}^$*+?.\\\\", 15, "|()[]{}^$*+?.\\\\");
/* TEST_ESCAPE(string, length, expected) */
TEST_ESCAPE("hello world", -1, "hello world");
TEST_ESCAPE("hello world", 5, "hello");