}
/**
+ * 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
* @length: the length of @string, or -1 if @string is nul-terminated
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;
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");